blob: d8a42d9a9fec83c787f9382f8797ce61667435a5 [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,
FUJITA Tomonoricbccc202008-02-16 23:57:15 +0900224 .use_clustering = DISABLE_CLUSTERING,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 .module = THIS_MODULE,
226};
227
228static unsigned char * fake_storep; /* ramdisk storage */
229
230static int num_aborts = 0;
231static int num_dev_resets = 0;
232static int num_bus_resets = 0;
233static int num_host_resets = 0;
234
235static DEFINE_SPINLOCK(queued_arr_lock);
236static DEFINE_RWLOCK(atomic_rw);
237
238static char sdebug_proc_name[] = "scsi_debug";
239
240static int sdebug_driver_probe(struct device *);
241static int sdebug_driver_remove(struct device *);
242static struct bus_type pseudo_lld_bus;
243
244static struct device_driver sdebug_driverfs_driver = {
245 .name = sdebug_proc_name,
246 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247};
248
249static const int check_condition_result =
250 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
251
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400252static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
253 0, 0, 0x2, 0x4b};
254static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
255 0, 0, 0x0, 0x0};
256
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257/* function declarations */
258static int resp_inquiry(struct scsi_cmnd * SCpnt, int target,
259 struct sdebug_dev_info * devip);
260static int resp_requests(struct scsi_cmnd * SCpnt,
261 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400262static int resp_start_stop(struct scsi_cmnd * scp,
263 struct sdebug_dev_info * devip);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200264static int resp_report_tgtpgs(struct scsi_cmnd * scp,
265 struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266static int resp_readcap(struct scsi_cmnd * SCpnt,
267 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400268static int resp_readcap16(struct scsi_cmnd * SCpnt,
269 struct sdebug_dev_info * devip);
270static int resp_mode_sense(struct scsi_cmnd * scp, int target,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400272static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
273 struct sdebug_dev_info * devip);
274static int resp_log_sense(struct scsi_cmnd * scp,
275 struct sdebug_dev_info * devip);
276static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
277 unsigned int num, struct sdebug_dev_info * devip);
278static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
279 unsigned int num, struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280static int resp_report_luns(struct scsi_cmnd * SCpnt,
281 struct sdebug_dev_info * devip);
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900282static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
283 unsigned int num, struct sdebug_dev_info *devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
285 int arr_len);
286static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
287 int max_arr_len);
288static void timer_intr_handler(unsigned long);
289static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev);
290static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
291 int asc, int asq);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400292static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
293 struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294static int schedule_resp(struct scsi_cmnd * cmnd,
295 struct sdebug_dev_info * devip,
296 done_funct_t done, int scsi_result, int delta_jiff);
297static void __init sdebug_build_parts(unsigned char * ramp);
298static void __init init_all_queued(void);
299static void stop_all_queued(void);
300static int stop_queued_cmnd(struct scsi_cmnd * cmnd);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200301static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
302 int target_dev_id, int dev_id_num,
303 const char * dev_id_str, int dev_id_str_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400304static int inquiry_evpd_88(unsigned char * arr, int target_dev_id);
Randy Dunlap6ecaff72006-07-11 20:53:22 -0700305static int do_create_driverfs_files(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306static void do_remove_driverfs_files(void);
307
308static int sdebug_add_adapter(void);
309static void sdebug_remove_adapter(void);
310static void sdebug_max_tgts_luns(void);
311
312static struct device pseudo_primary;
313static struct bus_type pseudo_lld_bus;
314
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900315static void get_data_transfer_info(unsigned char *cmd,
316 unsigned long long *lba, unsigned int *num)
317{
318 int i;
319
320 switch (*cmd) {
321 case WRITE_16:
322 case READ_16:
323 for (*lba = 0, i = 0; i < 8; ++i) {
324 if (i > 0)
325 *lba <<= 8;
326 *lba += cmd[2 + i];
327 }
328 *num = cmd[13] + (cmd[12] << 8) +
329 (cmd[11] << 16) + (cmd[10] << 24);
330 break;
331 case WRITE_12:
332 case READ_12:
333 *lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
334 *num = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
335 break;
336 case WRITE_10:
337 case READ_10:
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900338 case XDWRITEREAD_10:
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900339 *lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
340 *num = cmd[8] + (cmd[7] << 8);
341 break;
342 case WRITE_6:
343 case READ_6:
344 *lba = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
345 *num = (0 == cmd[4]) ? 256 : cmd[4];
346 break;
347 default:
348 break;
349 }
350}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
352static
353int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
354{
355 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900356 int len, k;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400357 unsigned int num;
358 unsigned long long lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 int errsts = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400360 int target = SCpnt->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 struct sdebug_dev_info * devip = NULL;
362 int inj_recovered = 0;
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500363 int inj_transport = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400364 int delay_override = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
366 if (done == NULL)
367 return 0; /* assume mid level reprocessing command */
368
Boaz Harroshc73961e2007-09-07 06:50:20 +0900369 scsi_set_resid(SCpnt, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
371 printk(KERN_INFO "scsi_debug: cmd ");
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400372 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 printk("%02x ", (int)cmd[k]);
374 printk("\n");
375 }
376 if(target == sdebug_driver_template.this_id) {
377 printk(KERN_INFO "scsi_debug: initiator's id used as "
378 "target!\n");
379 return schedule_resp(SCpnt, NULL, done,
380 DID_NO_CONNECT << 16, 0);
381 }
382
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400383 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
384 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 return schedule_resp(SCpnt, NULL, done,
386 DID_NO_CONNECT << 16, 0);
387 devip = devInfoReg(SCpnt->device);
388 if (NULL == devip)
389 return schedule_resp(SCpnt, NULL, done,
390 DID_NO_CONNECT << 16, 0);
391
392 if ((scsi_debug_every_nth != 0) &&
393 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
394 scsi_debug_cmnd_count = 0;
395 if (scsi_debug_every_nth < -1)
396 scsi_debug_every_nth = -1;
397 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
398 return 0; /* ignore command causing timeout */
399 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
400 inj_recovered = 1; /* to reads and writes below */
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500401 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
402 inj_transport = 1; /* to reads and writes below */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 }
404
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400405 if (devip->wlun) {
406 switch (*cmd) {
407 case INQUIRY:
408 case REQUEST_SENSE:
409 case TEST_UNIT_READY:
410 case REPORT_LUNS:
411 break; /* only allowable wlun commands */
412 default:
413 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
414 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
415 "not supported for wlun\n", *cmd);
416 mk_sense_buffer(devip, ILLEGAL_REQUEST,
417 INVALID_OPCODE, 0);
418 errsts = check_condition_result;
419 return schedule_resp(SCpnt, devip, done, errsts,
420 0);
421 }
422 }
423
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 switch (*cmd) {
425 case INQUIRY: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400426 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 errsts = resp_inquiry(SCpnt, target, devip);
428 break;
429 case REQUEST_SENSE: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400430 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 errsts = resp_requests(SCpnt, devip);
432 break;
433 case REZERO_UNIT: /* actually this is REWIND for SSC */
434 case START_STOP:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400435 errsts = resp_start_stop(SCpnt, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 break;
437 case ALLOW_MEDIUM_REMOVAL:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400438 if ((errsts = check_readiness(SCpnt, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 break;
440 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
441 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
442 cmd[4] ? "inhibited" : "enabled");
443 break;
444 case SEND_DIAGNOSTIC: /* mandatory */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400445 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 break;
447 case TEST_UNIT_READY: /* mandatory */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400448 delay_override = 1;
449 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 break;
451 case RESERVE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400452 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 break;
454 case RESERVE_10:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400455 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 break;
457 case RELEASE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400458 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 break;
460 case RELEASE_10:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400461 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 break;
463 case READ_CAPACITY:
464 errsts = resp_readcap(SCpnt, devip);
465 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400466 case SERVICE_ACTION_IN:
467 if (SAI_READ_CAPACITY_16 != cmd[1]) {
468 mk_sense_buffer(devip, ILLEGAL_REQUEST,
469 INVALID_OPCODE, 0);
470 errsts = check_condition_result;
471 break;
472 }
473 errsts = resp_readcap16(SCpnt, devip);
474 break;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200475 case MAINTENANCE_IN:
476 if (MI_REPORT_TARGET_PGS != cmd[1]) {
477 mk_sense_buffer(devip, ILLEGAL_REQUEST,
478 INVALID_OPCODE, 0);
479 errsts = check_condition_result;
480 break;
481 }
482 errsts = resp_report_tgtpgs(SCpnt, devip);
483 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 case READ_16:
485 case READ_12:
486 case READ_10:
487 case READ_6:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400488 if ((errsts = check_readiness(SCpnt, 0, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 break;
Douglas Gilbert23183912006-09-16 20:30:47 -0400490 if (scsi_debug_fake_rw)
491 break;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900492 get_data_transfer_info(cmd, &lba, &num);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400493 errsts = resp_read(SCpnt, lba, num, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 if (inj_recovered && (0 == errsts)) {
495 mk_sense_buffer(devip, RECOVERED_ERROR,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400496 THRESHOLD_EXCEEDED, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 errsts = check_condition_result;
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500498 } else if (inj_transport && (0 == errsts)) {
499 mk_sense_buffer(devip, ABORTED_COMMAND,
500 TRANSPORT_PROBLEM, ACK_NAK_TO);
501 errsts = check_condition_result;
502 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 break;
504 case REPORT_LUNS: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400505 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 errsts = resp_report_luns(SCpnt, devip);
507 break;
508 case VERIFY: /* 10 byte SBC-2 command */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400509 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 break;
511 case WRITE_16:
512 case WRITE_12:
513 case WRITE_10:
514 case WRITE_6:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400515 if ((errsts = check_readiness(SCpnt, 0, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 break;
Douglas Gilbert23183912006-09-16 20:30:47 -0400517 if (scsi_debug_fake_rw)
518 break;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900519 get_data_transfer_info(cmd, &lba, &num);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400520 errsts = resp_write(SCpnt, lba, num, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 if (inj_recovered && (0 == errsts)) {
522 mk_sense_buffer(devip, RECOVERED_ERROR,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400523 THRESHOLD_EXCEEDED, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 errsts = check_condition_result;
525 }
526 break;
527 case MODE_SENSE:
528 case MODE_SENSE_10:
529 errsts = resp_mode_sense(SCpnt, target, devip);
530 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400531 case MODE_SELECT:
532 errsts = resp_mode_select(SCpnt, 1, devip);
533 break;
534 case MODE_SELECT_10:
535 errsts = resp_mode_select(SCpnt, 0, devip);
536 break;
537 case LOG_SENSE:
538 errsts = resp_log_sense(SCpnt, devip);
539 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 case SYNCHRONIZE_CACHE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400541 delay_override = 1;
542 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 break;
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500544 case WRITE_BUFFER:
545 errsts = check_readiness(SCpnt, 1, devip);
546 break;
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900547 case XDWRITEREAD_10:
548 if (!scsi_bidi_cmnd(SCpnt)) {
549 mk_sense_buffer(devip, ILLEGAL_REQUEST,
550 INVALID_FIELD_IN_CDB, 0);
551 errsts = check_condition_result;
552 break;
553 }
554
555 errsts = check_readiness(SCpnt, 0, devip);
556 if (errsts)
557 break;
558 if (scsi_debug_fake_rw)
559 break;
560 get_data_transfer_info(cmd, &lba, &num);
561 errsts = resp_read(SCpnt, lba, num, devip);
562 if (errsts)
563 break;
564 errsts = resp_write(SCpnt, lba, num, devip);
565 if (errsts)
566 break;
567 errsts = resp_xdwriteread(SCpnt, lba, num, devip);
568 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 default:
570 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
571 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
572 "supported\n", *cmd);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400573 if ((errsts = check_readiness(SCpnt, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 break; /* Unit attention takes precedence */
575 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
576 errsts = check_condition_result;
577 break;
578 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400579 return schedule_resp(SCpnt, devip, done, errsts,
580 (delay_override ? 0 : scsi_debug_delay));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581}
582
583static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
584{
585 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
586 printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
587 }
588 return -EINVAL;
589 /* return -ENOTTY; // correct return but upsets fdisk */
590}
591
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400592static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
593 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594{
595 if (devip->reset) {
596 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
597 printk(KERN_INFO "scsi_debug: Reporting Unit "
598 "attention: power on reset\n");
599 devip->reset = 0;
600 mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
601 return check_condition_result;
602 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400603 if ((0 == reset_only) && devip->stopped) {
604 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
605 printk(KERN_INFO "scsi_debug: Reporting Not "
606 "ready: initializing command required\n");
607 mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
608 0x2);
609 return check_condition_result;
610 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 return 0;
612}
613
614/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
615static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
616 int arr_len)
617{
618 int k, req_len, act_len, len, active;
619 void * kaddr;
620 void * kaddr_off;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900621 struct scatterlist *sg;
622 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900624 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900626 if (!sdb->table.sgl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 return (DID_ERROR << 16);
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900628 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 return (DID_ERROR << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 active = 1;
Jens Axboe852e0342007-07-16 10:19:24 +0200631 req_len = act_len = 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900632 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, k) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 if (active) {
634 kaddr = (unsigned char *)
Jens Axboe45711f12007-10-22 21:19:53 +0200635 kmap_atomic(sg_page(sg), KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 if (NULL == kaddr)
637 return (DID_ERROR << 16);
Jens Axboe852e0342007-07-16 10:19:24 +0200638 kaddr_off = (unsigned char *)kaddr + sg->offset;
639 len = sg->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 if ((req_len + len) > arr_len) {
641 active = 0;
642 len = arr_len - req_len;
643 }
644 memcpy(kaddr_off, arr + req_len, len);
645 kunmap_atomic(kaddr, KM_USER0);
646 act_len += len;
647 }
Jens Axboe852e0342007-07-16 10:19:24 +0200648 req_len += sg->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 }
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900650 if (sdb->resid)
651 sdb->resid -= act_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400652 else
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900653 sdb->resid = req_len - act_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 return 0;
655}
656
657/* Returns number of bytes fetched into 'arr' or -1 if error. */
658static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
659 int max_arr_len)
660{
661 int k, req_len, len, fin;
662 void * kaddr;
663 void * kaddr_off;
Jens Axboe852e0342007-07-16 10:19:24 +0200664 struct scatterlist * sg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665
Boaz Harroshc73961e2007-09-07 06:50:20 +0900666 if (0 == scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 return 0;
Boaz Harroshc73961e2007-09-07 06:50:20 +0900668 if (NULL == scsi_sglist(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 return -1;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900670 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 return -1;
Jens Axboe852e0342007-07-16 10:19:24 +0200672 req_len = fin = 0;
Boaz Harroshc73961e2007-09-07 06:50:20 +0900673 scsi_for_each_sg(scp, sg, scsi_sg_count(scp), k) {
Jens Axboe45711f12007-10-22 21:19:53 +0200674 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 if (NULL == kaddr)
676 return -1;
Jens Axboe852e0342007-07-16 10:19:24 +0200677 kaddr_off = (unsigned char *)kaddr + sg->offset;
678 len = sg->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 if ((req_len + len) > max_arr_len) {
680 len = max_arr_len - req_len;
681 fin = 1;
682 }
683 memcpy(arr + req_len, kaddr_off, len);
684 kunmap_atomic(kaddr, KM_USER0);
685 if (fin)
686 return req_len + len;
Jens Axboe852e0342007-07-16 10:19:24 +0200687 req_len += sg->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 }
689 return req_len;
690}
691
692
693static const char * inq_vendor_id = "Linux ";
694static const char * inq_product_id = "scsi_debug ";
695static const char * inq_product_rev = "0004";
696
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200697static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
698 int target_dev_id, int dev_id_num,
699 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400700 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400702 int num, port_a;
703 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400705 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 /* T10 vendor identifier field format (faked) */
707 arr[0] = 0x2; /* ASCII */
708 arr[1] = 0x1;
709 arr[2] = 0x0;
710 memcpy(&arr[4], inq_vendor_id, 8);
711 memcpy(&arr[12], inq_product_id, 16);
712 memcpy(&arr[28], dev_id_str, dev_id_str_len);
713 num = 8 + 16 + dev_id_str_len;
714 arr[3] = num;
715 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400716 if (dev_id_num >= 0) {
717 /* NAA-5, Logical unit identifier (binary) */
718 arr[num++] = 0x1; /* binary (not necessarily sas) */
719 arr[num++] = 0x3; /* PIV=0, lu, naa */
720 arr[num++] = 0x0;
721 arr[num++] = 0x8;
722 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
723 arr[num++] = 0x33;
724 arr[num++] = 0x33;
725 arr[num++] = 0x30;
726 arr[num++] = (dev_id_num >> 24);
727 arr[num++] = (dev_id_num >> 16) & 0xff;
728 arr[num++] = (dev_id_num >> 8) & 0xff;
729 arr[num++] = dev_id_num & 0xff;
730 /* Target relative port number */
731 arr[num++] = 0x61; /* proto=sas, binary */
732 arr[num++] = 0x94; /* PIV=1, target port, rel port */
733 arr[num++] = 0x0; /* reserved */
734 arr[num++] = 0x4; /* length */
735 arr[num++] = 0x0; /* reserved */
736 arr[num++] = 0x0; /* reserved */
737 arr[num++] = 0x0;
738 arr[num++] = 0x1; /* relative port A */
739 }
740 /* NAA-5, Target port identifier */
741 arr[num++] = 0x61; /* proto=sas, binary */
742 arr[num++] = 0x93; /* piv=1, target port, naa */
743 arr[num++] = 0x0;
744 arr[num++] = 0x8;
745 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
746 arr[num++] = 0x22;
747 arr[num++] = 0x22;
748 arr[num++] = 0x20;
749 arr[num++] = (port_a >> 24);
750 arr[num++] = (port_a >> 16) & 0xff;
751 arr[num++] = (port_a >> 8) & 0xff;
752 arr[num++] = port_a & 0xff;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200753 /* NAA-5, Target port group identifier */
754 arr[num++] = 0x61; /* proto=sas, binary */
755 arr[num++] = 0x95; /* piv=1, target port group id */
756 arr[num++] = 0x0;
757 arr[num++] = 0x4;
758 arr[num++] = 0;
759 arr[num++] = 0;
760 arr[num++] = (port_group_id >> 8) & 0xff;
761 arr[num++] = port_group_id & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400762 /* NAA-5, Target device identifier */
763 arr[num++] = 0x61; /* proto=sas, binary */
764 arr[num++] = 0xa3; /* piv=1, target device, naa */
765 arr[num++] = 0x0;
766 arr[num++] = 0x8;
767 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
768 arr[num++] = 0x22;
769 arr[num++] = 0x22;
770 arr[num++] = 0x20;
771 arr[num++] = (target_dev_id >> 24);
772 arr[num++] = (target_dev_id >> 16) & 0xff;
773 arr[num++] = (target_dev_id >> 8) & 0xff;
774 arr[num++] = target_dev_id & 0xff;
775 /* SCSI name string: Target device identifier */
776 arr[num++] = 0x63; /* proto=sas, UTF-8 */
777 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
778 arr[num++] = 0x0;
779 arr[num++] = 24;
780 memcpy(arr + num, "naa.52222220", 12);
781 num += 12;
782 snprintf(b, sizeof(b), "%08X", target_dev_id);
783 memcpy(arr + num, b, 8);
784 num += 8;
785 memset(arr + num, 0, 4);
786 num += 4;
787 return num;
788}
789
790
791static unsigned char vpd84_data[] = {
792/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
793 0x22,0x22,0x22,0x0,0xbb,0x1,
794 0x22,0x22,0x22,0x0,0xbb,0x2,
795};
796
797static int inquiry_evpd_84(unsigned char * arr)
798{
799 memcpy(arr, vpd84_data, sizeof(vpd84_data));
800 return sizeof(vpd84_data);
801}
802
803static int inquiry_evpd_85(unsigned char * arr)
804{
805 int num = 0;
806 const char * na1 = "https://www.kernel.org/config";
807 const char * na2 = "http://www.kernel.org/log";
808 int plen, olen;
809
810 arr[num++] = 0x1; /* lu, storage config */
811 arr[num++] = 0x0; /* reserved */
812 arr[num++] = 0x0;
813 olen = strlen(na1);
814 plen = olen + 1;
815 if (plen % 4)
816 plen = ((plen / 4) + 1) * 4;
817 arr[num++] = plen; /* length, null termianted, padded */
818 memcpy(arr + num, na1, olen);
819 memset(arr + num + olen, 0, plen - olen);
820 num += plen;
821
822 arr[num++] = 0x4; /* lu, logging */
823 arr[num++] = 0x0; /* reserved */
824 arr[num++] = 0x0;
825 olen = strlen(na2);
826 plen = olen + 1;
827 if (plen % 4)
828 plen = ((plen / 4) + 1) * 4;
829 arr[num++] = plen; /* length, null terminated, padded */
830 memcpy(arr + num, na2, olen);
831 memset(arr + num + olen, 0, plen - olen);
832 num += plen;
833
834 return num;
835}
836
837/* SCSI ports VPD page */
838static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
839{
840 int num = 0;
841 int port_a, port_b;
842
843 port_a = target_dev_id + 1;
844 port_b = port_a + 1;
845 arr[num++] = 0x0; /* reserved */
846 arr[num++] = 0x0; /* reserved */
847 arr[num++] = 0x0;
848 arr[num++] = 0x1; /* relative port 1 (primary) */
849 memset(arr + num, 0, 6);
850 num += 6;
851 arr[num++] = 0x0;
852 arr[num++] = 12; /* length tp descriptor */
853 /* naa-5 target port identifier (A) */
854 arr[num++] = 0x61; /* proto=sas, binary */
855 arr[num++] = 0x93; /* PIV=1, target port, NAA */
856 arr[num++] = 0x0; /* reserved */
857 arr[num++] = 0x8; /* length */
858 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
859 arr[num++] = 0x22;
860 arr[num++] = 0x22;
861 arr[num++] = 0x20;
862 arr[num++] = (port_a >> 24);
863 arr[num++] = (port_a >> 16) & 0xff;
864 arr[num++] = (port_a >> 8) & 0xff;
865 arr[num++] = port_a & 0xff;
866
867 arr[num++] = 0x0; /* reserved */
868 arr[num++] = 0x0; /* reserved */
869 arr[num++] = 0x0;
870 arr[num++] = 0x2; /* relative port 2 (secondary) */
871 memset(arr + num, 0, 6);
872 num += 6;
873 arr[num++] = 0x0;
874 arr[num++] = 12; /* length tp descriptor */
875 /* naa-5 target port identifier (B) */
876 arr[num++] = 0x61; /* proto=sas, binary */
877 arr[num++] = 0x93; /* PIV=1, target port, NAA */
878 arr[num++] = 0x0; /* reserved */
879 arr[num++] = 0x8; /* length */
880 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
881 arr[num++] = 0x22;
882 arr[num++] = 0x22;
883 arr[num++] = 0x20;
884 arr[num++] = (port_b >> 24);
885 arr[num++] = (port_b >> 16) & 0xff;
886 arr[num++] = (port_b >> 8) & 0xff;
887 arr[num++] = port_b & 0xff;
888
889 return num;
890}
891
892
893static unsigned char vpd89_data[] = {
894/* from 4th byte */ 0,0,0,0,
895'l','i','n','u','x',' ',' ',' ',
896'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
897'1','2','3','4',
8980x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
8990xec,0,0,0,
9000x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
9010,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
9020x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
9030x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
9040x53,0x41,
9050x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
9060x20,0x20,
9070x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
9080x10,0x80,
9090,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
9100x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
9110x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
9120,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
9130x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
9140x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
9150,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,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,0,0,
9190x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
9200,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
9210xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
9220,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
9230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9240,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9250,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9260,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9270,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9280,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9290,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9300,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9310,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9320,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9330,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9340,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
935};
936
937static int inquiry_evpd_89(unsigned char * arr)
938{
939 memcpy(arr, vpd89_data, sizeof(vpd89_data));
940 return sizeof(vpd89_data);
941}
942
943
944static unsigned char vpdb0_data[] = {
945 /* from 4th byte */ 0,0,0,4,
946 0,0,0x4,0,
947 0,0,0,64,
948};
949
950static int inquiry_evpd_b0(unsigned char * arr)
951{
952 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
953 if (sdebug_store_sectors > 0x400) {
954 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
955 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
956 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
957 arr[7] = sdebug_store_sectors & 0xff;
958 }
959 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960}
961
962
963#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400964#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
966static int resp_inquiry(struct scsi_cmnd * scp, int target,
967 struct sdebug_dev_info * devip)
968{
969 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200970 unsigned char * arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 unsigned char *cmd = (unsigned char *)scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200972 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973
974 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500975 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
976 if (! arr)
977 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400978 if (devip->wlun)
979 pq_pdt = 0x1e; /* present, wlun */
980 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
981 pq_pdt = 0x7f; /* not present, no device type */
982 else
983 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 arr[0] = pq_pdt;
985 if (0x2 & cmd[1]) { /* CMDDT bit set */
986 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
987 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200988 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 return check_condition_result;
990 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200991 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400992 char lu_id_str[6];
993 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200995 port_group_id = (((host_no + 1) & 0x7f) << 8) +
996 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -0400997 if (0 == scsi_debug_vpd_use_hostno)
998 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400999 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
1000 (devip->target * 1000) + devip->lun);
1001 target_dev_id = ((host_no + 1) * 2000) +
1002 (devip->target * 1000) - 3;
1003 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001005 arr[1] = cmd[2]; /*sanity */
1006 n = 4;
1007 arr[n++] = 0x0; /* this page */
1008 arr[n++] = 0x80; /* unit serial number */
1009 arr[n++] = 0x83; /* device identification */
1010 arr[n++] = 0x84; /* software interface ident. */
1011 arr[n++] = 0x85; /* management network addresses */
1012 arr[n++] = 0x86; /* extended inquiry */
1013 arr[n++] = 0x87; /* mode page policy */
1014 arr[n++] = 0x88; /* SCSI ports */
1015 arr[n++] = 0x89; /* ATA information */
1016 arr[n++] = 0xb0; /* Block limits (SBC) */
1017 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001019 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001021 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001023 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001024 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
1025 target_dev_id, lu_id_num,
1026 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001027 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1028 arr[1] = cmd[2]; /*sanity */
1029 arr[3] = inquiry_evpd_84(&arr[4]);
1030 } else if (0x85 == cmd[2]) { /* Management network addresses */
1031 arr[1] = cmd[2]; /*sanity */
1032 arr[3] = inquiry_evpd_85(&arr[4]);
1033 } else if (0x86 == cmd[2]) { /* extended inquiry */
1034 arr[1] = cmd[2]; /*sanity */
1035 arr[3] = 0x3c; /* number of following entries */
1036 arr[4] = 0x0; /* no protection stuff */
1037 arr[5] = 0x7; /* head of q, ordered + simple q's */
1038 } else if (0x87 == cmd[2]) { /* mode page policy */
1039 arr[1] = cmd[2]; /*sanity */
1040 arr[3] = 0x8; /* number of following entries */
1041 arr[4] = 0x2; /* disconnect-reconnect mp */
1042 arr[6] = 0x80; /* mlus, shared */
1043 arr[8] = 0x18; /* protocol specific lu */
1044 arr[10] = 0x82; /* mlus, per initiator port */
1045 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1046 arr[1] = cmd[2]; /*sanity */
1047 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
1048 } else if (0x89 == cmd[2]) { /* ATA information */
1049 arr[1] = cmd[2]; /*sanity */
1050 n = inquiry_evpd_89(&arr[4]);
1051 arr[2] = (n >> 8);
1052 arr[3] = (n & 0xff);
1053 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
1054 arr[1] = cmd[2]; /*sanity */
1055 arr[3] = inquiry_evpd_b0(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 } else {
1057 /* Illegal request, invalid field in cdb */
1058 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1059 INVALID_FIELD_IN_CDB, 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001060 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 return check_condition_result;
1062 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001063 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001064 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001065 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001066 kfree(arr);
1067 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 }
1069 /* drops through here for a standard inquiry */
1070 arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
1071 arr[2] = scsi_debug_scsi_level;
1072 arr[3] = 2; /* response_data_format==2 */
1073 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001074 if (0 == scsi_debug_vpd_use_hostno)
1075 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001076 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001078 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 memcpy(&arr[8], inq_vendor_id, 8);
1080 memcpy(&arr[16], inq_product_id, 16);
1081 memcpy(&arr[32], inq_product_rev, 4);
1082 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001083 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
1084 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
1085 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001087 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001089 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001091 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001092 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001094 kfree(arr);
1095 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096}
1097
1098static int resp_requests(struct scsi_cmnd * scp,
1099 struct sdebug_dev_info * devip)
1100{
1101 unsigned char * sbuff;
1102 unsigned char *cmd = (unsigned char *)scp->cmnd;
1103 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001104 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 int len = 18;
1106
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001107 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001109 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
1110 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001112 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1113 if (want_dsense) {
1114 arr[0] = 0x72;
1115 arr[1] = 0x0; /* NO_SENSE in sense_key */
1116 arr[2] = THRESHOLD_EXCEEDED;
1117 arr[3] = 0xff; /* TEST set and MRIE==6 */
1118 } else {
1119 arr[0] = 0x70;
1120 arr[2] = 0x0; /* NO_SENSE in sense_key */
1121 arr[7] = 0xa; /* 18 byte sense buffer */
1122 arr[12] = THRESHOLD_EXCEEDED;
1123 arr[13] = 0xff; /* TEST set and MRIE==6 */
1124 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001125 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001127 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
1128 /* DESC bit set and sense_buff in fixed format */
1129 memset(arr, 0, sizeof(arr));
1130 arr[0] = 0x72;
1131 arr[1] = sbuff[2]; /* sense key */
1132 arr[2] = sbuff[12]; /* asc */
1133 arr[3] = sbuff[13]; /* ascq */
1134 len = 8;
1135 }
1136 }
1137 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 return fill_from_dev_buffer(scp, arr, len);
1139}
1140
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001141static int resp_start_stop(struct scsi_cmnd * scp,
1142 struct sdebug_dev_info * devip)
1143{
1144 unsigned char *cmd = (unsigned char *)scp->cmnd;
1145 int power_cond, errsts, start;
1146
1147 if ((errsts = check_readiness(scp, 1, devip)))
1148 return errsts;
1149 power_cond = (cmd[4] & 0xf0) >> 4;
1150 if (power_cond) {
1151 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1152 0);
1153 return check_condition_result;
1154 }
1155 start = cmd[4] & 1;
1156 if (start == devip->stopped)
1157 devip->stopped = !start;
1158 return 0;
1159}
1160
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161#define SDEBUG_READCAP_ARR_SZ 8
1162static int resp_readcap(struct scsi_cmnd * scp,
1163 struct sdebug_dev_info * devip)
1164{
1165 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001166 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 int errsts;
1168
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001169 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001171 /* following just in case virtual_gb changed */
1172 if (scsi_debug_virtual_gb > 0) {
1173 sdebug_capacity = 2048 * 1024;
1174 sdebug_capacity *= scsi_debug_virtual_gb;
1175 } else
1176 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001178 if (sdebug_capacity < 0xffffffff) {
1179 capac = (unsigned int)sdebug_capacity - 1;
1180 arr[0] = (capac >> 24);
1181 arr[1] = (capac >> 16) & 0xff;
1182 arr[2] = (capac >> 8) & 0xff;
1183 arr[3] = capac & 0xff;
1184 } else {
1185 arr[0] = 0xff;
1186 arr[1] = 0xff;
1187 arr[2] = 0xff;
1188 arr[3] = 0xff;
1189 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1191 arr[7] = SECT_SIZE_PER(target) & 0xff;
1192 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1193}
1194
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001195#define SDEBUG_READCAP16_ARR_SZ 32
1196static int resp_readcap16(struct scsi_cmnd * scp,
1197 struct sdebug_dev_info * devip)
1198{
1199 unsigned char *cmd = (unsigned char *)scp->cmnd;
1200 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1201 unsigned long long capac;
1202 int errsts, k, alloc_len;
1203
1204 if ((errsts = check_readiness(scp, 1, devip)))
1205 return errsts;
1206 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1207 + cmd[13]);
1208 /* following just in case virtual_gb changed */
1209 if (scsi_debug_virtual_gb > 0) {
1210 sdebug_capacity = 2048 * 1024;
1211 sdebug_capacity *= scsi_debug_virtual_gb;
1212 } else
1213 sdebug_capacity = sdebug_store_sectors;
1214 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1215 capac = sdebug_capacity - 1;
1216 for (k = 0; k < 8; ++k, capac >>= 8)
1217 arr[7 - k] = capac & 0xff;
1218 arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff;
1219 arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff;
1220 arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1221 arr[11] = SECT_SIZE_PER(target) & 0xff;
1222 return fill_from_dev_buffer(scp, arr,
1223 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1224}
1225
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001226#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1227
1228static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1229 struct sdebug_dev_info * devip)
1230{
1231 unsigned char *cmd = (unsigned char *)scp->cmnd;
1232 unsigned char * arr;
1233 int host_no = devip->sdbg_host->shost->host_no;
1234 int n, ret, alen, rlen;
1235 int port_group_a, port_group_b, port_a, port_b;
1236
1237 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
1238 + cmd[9]);
1239
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001240 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1241 if (! arr)
1242 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001243 /*
1244 * EVPD page 0x88 states we have two ports, one
1245 * real and a fake port with no device connected.
1246 * So we create two port groups with one port each
1247 * and set the group with port B to unavailable.
1248 */
1249 port_a = 0x1; /* relative port A */
1250 port_b = 0x2; /* relative port B */
1251 port_group_a = (((host_no + 1) & 0x7f) << 8) +
1252 (devip->channel & 0x7f);
1253 port_group_b = (((host_no + 1) & 0x7f) << 8) +
1254 (devip->channel & 0x7f) + 0x80;
1255
1256 /*
1257 * The asymmetric access state is cycled according to the host_id.
1258 */
1259 n = 4;
1260 if (0 == scsi_debug_vpd_use_hostno) {
1261 arr[n++] = host_no % 3; /* Asymm access state */
1262 arr[n++] = 0x0F; /* claim: all states are supported */
1263 } else {
1264 arr[n++] = 0x0; /* Active/Optimized path */
1265 arr[n++] = 0x01; /* claim: only support active/optimized paths */
1266 }
1267 arr[n++] = (port_group_a >> 8) & 0xff;
1268 arr[n++] = port_group_a & 0xff;
1269 arr[n++] = 0; /* Reserved */
1270 arr[n++] = 0; /* Status code */
1271 arr[n++] = 0; /* Vendor unique */
1272 arr[n++] = 0x1; /* One port per group */
1273 arr[n++] = 0; /* Reserved */
1274 arr[n++] = 0; /* Reserved */
1275 arr[n++] = (port_a >> 8) & 0xff;
1276 arr[n++] = port_a & 0xff;
1277 arr[n++] = 3; /* Port unavailable */
1278 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1279 arr[n++] = (port_group_b >> 8) & 0xff;
1280 arr[n++] = port_group_b & 0xff;
1281 arr[n++] = 0; /* Reserved */
1282 arr[n++] = 0; /* Status code */
1283 arr[n++] = 0; /* Vendor unique */
1284 arr[n++] = 0x1; /* One port per group */
1285 arr[n++] = 0; /* Reserved */
1286 arr[n++] = 0; /* Reserved */
1287 arr[n++] = (port_b >> 8) & 0xff;
1288 arr[n++] = port_b & 0xff;
1289
1290 rlen = n - 4;
1291 arr[0] = (rlen >> 24) & 0xff;
1292 arr[1] = (rlen >> 16) & 0xff;
1293 arr[2] = (rlen >> 8) & 0xff;
1294 arr[3] = rlen & 0xff;
1295
1296 /*
1297 * Return the smallest value of either
1298 * - The allocated length
1299 * - The constructed command length
1300 * - The maximum array size
1301 */
1302 rlen = min(alen,n);
1303 ret = fill_from_dev_buffer(scp, arr,
1304 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1305 kfree(arr);
1306 return ret;
1307}
1308
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309/* <<Following mode page info copied from ST318451LW>> */
1310
1311static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1312{ /* Read-Write Error Recovery page for mode_sense */
1313 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1314 5, 0, 0xff, 0xff};
1315
1316 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1317 if (1 == pcontrol)
1318 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1319 return sizeof(err_recov_pg);
1320}
1321
1322static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1323{ /* Disconnect-Reconnect page for mode_sense */
1324 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1325 0, 0, 0, 0, 0, 0, 0, 0};
1326
1327 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1328 if (1 == pcontrol)
1329 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1330 return sizeof(disconnect_pg);
1331}
1332
1333static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1334{ /* Format device page for mode_sense */
1335 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1336 0, 0, 0, 0, 0, 0, 0, 0,
1337 0, 0, 0, 0, 0x40, 0, 0, 0};
1338
1339 memcpy(p, format_pg, sizeof(format_pg));
1340 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1341 p[11] = sdebug_sectors_per & 0xff;
1342 p[12] = (SECT_SIZE >> 8) & 0xff;
1343 p[13] = SECT_SIZE & 0xff;
1344 if (DEV_REMOVEABLE(target))
1345 p[20] |= 0x20; /* should agree with INQUIRY */
1346 if (1 == pcontrol)
1347 memset(p + 2, 0, sizeof(format_pg) - 2);
1348 return sizeof(format_pg);
1349}
1350
1351static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1352{ /* Caching page for mode_sense */
1353 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1354 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1355
1356 memcpy(p, caching_pg, sizeof(caching_pg));
1357 if (1 == pcontrol)
1358 memset(p + 2, 0, sizeof(caching_pg) - 2);
1359 return sizeof(caching_pg);
1360}
1361
1362static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1363{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001364 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1365 0, 0, 0, 0};
1366 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 0, 0, 0x2, 0x4b};
1368
1369 if (scsi_debug_dsense)
1370 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001371 else
1372 ctrl_m_pg[2] &= ~0x4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1374 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001375 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1376 else if (2 == pcontrol)
1377 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 return sizeof(ctrl_m_pg);
1379}
1380
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001381
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1383{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001384 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1385 0, 0, 0x0, 0x0};
1386 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1387 0, 0, 0x0, 0x0};
1388
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1390 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001391 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1392 else if (2 == pcontrol)
1393 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 return sizeof(iec_m_pg);
1395}
1396
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001397static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1398{ /* SAS SSP mode page - short format for mode_sense */
1399 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1400 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1401
1402 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1403 if (1 == pcontrol)
1404 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1405 return sizeof(sas_sf_m_pg);
1406}
1407
1408
1409static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1410 int target_dev_id)
1411{ /* SAS phy control and discover mode page for mode_sense */
1412 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1413 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1414 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1415 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1416 0x2, 0, 0, 0, 0, 0, 0, 0,
1417 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1418 0, 0, 0, 0, 0, 0, 0, 0,
1419 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1420 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1421 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1422 0x3, 0, 0, 0, 0, 0, 0, 0,
1423 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1424 0, 0, 0, 0, 0, 0, 0, 0,
1425 };
1426 int port_a, port_b;
1427
1428 port_a = target_dev_id + 1;
1429 port_b = port_a + 1;
1430 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1431 p[20] = (port_a >> 24);
1432 p[21] = (port_a >> 16) & 0xff;
1433 p[22] = (port_a >> 8) & 0xff;
1434 p[23] = port_a & 0xff;
1435 p[48 + 20] = (port_b >> 24);
1436 p[48 + 21] = (port_b >> 16) & 0xff;
1437 p[48 + 22] = (port_b >> 8) & 0xff;
1438 p[48 + 23] = port_b & 0xff;
1439 if (1 == pcontrol)
1440 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1441 return sizeof(sas_pcd_m_pg);
1442}
1443
1444static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1445{ /* SAS SSP shared protocol specific port mode subpage */
1446 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1447 0, 0, 0, 0, 0, 0, 0, 0,
1448 };
1449
1450 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1451 if (1 == pcontrol)
1452 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1453 return sizeof(sas_sha_m_pg);
1454}
1455
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456#define SDEBUG_MAX_MSENSE_SZ 256
1457
1458static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1459 struct sdebug_dev_info * devip)
1460{
Douglas Gilbert23183912006-09-16 20:30:47 -04001461 unsigned char dbd, llbaa;
1462 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001464 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 unsigned char * ap;
1466 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1467 unsigned char *cmd = (unsigned char *)scp->cmnd;
1468
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001469 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001471 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 pcontrol = (cmd[2] & 0xc0) >> 6;
1473 pcode = cmd[2] & 0x3f;
1474 subpcode = cmd[3];
1475 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001476 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1477 if ((0 == scsi_debug_ptype) && (0 == dbd))
1478 bd_len = llbaa ? 16 : 8;
1479 else
1480 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1482 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1483 if (0x3 == pcontrol) { /* Saving values not supported */
1484 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1485 0);
1486 return check_condition_result;
1487 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001488 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1489 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001490 /* set DPOFUA bit for disks */
1491 if (0 == scsi_debug_ptype)
1492 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1493 else
1494 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 if (msense_6) {
1496 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001497 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 offset = 4;
1499 } else {
1500 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001501 if (16 == bd_len)
1502 arr[4] = 0x1; /* set LONGLBA bit */
1503 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 offset = 8;
1505 }
1506 ap = arr + offset;
Douglas Gilbert23183912006-09-16 20:30:47 -04001507 if ((bd_len > 0) && (0 == sdebug_capacity)) {
1508 if (scsi_debug_virtual_gb > 0) {
1509 sdebug_capacity = 2048 * 1024;
1510 sdebug_capacity *= scsi_debug_virtual_gb;
1511 } else
1512 sdebug_capacity = sdebug_store_sectors;
1513 }
1514 if (8 == bd_len) {
1515 if (sdebug_capacity > 0xfffffffe) {
1516 ap[0] = 0xff;
1517 ap[1] = 0xff;
1518 ap[2] = 0xff;
1519 ap[3] = 0xff;
1520 } else {
1521 ap[0] = (sdebug_capacity >> 24) & 0xff;
1522 ap[1] = (sdebug_capacity >> 16) & 0xff;
1523 ap[2] = (sdebug_capacity >> 8) & 0xff;
1524 ap[3] = sdebug_capacity & 0xff;
1525 }
1526 ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1527 ap[7] = SECT_SIZE_PER(target) & 0xff;
1528 offset += bd_len;
1529 ap = arr + offset;
1530 } else if (16 == bd_len) {
1531 unsigned long long capac = sdebug_capacity;
1532
1533 for (k = 0; k < 8; ++k, capac >>= 8)
1534 ap[7 - k] = capac & 0xff;
1535 ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff;
1536 ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff;
1537 ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1538 ap[15] = SECT_SIZE_PER(target) & 0xff;
1539 offset += bd_len;
1540 ap = arr + offset;
1541 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001543 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1544 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1546 0);
1547 return check_condition_result;
1548 }
1549 switch (pcode) {
1550 case 0x1: /* Read-Write error recovery page, direct access */
1551 len = resp_err_recov_pg(ap, pcontrol, target);
1552 offset += len;
1553 break;
1554 case 0x2: /* Disconnect-Reconnect page, all devices */
1555 len = resp_disconnect_pg(ap, pcontrol, target);
1556 offset += len;
1557 break;
1558 case 0x3: /* Format device page, direct access */
1559 len = resp_format_pg(ap, pcontrol, target);
1560 offset += len;
1561 break;
1562 case 0x8: /* Caching page, direct access */
1563 len = resp_caching_pg(ap, pcontrol, target);
1564 offset += len;
1565 break;
1566 case 0xa: /* Control Mode page, all devices */
1567 len = resp_ctrl_m_pg(ap, pcontrol, target);
1568 offset += len;
1569 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001570 case 0x19: /* if spc==1 then sas phy, control+discover */
1571 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1572 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1573 INVALID_FIELD_IN_CDB, 0);
1574 return check_condition_result;
1575 }
1576 len = 0;
1577 if ((0x0 == subpcode) || (0xff == subpcode))
1578 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1579 if ((0x1 == subpcode) || (0xff == subpcode))
1580 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1581 target_dev_id);
1582 if ((0x2 == subpcode) || (0xff == subpcode))
1583 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1584 offset += len;
1585 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 case 0x1c: /* Informational Exceptions Mode page, all devices */
1587 len = resp_iec_m_pg(ap, pcontrol, target);
1588 offset += len;
1589 break;
1590 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001591 if ((0 == subpcode) || (0xff == subpcode)) {
1592 len = resp_err_recov_pg(ap, pcontrol, target);
1593 len += resp_disconnect_pg(ap + len, pcontrol, target);
1594 len += resp_format_pg(ap + len, pcontrol, target);
1595 len += resp_caching_pg(ap + len, pcontrol, target);
1596 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1597 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1598 if (0xff == subpcode) {
1599 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1600 target, target_dev_id);
1601 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1602 }
1603 len += resp_iec_m_pg(ap + len, pcontrol, target);
1604 } else {
1605 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1606 INVALID_FIELD_IN_CDB, 0);
1607 return check_condition_result;
1608 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 offset += len;
1610 break;
1611 default:
1612 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1613 0);
1614 return check_condition_result;
1615 }
1616 if (msense_6)
1617 arr[0] = offset - 1;
1618 else {
1619 arr[0] = ((offset - 2) >> 8) & 0xff;
1620 arr[1] = (offset - 2) & 0xff;
1621 }
1622 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1623}
1624
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001625#define SDEBUG_MAX_MSELECT_SZ 512
1626
1627static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1628 struct sdebug_dev_info * devip)
1629{
1630 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1631 int param_len, res, errsts, mpage;
1632 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1633 unsigned char *cmd = (unsigned char *)scp->cmnd;
1634
1635 if ((errsts = check_readiness(scp, 1, devip)))
1636 return errsts;
1637 memset(arr, 0, sizeof(arr));
1638 pf = cmd[1] & 0x10;
1639 sp = cmd[1] & 0x1;
1640 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1641 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1642 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1643 INVALID_FIELD_IN_CDB, 0);
1644 return check_condition_result;
1645 }
1646 res = fetch_to_dev_buffer(scp, arr, param_len);
1647 if (-1 == res)
1648 return (DID_ERROR << 16);
1649 else if ((res < param_len) &&
1650 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1651 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1652 " IO sent=%d bytes\n", param_len, res);
1653 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1654 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001655 if (md_len > 2) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001656 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1657 INVALID_FIELD_IN_PARAM_LIST, 0);
1658 return check_condition_result;
1659 }
1660 off = bd_len + (mselect6 ? 4 : 8);
1661 mpage = arr[off] & 0x3f;
1662 ps = !!(arr[off] & 0x80);
1663 if (ps) {
1664 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1665 INVALID_FIELD_IN_PARAM_LIST, 0);
1666 return check_condition_result;
1667 }
1668 spf = !!(arr[off] & 0x40);
1669 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1670 (arr[off + 1] + 2);
1671 if ((pg_len + off) > param_len) {
1672 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1673 PARAMETER_LIST_LENGTH_ERR, 0);
1674 return check_condition_result;
1675 }
1676 switch (mpage) {
1677 case 0xa: /* Control Mode page */
1678 if (ctrl_m_pg[1] == arr[off + 1]) {
1679 memcpy(ctrl_m_pg + 2, arr + off + 2,
1680 sizeof(ctrl_m_pg) - 2);
1681 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1682 return 0;
1683 }
1684 break;
1685 case 0x1c: /* Informational Exceptions Mode page */
1686 if (iec_m_pg[1] == arr[off + 1]) {
1687 memcpy(iec_m_pg + 2, arr + off + 2,
1688 sizeof(iec_m_pg) - 2);
1689 return 0;
1690 }
1691 break;
1692 default:
1693 break;
1694 }
1695 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1696 INVALID_FIELD_IN_PARAM_LIST, 0);
1697 return check_condition_result;
1698}
1699
1700static int resp_temp_l_pg(unsigned char * arr)
1701{
1702 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1703 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1704 };
1705
1706 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1707 return sizeof(temp_l_pg);
1708}
1709
1710static int resp_ie_l_pg(unsigned char * arr)
1711{
1712 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1713 };
1714
1715 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1716 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1717 arr[4] = THRESHOLD_EXCEEDED;
1718 arr[5] = 0xff;
1719 }
1720 return sizeof(ie_l_pg);
1721}
1722
1723#define SDEBUG_MAX_LSENSE_SZ 512
1724
1725static int resp_log_sense(struct scsi_cmnd * scp,
1726 struct sdebug_dev_info * devip)
1727{
Douglas Gilbert23183912006-09-16 20:30:47 -04001728 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001729 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1730 unsigned char *cmd = (unsigned char *)scp->cmnd;
1731
1732 if ((errsts = check_readiness(scp, 1, devip)))
1733 return errsts;
1734 memset(arr, 0, sizeof(arr));
1735 ppc = cmd[1] & 0x2;
1736 sp = cmd[1] & 0x1;
1737 if (ppc || sp) {
1738 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1739 INVALID_FIELD_IN_CDB, 0);
1740 return check_condition_result;
1741 }
1742 pcontrol = (cmd[2] & 0xc0) >> 6;
1743 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001744 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001745 alloc_len = (cmd[7] << 8) + cmd[8];
1746 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001747 if (0 == subpcode) {
1748 switch (pcode) {
1749 case 0x0: /* Supported log pages log page */
1750 n = 4;
1751 arr[n++] = 0x0; /* this page */
1752 arr[n++] = 0xd; /* Temperature */
1753 arr[n++] = 0x2f; /* Informational exceptions */
1754 arr[3] = n - 4;
1755 break;
1756 case 0xd: /* Temperature log page */
1757 arr[3] = resp_temp_l_pg(arr + 4);
1758 break;
1759 case 0x2f: /* Informational exceptions log page */
1760 arr[3] = resp_ie_l_pg(arr + 4);
1761 break;
1762 default:
1763 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1764 INVALID_FIELD_IN_CDB, 0);
1765 return check_condition_result;
1766 }
1767 } else if (0xff == subpcode) {
1768 arr[0] |= 0x40;
1769 arr[1] = subpcode;
1770 switch (pcode) {
1771 case 0x0: /* Supported log pages and subpages log page */
1772 n = 4;
1773 arr[n++] = 0x0;
1774 arr[n++] = 0x0; /* 0,0 page */
1775 arr[n++] = 0x0;
1776 arr[n++] = 0xff; /* this page */
1777 arr[n++] = 0xd;
1778 arr[n++] = 0x0; /* Temperature */
1779 arr[n++] = 0x2f;
1780 arr[n++] = 0x0; /* Informational exceptions */
1781 arr[3] = n - 4;
1782 break;
1783 case 0xd: /* Temperature subpages */
1784 n = 4;
1785 arr[n++] = 0xd;
1786 arr[n++] = 0x0; /* Temperature */
1787 arr[3] = n - 4;
1788 break;
1789 case 0x2f: /* Informational exceptions subpages */
1790 n = 4;
1791 arr[n++] = 0x2f;
1792 arr[n++] = 0x0; /* Informational exceptions */
1793 arr[3] = n - 4;
1794 break;
1795 default:
1796 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1797 INVALID_FIELD_IN_CDB, 0);
1798 return check_condition_result;
1799 }
1800 } else {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001801 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1802 INVALID_FIELD_IN_CDB, 0);
1803 return check_condition_result;
1804 }
1805 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1806 return fill_from_dev_buffer(scp, arr,
1807 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1808}
1809
1810static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
1811 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812{
1813 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001814 unsigned int block, from_bottom;
1815 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 int ret;
1817
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001818 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1820 0);
1821 return check_condition_result;
1822 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001823 /* transfer length excessive (tie in to block limits VPD page) */
1824 if (num > sdebug_store_sectors) {
1825 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1826 0);
1827 return check_condition_result;
1828 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001830 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1831 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1832 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1834 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001835 /* set info field and valid bit for fixed descriptor */
1836 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1837 devip->sense_buff[0] |= 0x80; /* Valid bit */
1838 ret = OPT_MEDIUM_ERR_ADDR;
1839 devip->sense_buff[3] = (ret >> 24) & 0xff;
1840 devip->sense_buff[4] = (ret >> 16) & 0xff;
1841 devip->sense_buff[5] = (ret >> 8) & 0xff;
1842 devip->sense_buff[6] = ret & 0xff;
1843 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 return check_condition_result;
1845 }
1846 read_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001847 if ((lba + num) <= sdebug_store_sectors)
1848 ret = fill_from_dev_buffer(SCpnt,
1849 fake_storep + (lba * SECT_SIZE),
1850 num * SECT_SIZE);
1851 else {
1852 /* modulo when one arg is 64 bits needs do_div() */
1853 u = lba;
1854 block = do_div(u, sdebug_store_sectors);
1855 from_bottom = 0;
1856 if ((block + num) > sdebug_store_sectors)
1857 from_bottom = (block + num) - sdebug_store_sectors;
1858 ret = fill_from_dev_buffer(SCpnt,
1859 fake_storep + (block * SECT_SIZE),
1860 (num - from_bottom) * SECT_SIZE);
1861 if ((0 == ret) && (from_bottom > 0))
1862 ret = fill_from_dev_buffer(SCpnt, fake_storep,
1863 from_bottom * SECT_SIZE);
1864 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 read_unlock_irqrestore(&atomic_rw, iflags);
1866 return ret;
1867}
1868
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001869static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
1870 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871{
1872 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001873 unsigned int block, to_bottom;
1874 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 int res;
1876
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001877 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1879 0);
1880 return check_condition_result;
1881 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001882 /* transfer length excessive (tie in to block limits VPD page) */
1883 if (num > sdebug_store_sectors) {
1884 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1885 0);
1886 return check_condition_result;
1887 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888
1889 write_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001890 if ((lba + num) <= sdebug_store_sectors)
1891 res = fetch_to_dev_buffer(SCpnt,
1892 fake_storep + (lba * SECT_SIZE),
1893 num * SECT_SIZE);
1894 else {
1895 /* modulo when one arg is 64 bits needs do_div() */
1896 u = lba;
1897 block = do_div(u, sdebug_store_sectors);
1898 to_bottom = 0;
1899 if ((block + num) > sdebug_store_sectors)
1900 to_bottom = (block + num) - sdebug_store_sectors;
1901 res = fetch_to_dev_buffer(SCpnt,
1902 fake_storep + (block * SECT_SIZE),
1903 (num - to_bottom) * SECT_SIZE);
1904 if ((0 == res) && (to_bottom > 0))
1905 res = fetch_to_dev_buffer(SCpnt, fake_storep,
1906 to_bottom * SECT_SIZE);
1907 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 write_unlock_irqrestore(&atomic_rw, iflags);
1909 if (-1 == res)
1910 return (DID_ERROR << 16);
1911 else if ((res < (num * SECT_SIZE)) &&
1912 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001913 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 " IO sent=%d bytes\n", num * SECT_SIZE, res);
1915 return 0;
1916}
1917
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001918#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919
1920static int resp_report_luns(struct scsi_cmnd * scp,
1921 struct sdebug_dev_info * devip)
1922{
1923 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001924 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 unsigned char *cmd = (unsigned char *)scp->cmnd;
1926 int select_report = (int)cmd[2];
1927 struct scsi_lun *one_lun;
1928 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001929 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930
1931 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001932 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1934 0);
1935 return check_condition_result;
1936 }
1937 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
1938 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
1939 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001940 if (1 == select_report)
1941 lun_cnt = 0;
1942 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
1943 --lun_cnt;
1944 wlun = (select_report > 0) ? 1 : 0;
1945 num = lun_cnt + wlun;
1946 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
1947 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
1948 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
1949 sizeof(struct scsi_lun)), num);
1950 if (n < num) {
1951 wlun = 0;
1952 lun_cnt = n;
1953 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001955 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
1956 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
1957 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
1958 i++, lun++) {
1959 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 if (upper)
1961 one_lun[i].scsi_lun[0] =
1962 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001963 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001965 if (wlun) {
1966 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
1967 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
1968 i++;
1969 }
1970 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 return fill_from_dev_buffer(scp, arr,
1972 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
1973}
1974
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001975static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
1976 unsigned int num, struct sdebug_dev_info *devip)
1977{
1978 int i, j, ret = -1;
1979 unsigned char *kaddr, *buf;
1980 unsigned int offset;
1981 struct scatterlist *sg;
1982 struct scsi_data_buffer *sdb = scsi_in(scp);
1983
1984 /* better not to use temporary buffer. */
1985 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
1986 if (!buf)
1987 return ret;
1988
1989 offset = 0;
1990 scsi_for_each_sg(scp, sg, scsi_sg_count(scp), i) {
1991 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
1992 if (!kaddr)
1993 goto out;
1994
1995 memcpy(buf + offset, kaddr + sg->offset, sg->length);
1996 offset += sg->length;
1997 kunmap_atomic(kaddr, KM_USER0);
1998 }
1999
2000 offset = 0;
2001 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
2002 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
2003 if (!kaddr)
2004 goto out;
2005
2006 for (j = 0; j < sg->length; j++)
2007 *(kaddr + sg->offset + j) ^= *(buf + offset + j);
2008
2009 offset += sg->length;
2010 kunmap_atomic(kaddr, KM_USER0);
2011 }
2012 ret = 0;
2013out:
2014 kfree(buf);
2015
2016 return ret;
2017}
2018
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019/* When timer goes off this function is called. */
2020static void timer_intr_handler(unsigned long indx)
2021{
2022 struct sdebug_queued_cmd * sqcp;
2023 unsigned long iflags;
2024
2025 if (indx >= SCSI_DEBUG_CANQUEUE) {
2026 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
2027 "large\n");
2028 return;
2029 }
2030 spin_lock_irqsave(&queued_arr_lock, iflags);
2031 sqcp = &queued_arr[(int)indx];
2032 if (! sqcp->in_use) {
2033 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
2034 "interrupt\n");
2035 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2036 return;
2037 }
2038 sqcp->in_use = 0;
2039 if (sqcp->done_funct) {
2040 sqcp->a_cmnd->result = sqcp->scsi_result;
2041 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
2042 }
2043 sqcp->done_funct = NULL;
2044 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2045}
2046
2047static int scsi_debug_slave_alloc(struct scsi_device * sdp)
2048{
2049 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002050 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
2051 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002052 set_bit(QUEUE_FLAG_BIDI, &sdp->request_queue->queue_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 return 0;
2054}
2055
2056static int scsi_debug_slave_configure(struct scsi_device * sdp)
2057{
2058 struct sdebug_dev_info * devip;
2059
2060 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002061 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
2062 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
2064 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
2065 devip = devInfoReg(sdp);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002066 if (NULL == devip)
2067 return 1; /* no resources, will be marked offline */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 sdp->hostdata = devip;
2069 if (sdp->host->cmd_per_lun)
2070 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
2071 sdp->host->cmd_per_lun);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002072 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 return 0;
2074}
2075
2076static void scsi_debug_slave_destroy(struct scsi_device * sdp)
2077{
2078 struct sdebug_dev_info * devip =
2079 (struct sdebug_dev_info *)sdp->hostdata;
2080
2081 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002082 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
2083 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 if (devip) {
2085 /* make this slot avaliable for re-use */
2086 devip->used = 0;
2087 sdp->hostdata = NULL;
2088 }
2089}
2090
2091static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
2092{
2093 struct sdebug_host_info * sdbg_host;
2094 struct sdebug_dev_info * open_devip = NULL;
2095 struct sdebug_dev_info * devip =
2096 (struct sdebug_dev_info *)sdev->hostdata;
2097
2098 if (devip)
2099 return devip;
2100 sdbg_host = *(struct sdebug_host_info **) sdev->host->hostdata;
2101 if(! sdbg_host) {
2102 printk(KERN_ERR "Host info NULL\n");
2103 return NULL;
2104 }
2105 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
2106 if ((devip->used) && (devip->channel == sdev->channel) &&
2107 (devip->target == sdev->id) &&
2108 (devip->lun == sdev->lun))
2109 return devip;
2110 else {
2111 if ((!devip->used) && (!open_devip))
2112 open_devip = devip;
2113 }
2114 }
2115 if (NULL == open_devip) { /* try and make a new one */
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002116 open_devip = kzalloc(sizeof(*open_devip),GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 if (NULL == open_devip) {
2118 printk(KERN_ERR "%s: out of memory at line %d\n",
2119 __FUNCTION__, __LINE__);
2120 return NULL;
2121 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 open_devip->sdbg_host = sdbg_host;
2123 list_add_tail(&open_devip->dev_list,
2124 &sdbg_host->dev_info_list);
2125 }
2126 if (open_devip) {
2127 open_devip->channel = sdev->channel;
2128 open_devip->target = sdev->id;
2129 open_devip->lun = sdev->lun;
2130 open_devip->sdbg_host = sdbg_host;
2131 open_devip->reset = 1;
2132 open_devip->used = 1;
2133 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
2134 if (scsi_debug_dsense)
2135 open_devip->sense_buff[0] = 0x72;
2136 else {
2137 open_devip->sense_buff[0] = 0x70;
2138 open_devip->sense_buff[7] = 0xa;
2139 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002140 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2141 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142 return open_devip;
2143 }
2144 return NULL;
2145}
2146
2147static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
2148 int asc, int asq)
2149{
2150 unsigned char * sbuff;
2151
2152 sbuff = devip->sense_buff;
2153 memset(sbuff, 0, SDEBUG_SENSE_LEN);
2154 if (scsi_debug_dsense) {
2155 sbuff[0] = 0x72; /* descriptor, current */
2156 sbuff[1] = key;
2157 sbuff[2] = asc;
2158 sbuff[3] = asq;
2159 } else {
2160 sbuff[0] = 0x70; /* fixed, current */
2161 sbuff[2] = key;
2162 sbuff[7] = 0xa; /* implies 18 byte sense buffer */
2163 sbuff[12] = asc;
2164 sbuff[13] = asq;
2165 }
2166 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2167 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
2168 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
2169}
2170
2171static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
2172{
2173 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2174 printk(KERN_INFO "scsi_debug: abort\n");
2175 ++num_aborts;
2176 stop_queued_cmnd(SCpnt);
2177 return SUCCESS;
2178}
2179
2180static int scsi_debug_biosparam(struct scsi_device *sdev,
2181 struct block_device * bdev, sector_t capacity, int *info)
2182{
2183 int res;
2184 unsigned char *buf;
2185
2186 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2187 printk(KERN_INFO "scsi_debug: biosparam\n");
2188 buf = scsi_bios_ptable(bdev);
2189 if (buf) {
2190 res = scsi_partsize(buf, capacity,
2191 &info[2], &info[0], &info[1]);
2192 kfree(buf);
2193 if (! res)
2194 return res;
2195 }
2196 info[0] = sdebug_heads;
2197 info[1] = sdebug_sectors_per;
2198 info[2] = sdebug_cylinders_per;
2199 return 0;
2200}
2201
2202static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
2203{
2204 struct sdebug_dev_info * devip;
2205
2206 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2207 printk(KERN_INFO "scsi_debug: device_reset\n");
2208 ++num_dev_resets;
2209 if (SCpnt) {
2210 devip = devInfoReg(SCpnt->device);
2211 if (devip)
2212 devip->reset = 1;
2213 }
2214 return SUCCESS;
2215}
2216
2217static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
2218{
2219 struct sdebug_host_info *sdbg_host;
2220 struct sdebug_dev_info * dev_info;
2221 struct scsi_device * sdp;
2222 struct Scsi_Host * hp;
2223
2224 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2225 printk(KERN_INFO "scsi_debug: bus_reset\n");
2226 ++num_bus_resets;
2227 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
2228 sdbg_host = *(struct sdebug_host_info **) hp->hostdata;
2229 if (sdbg_host) {
2230 list_for_each_entry(dev_info,
2231 &sdbg_host->dev_info_list,
2232 dev_list)
2233 dev_info->reset = 1;
2234 }
2235 }
2236 return SUCCESS;
2237}
2238
2239static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
2240{
2241 struct sdebug_host_info * sdbg_host;
2242 struct sdebug_dev_info * dev_info;
2243
2244 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2245 printk(KERN_INFO "scsi_debug: host_reset\n");
2246 ++num_host_resets;
2247 spin_lock(&sdebug_host_list_lock);
2248 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
2249 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
2250 dev_list)
2251 dev_info->reset = 1;
2252 }
2253 spin_unlock(&sdebug_host_list_lock);
2254 stop_all_queued();
2255 return SUCCESS;
2256}
2257
2258/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
2259static int stop_queued_cmnd(struct scsi_cmnd * cmnd)
2260{
2261 unsigned long iflags;
2262 int k;
2263 struct sdebug_queued_cmd * sqcp;
2264
2265 spin_lock_irqsave(&queued_arr_lock, iflags);
2266 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2267 sqcp = &queued_arr[k];
2268 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
2269 del_timer_sync(&sqcp->cmnd_timer);
2270 sqcp->in_use = 0;
2271 sqcp->a_cmnd = NULL;
2272 break;
2273 }
2274 }
2275 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2276 return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
2277}
2278
2279/* Deletes (stops) timers of all queued commands */
2280static void stop_all_queued(void)
2281{
2282 unsigned long iflags;
2283 int k;
2284 struct sdebug_queued_cmd * sqcp;
2285
2286 spin_lock_irqsave(&queued_arr_lock, iflags);
2287 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2288 sqcp = &queued_arr[k];
2289 if (sqcp->in_use && sqcp->a_cmnd) {
2290 del_timer_sync(&sqcp->cmnd_timer);
2291 sqcp->in_use = 0;
2292 sqcp->a_cmnd = NULL;
2293 }
2294 }
2295 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2296}
2297
2298/* Initializes timers in queued array */
2299static void __init init_all_queued(void)
2300{
2301 unsigned long iflags;
2302 int k;
2303 struct sdebug_queued_cmd * sqcp;
2304
2305 spin_lock_irqsave(&queued_arr_lock, iflags);
2306 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2307 sqcp = &queued_arr[k];
2308 init_timer(&sqcp->cmnd_timer);
2309 sqcp->in_use = 0;
2310 sqcp->a_cmnd = NULL;
2311 }
2312 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2313}
2314
2315static void __init sdebug_build_parts(unsigned char * ramp)
2316{
2317 struct partition * pp;
2318 int starts[SDEBUG_MAX_PARTS + 2];
2319 int sectors_per_part, num_sectors, k;
2320 int heads_by_sects, start_sec, end_sec;
2321
2322 /* assume partition table already zeroed */
2323 if ((scsi_debug_num_parts < 1) || (sdebug_store_size < 1048576))
2324 return;
2325 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
2326 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
2327 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
2328 "partitions to %d\n", SDEBUG_MAX_PARTS);
2329 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002330 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 sectors_per_part = (num_sectors - sdebug_sectors_per)
2332 / scsi_debug_num_parts;
2333 heads_by_sects = sdebug_heads * sdebug_sectors_per;
2334 starts[0] = sdebug_sectors_per;
2335 for (k = 1; k < scsi_debug_num_parts; ++k)
2336 starts[k] = ((k * sectors_per_part) / heads_by_sects)
2337 * heads_by_sects;
2338 starts[scsi_debug_num_parts] = num_sectors;
2339 starts[scsi_debug_num_parts + 1] = 0;
2340
2341 ramp[510] = 0x55; /* magic partition markings */
2342 ramp[511] = 0xAA;
2343 pp = (struct partition *)(ramp + 0x1be);
2344 for (k = 0; starts[k + 1]; ++k, ++pp) {
2345 start_sec = starts[k];
2346 end_sec = starts[k + 1] - 1;
2347 pp->boot_ind = 0;
2348
2349 pp->cyl = start_sec / heads_by_sects;
2350 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2351 / sdebug_sectors_per;
2352 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2353
2354 pp->end_cyl = end_sec / heads_by_sects;
2355 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2356 / sdebug_sectors_per;
2357 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2358
2359 pp->start_sect = start_sec;
2360 pp->nr_sects = end_sec - start_sec + 1;
2361 pp->sys_ind = 0x83; /* plain Linux partition */
2362 }
2363}
2364
2365static int schedule_resp(struct scsi_cmnd * cmnd,
2366 struct sdebug_dev_info * devip,
2367 done_funct_t done, int scsi_result, int delta_jiff)
2368{
2369 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2370 if (scsi_result) {
2371 struct scsi_device * sdp = cmnd->device;
2372
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002373 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2374 "non-zero result=0x%x\n", sdp->host->host_no,
2375 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 }
2377 }
2378 if (cmnd && devip) {
2379 /* simulate autosense by this driver */
2380 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2381 memcpy(cmnd->sense_buffer, devip->sense_buff,
2382 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2383 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2384 }
2385 if (delta_jiff <= 0) {
2386 if (cmnd)
2387 cmnd->result = scsi_result;
2388 if (done)
2389 done(cmnd);
2390 return 0;
2391 } else {
2392 unsigned long iflags;
2393 int k;
2394 struct sdebug_queued_cmd * sqcp = NULL;
2395
2396 spin_lock_irqsave(&queued_arr_lock, iflags);
2397 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2398 sqcp = &queued_arr[k];
2399 if (! sqcp->in_use)
2400 break;
2401 }
2402 if (k >= SCSI_DEBUG_CANQUEUE) {
2403 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2404 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2405 return 1; /* report busy to mid level */
2406 }
2407 sqcp->in_use = 1;
2408 sqcp->a_cmnd = cmnd;
2409 sqcp->scsi_result = scsi_result;
2410 sqcp->done_funct = done;
2411 sqcp->cmnd_timer.function = timer_intr_handler;
2412 sqcp->cmnd_timer.data = k;
2413 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2414 add_timer(&sqcp->cmnd_timer);
2415 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2416 if (cmnd)
2417 cmnd->result = 0;
2418 return 0;
2419 }
2420}
2421
Douglas Gilbert23183912006-09-16 20:30:47 -04002422/* Note: The following macros create attribute files in the
2423 /sys/module/scsi_debug/parameters directory. Unfortunately this
2424 driver is unaware of a change and cannot trigger auxiliary actions
2425 as it can when the corresponding attribute in the
2426 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2427 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002428module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2429module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2430module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2431module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2432module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002433module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002434module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2435module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2436module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2437module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2438module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2439module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2440module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2441module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002442module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2443 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444
2445MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2446MODULE_DESCRIPTION("SCSI debug adapter driver");
2447MODULE_LICENSE("GPL");
2448MODULE_VERSION(SCSI_DEBUG_VERSION);
2449
2450MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2451MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002452MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2453MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07002454MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002455MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002456MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2457MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002459MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002460MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2462MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002463MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002464MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465
2466
2467static char sdebug_info[256];
2468
2469static const char * scsi_debug_info(struct Scsi_Host * shp)
2470{
2471 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2472 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2473 scsi_debug_version_date, scsi_debug_dev_size_mb,
2474 scsi_debug_opts);
2475 return sdebug_info;
2476}
2477
2478/* scsi_debug_proc_info
2479 * Used if the driver currently has no own support for /proc/scsi
2480 */
2481static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2482 int length, int inout)
2483{
2484 int len, pos, begin;
2485 int orig_length;
2486
2487 orig_length = length;
2488
2489 if (inout == 1) {
2490 char arr[16];
2491 int minLen = length > 15 ? 15 : length;
2492
2493 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2494 return -EACCES;
2495 memcpy(arr, buffer, minLen);
2496 arr[minLen] = '\0';
2497 if (1 != sscanf(arr, "%d", &pos))
2498 return -EINVAL;
2499 scsi_debug_opts = pos;
2500 if (scsi_debug_every_nth != 0)
2501 scsi_debug_cmnd_count = 0;
2502 return length;
2503 }
2504 begin = 0;
2505 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2506 "%s [%s]\n"
2507 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2508 "every_nth=%d(curr:%d)\n"
2509 "delay=%d, max_luns=%d, scsi_level=%d\n"
2510 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2511 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
2512 "host_resets=%d\n",
2513 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2514 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2515 scsi_debug_cmnd_count, scsi_debug_delay,
2516 scsi_debug_max_luns, scsi_debug_scsi_level,
2517 SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
2518 num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
2519 if (pos < offset) {
2520 len = 0;
2521 begin = pos;
2522 }
2523 *start = buffer + (offset - begin); /* Start of wanted data */
2524 len -= (offset - begin);
2525 if (len > length)
2526 len = length;
2527 return len;
2528}
2529
2530static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2531{
2532 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2533}
2534
2535static ssize_t sdebug_delay_store(struct device_driver * ddp,
2536 const char * buf, size_t count)
2537{
2538 int delay;
2539 char work[20];
2540
2541 if (1 == sscanf(buf, "%10s", work)) {
2542 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2543 scsi_debug_delay = delay;
2544 return count;
2545 }
2546 }
2547 return -EINVAL;
2548}
2549DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2550 sdebug_delay_store);
2551
2552static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2553{
2554 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2555}
2556
2557static ssize_t sdebug_opts_store(struct device_driver * ddp,
2558 const char * buf, size_t count)
2559{
2560 int opts;
2561 char work[20];
2562
2563 if (1 == sscanf(buf, "%10s", work)) {
2564 if (0 == strnicmp(work,"0x", 2)) {
2565 if (1 == sscanf(&work[2], "%x", &opts))
2566 goto opts_done;
2567 } else {
2568 if (1 == sscanf(work, "%d", &opts))
2569 goto opts_done;
2570 }
2571 }
2572 return -EINVAL;
2573opts_done:
2574 scsi_debug_opts = opts;
2575 scsi_debug_cmnd_count = 0;
2576 return count;
2577}
2578DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2579 sdebug_opts_store);
2580
2581static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2582{
2583 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2584}
2585static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2586 const char * buf, size_t count)
2587{
2588 int n;
2589
2590 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2591 scsi_debug_ptype = n;
2592 return count;
2593 }
2594 return -EINVAL;
2595}
2596DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2597
2598static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2599{
2600 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2601}
2602static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2603 const char * buf, size_t count)
2604{
2605 int n;
2606
2607 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2608 scsi_debug_dsense = n;
2609 return count;
2610 }
2611 return -EINVAL;
2612}
2613DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2614 sdebug_dsense_store);
2615
Douglas Gilbert23183912006-09-16 20:30:47 -04002616static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2617{
2618 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2619}
2620static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2621 const char * buf, size_t count)
2622{
2623 int n;
2624
2625 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2626 scsi_debug_fake_rw = n;
2627 return count;
2628 }
2629 return -EINVAL;
2630}
2631DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2632 sdebug_fake_rw_store);
2633
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002634static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2635{
2636 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2637}
2638static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2639 const char * buf, size_t count)
2640{
2641 int n;
2642
2643 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2644 scsi_debug_no_lun_0 = n;
2645 return count;
2646 }
2647 return -EINVAL;
2648}
2649DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2650 sdebug_no_lun_0_store);
2651
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2653{
2654 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2655}
2656static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2657 const char * buf, size_t count)
2658{
2659 int n;
2660
2661 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2662 scsi_debug_num_tgts = n;
2663 sdebug_max_tgts_luns();
2664 return count;
2665 }
2666 return -EINVAL;
2667}
2668DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2669 sdebug_num_tgts_store);
2670
2671static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2672{
2673 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2674}
2675DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2676
2677static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2678{
2679 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2680}
2681DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2682
2683static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2684{
2685 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2686}
2687static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2688 const char * buf, size_t count)
2689{
2690 int nth;
2691
2692 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2693 scsi_debug_every_nth = nth;
2694 scsi_debug_cmnd_count = 0;
2695 return count;
2696 }
2697 return -EINVAL;
2698}
2699DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2700 sdebug_every_nth_store);
2701
2702static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2703{
2704 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2705}
2706static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2707 const char * buf, size_t count)
2708{
2709 int n;
2710
2711 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2712 scsi_debug_max_luns = n;
2713 sdebug_max_tgts_luns();
2714 return count;
2715 }
2716 return -EINVAL;
2717}
2718DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2719 sdebug_max_luns_store);
2720
2721static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
2722{
2723 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
2724}
2725DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
2726
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002727static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2728{
2729 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2730}
2731static ssize_t sdebug_virtual_gb_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_virtual_gb = n;
2738 if (scsi_debug_virtual_gb > 0) {
2739 sdebug_capacity = 2048 * 1024;
2740 sdebug_capacity *= scsi_debug_virtual_gb;
2741 } else
2742 sdebug_capacity = sdebug_store_sectors;
2743 return count;
2744 }
2745 return -EINVAL;
2746}
2747DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2748 sdebug_virtual_gb_store);
2749
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
2751{
2752 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
2753}
2754
2755static ssize_t sdebug_add_host_store(struct device_driver * ddp,
2756 const char * buf, size_t count)
2757{
2758 int delta_hosts;
2759 char work[20];
2760
2761 if (1 != sscanf(buf, "%10s", work))
2762 return -EINVAL;
2763 { /* temporary hack around sscanf() problem with -ve nums */
2764 int neg = 0;
2765
2766 if ('-' == *work)
2767 neg = 1;
2768 if (1 != sscanf(work + neg, "%d", &delta_hosts))
2769 return -EINVAL;
2770 if (neg)
2771 delta_hosts = -delta_hosts;
2772 }
2773 if (delta_hosts > 0) {
2774 do {
2775 sdebug_add_adapter();
2776 } while (--delta_hosts);
2777 } else if (delta_hosts < 0) {
2778 do {
2779 sdebug_remove_adapter();
2780 } while (++delta_hosts);
2781 }
2782 return count;
2783}
2784DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
2785 sdebug_add_host_store);
2786
Douglas Gilbert23183912006-09-16 20:30:47 -04002787static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
2788 char * buf)
2789{
2790 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
2791}
2792static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
2793 const char * buf, size_t count)
2794{
2795 int n;
2796
2797 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2798 scsi_debug_vpd_use_hostno = n;
2799 return count;
2800 }
2801 return -EINVAL;
2802}
2803DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
2804 sdebug_vpd_use_hostno_store);
2805
2806/* Note: The following function creates attribute files in the
2807 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
2808 files (over those found in the /sys/module/scsi_debug/parameters
2809 directory) is that auxiliary actions can be triggered when an attribute
2810 is changed. For example see: sdebug_add_host_store() above.
2811 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002812static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002814 int ret;
2815
2816 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2817 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
2818 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2819 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2820 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04002821 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002822 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002823 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002824 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002825 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002826 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
2827 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
2828 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04002829 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
2830 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002831 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832}
2833
2834static void do_remove_driverfs_files(void)
2835{
Douglas Gilbert23183912006-09-16 20:30:47 -04002836 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
2837 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
2839 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
2840 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002842 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
2843 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002845 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
2847 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2848 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2849 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
2850 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2851}
2852
2853static int __init scsi_debug_init(void)
2854{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002855 unsigned int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 int host_to_add;
2857 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002858 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859
2860 if (scsi_debug_dev_size_mb < 1)
2861 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002862 sdebug_store_size = (unsigned int)scsi_debug_dev_size_mb * 1048576;
2863 sdebug_store_sectors = sdebug_store_size / SECT_SIZE;
2864 if (scsi_debug_virtual_gb > 0) {
2865 sdebug_capacity = 2048 * 1024;
2866 sdebug_capacity *= scsi_debug_virtual_gb;
2867 } else
2868 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869
2870 /* play around with geometry, don't waste too much on track 0 */
2871 sdebug_heads = 8;
2872 sdebug_sectors_per = 32;
2873 if (scsi_debug_dev_size_mb >= 16)
2874 sdebug_heads = 32;
2875 else if (scsi_debug_dev_size_mb >= 256)
2876 sdebug_heads = 64;
2877 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2878 (sdebug_sectors_per * sdebug_heads);
2879 if (sdebug_cylinders_per >= 1024) {
2880 /* other LLDs do this; implies >= 1GB ram disk ... */
2881 sdebug_heads = 255;
2882 sdebug_sectors_per = 63;
2883 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2884 (sdebug_sectors_per * sdebug_heads);
2885 }
2886
2887 sz = sdebug_store_size;
2888 fake_storep = vmalloc(sz);
2889 if (NULL == fake_storep) {
2890 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
2891 return -ENOMEM;
2892 }
2893 memset(fake_storep, 0, sz);
2894 if (scsi_debug_num_parts > 0)
2895 sdebug_build_parts(fake_storep);
2896
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002897 ret = device_register(&pseudo_primary);
2898 if (ret < 0) {
2899 printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
2900 ret);
2901 goto free_vm;
2902 }
2903 ret = bus_register(&pseudo_lld_bus);
2904 if (ret < 0) {
2905 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
2906 ret);
2907 goto dev_unreg;
2908 }
2909 ret = driver_register(&sdebug_driverfs_driver);
2910 if (ret < 0) {
2911 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
2912 ret);
2913 goto bus_unreg;
2914 }
2915 ret = do_create_driverfs_files();
2916 if (ret < 0) {
2917 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
2918 ret);
2919 goto del_files;
2920 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002922 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923
Kristian Høgsbergb02b6bc2007-05-09 19:23:12 -04002924 sdebug_driver_template.proc_name = sdebug_proc_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925
2926 host_to_add = scsi_debug_add_host;
2927 scsi_debug_add_host = 0;
2928
2929 for (k = 0; k < host_to_add; k++) {
2930 if (sdebug_add_adapter()) {
2931 printk(KERN_ERR "scsi_debug_init: "
2932 "sdebug_add_adapter failed k=%d\n", k);
2933 break;
2934 }
2935 }
2936
2937 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
2938 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
2939 scsi_debug_add_host);
2940 }
2941 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002942
2943del_files:
2944 do_remove_driverfs_files();
2945 driver_unregister(&sdebug_driverfs_driver);
2946bus_unreg:
2947 bus_unregister(&pseudo_lld_bus);
2948dev_unreg:
2949 device_unregister(&pseudo_primary);
2950free_vm:
2951 vfree(fake_storep);
2952
2953 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954}
2955
2956static void __exit scsi_debug_exit(void)
2957{
2958 int k = scsi_debug_add_host;
2959
2960 stop_all_queued();
2961 for (; k; k--)
2962 sdebug_remove_adapter();
2963 do_remove_driverfs_files();
2964 driver_unregister(&sdebug_driverfs_driver);
2965 bus_unregister(&pseudo_lld_bus);
2966 device_unregister(&pseudo_primary);
2967
2968 vfree(fake_storep);
2969}
2970
2971device_initcall(scsi_debug_init);
2972module_exit(scsi_debug_exit);
2973
Adrian Bunk52c1da32005-06-23 22:05:33 -07002974static void pseudo_0_release(struct device * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975{
2976 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2977 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
2978}
2979
2980static struct device pseudo_primary = {
2981 .bus_id = "pseudo_0",
2982 .release = pseudo_0_release,
2983};
2984
2985static int pseudo_lld_bus_match(struct device *dev,
2986 struct device_driver *dev_driver)
2987{
2988 return 1;
2989}
2990
2991static struct bus_type pseudo_lld_bus = {
2992 .name = "pseudo",
2993 .match = pseudo_lld_bus_match,
Russell Kingbbbe3a42006-01-05 14:44:46 +00002994 .probe = sdebug_driver_probe,
2995 .remove = sdebug_driver_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996};
2997
2998static void sdebug_release_adapter(struct device * dev)
2999{
3000 struct sdebug_host_info *sdbg_host;
3001
3002 sdbg_host = to_sdebug_host(dev);
3003 kfree(sdbg_host);
3004}
3005
3006static int sdebug_add_adapter(void)
3007{
3008 int k, devs_per_host;
3009 int error = 0;
3010 struct sdebug_host_info *sdbg_host;
3011 struct sdebug_dev_info *sdbg_devinfo;
3012 struct list_head *lh, *lh_sf;
3013
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003014 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 if (NULL == sdbg_host) {
3016 printk(KERN_ERR "%s: out of memory at line %d\n",
3017 __FUNCTION__, __LINE__);
3018 return -ENOMEM;
3019 }
3020
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
3022
3023 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
3024 for (k = 0; k < devs_per_host; k++) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003025 sdbg_devinfo = kzalloc(sizeof(*sdbg_devinfo),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 if (NULL == sdbg_devinfo) {
3027 printk(KERN_ERR "%s: out of memory at line %d\n",
3028 __FUNCTION__, __LINE__);
3029 error = -ENOMEM;
3030 goto clean;
3031 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032 sdbg_devinfo->sdbg_host = sdbg_host;
3033 list_add_tail(&sdbg_devinfo->dev_list,
3034 &sdbg_host->dev_info_list);
3035 }
3036
3037 spin_lock(&sdebug_host_list_lock);
3038 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
3039 spin_unlock(&sdebug_host_list_lock);
3040
3041 sdbg_host->dev.bus = &pseudo_lld_bus;
3042 sdbg_host->dev.parent = &pseudo_primary;
3043 sdbg_host->dev.release = &sdebug_release_adapter;
3044 sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host);
3045
3046 error = device_register(&sdbg_host->dev);
3047
3048 if (error)
3049 goto clean;
3050
3051 ++scsi_debug_add_host;
3052 return error;
3053
3054clean:
3055 list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) {
3056 sdbg_devinfo = list_entry(lh, struct sdebug_dev_info,
3057 dev_list);
3058 list_del(&sdbg_devinfo->dev_list);
3059 kfree(sdbg_devinfo);
3060 }
3061
3062 kfree(sdbg_host);
3063 return error;
3064}
3065
3066static void sdebug_remove_adapter(void)
3067{
3068 struct sdebug_host_info * sdbg_host = NULL;
3069
3070 spin_lock(&sdebug_host_list_lock);
3071 if (!list_empty(&sdebug_host_list)) {
3072 sdbg_host = list_entry(sdebug_host_list.prev,
3073 struct sdebug_host_info, host_list);
3074 list_del(&sdbg_host->host_list);
3075 }
3076 spin_unlock(&sdebug_host_list_lock);
3077
3078 if (!sdbg_host)
3079 return;
3080
3081 device_unregister(&sdbg_host->dev);
3082 --scsi_debug_add_host;
3083}
3084
3085static int sdebug_driver_probe(struct device * dev)
3086{
3087 int error = 0;
3088 struct sdebug_host_info *sdbg_host;
3089 struct Scsi_Host *hpnt;
3090
3091 sdbg_host = to_sdebug_host(dev);
3092
3093 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
3094 if (NULL == hpnt) {
3095 printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__);
3096 error = -ENODEV;
3097 return error;
3098 }
3099
3100 sdbg_host->shost = hpnt;
3101 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
3102 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
3103 hpnt->max_id = scsi_debug_num_tgts + 1;
3104 else
3105 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003106 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107
3108 error = scsi_add_host(hpnt, &sdbg_host->dev);
3109 if (error) {
3110 printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
3111 error = -ENODEV;
3112 scsi_host_put(hpnt);
3113 } else
3114 scsi_scan_host(hpnt);
3115
3116
3117 return error;
3118}
3119
3120static int sdebug_driver_remove(struct device * dev)
3121{
3122 struct list_head *lh, *lh_sf;
3123 struct sdebug_host_info *sdbg_host;
3124 struct sdebug_dev_info *sdbg_devinfo;
3125
3126 sdbg_host = to_sdebug_host(dev);
3127
3128 if (!sdbg_host) {
3129 printk(KERN_ERR "%s: Unable to locate host info\n",
3130 __FUNCTION__);
3131 return -ENODEV;
3132 }
3133
3134 scsi_remove_host(sdbg_host->shost);
3135
3136 list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) {
3137 sdbg_devinfo = list_entry(lh, struct sdebug_dev_info,
3138 dev_list);
3139 list_del(&sdbg_devinfo->dev_list);
3140 kfree(sdbg_devinfo);
3141 }
3142
3143 scsi_host_put(sdbg_host->shost);
3144 return 0;
3145}
3146
3147static void sdebug_max_tgts_luns(void)
3148{
3149 struct sdebug_host_info * sdbg_host;
3150 struct Scsi_Host *hpnt;
3151
3152 spin_lock(&sdebug_host_list_lock);
3153 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3154 hpnt = sdbg_host->shost;
3155 if ((hpnt->this_id >= 0) &&
3156 (scsi_debug_num_tgts > hpnt->this_id))
3157 hpnt->max_id = scsi_debug_num_tgts + 1;
3158 else
3159 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003160 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 }
3162 spin_unlock(&sdebug_host_list_lock);
3163}