blob: 26979e0185bec7bcef6b92f3aff09a12e1d05f2e [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#include <linux/blkdev.h>
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090043
44#include <scsi/scsi.h>
45#include <scsi/scsi_cmnd.h>
46#include <scsi/scsi_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <scsi/scsi_host.h>
48#include <scsi/scsicam.h>
49
50#include <linux/stat.h>
51
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include "scsi_logging.h"
53#include "scsi_debug.h"
54
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050055#define SCSI_DEBUG_VERSION "1.81"
56static const char * scsi_debug_version_date = "20070104";
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050058/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040059#define NO_ADDITIONAL_SENSE 0x0
60#define LOGICAL_UNIT_NOT_READY 0x4
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040062#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070063#define INVALID_OPCODE 0x20
64#define ADDR_OUT_OF_RANGE 0x21
65#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040066#define INVALID_FIELD_IN_PARAM_LIST 0x26
Linus Torvalds1da177e2005-04-16 15:20:36 -070067#define POWERON_RESET 0x29
68#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050069#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040070#define THRESHOLD_EXCEEDED 0x5d
71#define LOW_POWER_COND_ON 0x5e
Linus Torvalds1da177e2005-04-16 15:20:36 -070072
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050073/* Additional Sense Code Qualifier (ASCQ) */
74#define ACK_NAK_TO 0x3
75
Linus Torvalds1da177e2005-04-16 15:20:36 -070076#define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
77
78/* Default values for driver parameters */
79#define DEF_NUM_HOST 1
80#define DEF_NUM_TGTS 1
81#define DEF_MAX_LUNS 1
82/* With these defaults, this driver will make 1 host with 1 target
83 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
84 */
85#define DEF_DELAY 1
86#define DEF_DEV_SIZE_MB 8
87#define DEF_EVERY_NTH 0
88#define DEF_NUM_PARTS 0
89#define DEF_OPTS 0
90#define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */
91#define DEF_PTYPE 0
92#define DEF_D_SENSE 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -040093#define DEF_NO_LUN_0 0
94#define DEF_VIRTUAL_GB 0
Douglas Gilbert23183912006-09-16 20:30:47 -040095#define DEF_FAKE_RW 0
96#define DEF_VPD_USE_HOSTNO 1
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
98/* bit mask values for scsi_debug_opts */
99#define SCSI_DEBUG_OPT_NOISE 1
100#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
101#define SCSI_DEBUG_OPT_TIMEOUT 4
102#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500103#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104/* When "every_nth" > 0 then modulo "every_nth" commands:
105 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
106 * - a RECOVERED_ERROR is simulated on successful read and write
107 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500108 * - a TRANSPORT_ERROR is simulated on successful read and write
109 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 *
111 * When "every_nth" < 0 then after "- every_nth" commands:
112 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
113 * - a RECOVERED_ERROR is simulated on successful read and write
114 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500115 * - a TRANSPORT_ERROR is simulated on successful read and write
116 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 * This will continue until some other action occurs (e.g. the user
118 * writing a new value (other than -1 or 1) to every_nth via sysfs).
119 */
120
121/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
122 * sector on read commands: */
123#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
124
125/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
126 * or "peripheral device" addressing (value 0) */
127#define SAM2_LUN_ADDRESS_METHOD 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400128#define SAM2_WLUN_REPORT_LUNS 0xc101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
130static int scsi_debug_add_host = DEF_NUM_HOST;
131static int scsi_debug_delay = DEF_DELAY;
132static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
133static int scsi_debug_every_nth = DEF_EVERY_NTH;
134static int scsi_debug_max_luns = DEF_MAX_LUNS;
135static int scsi_debug_num_parts = DEF_NUM_PARTS;
136static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
137static int scsi_debug_opts = DEF_OPTS;
138static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
139static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
140static int scsi_debug_dsense = DEF_D_SENSE;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400141static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
142static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
Douglas Gilbert23183912006-09-16 20:30:47 -0400143static int scsi_debug_fake_rw = DEF_FAKE_RW;
144static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
146static int scsi_debug_cmnd_count = 0;
147
148#define DEV_READONLY(TGT) (0)
149#define DEV_REMOVEABLE(TGT) (0)
150
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400151static unsigned int sdebug_store_size; /* in bytes */
152static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153static sector_t sdebug_capacity; /* in sectors */
154
155/* old BIOS stuff, kernel may get rid of them but some mode sense pages
156 may still need them */
157static int sdebug_heads; /* heads per disk */
158static int sdebug_cylinders_per; /* cylinders per surface */
159static int sdebug_sectors_per; /* sectors per cylinder */
160
161/* default sector size is 512 bytes, 2**9 bytes */
162#define POW2_SECT_SIZE 9
163#define SECT_SIZE (1 << POW2_SECT_SIZE)
164#define SECT_SIZE_PER(TGT) SECT_SIZE
165
166#define SDEBUG_MAX_PARTS 4
167
168#define SDEBUG_SENSE_LEN 32
169
170struct sdebug_dev_info {
171 struct list_head dev_list;
172 unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */
173 unsigned int channel;
174 unsigned int target;
175 unsigned int lun;
176 struct sdebug_host_info *sdbg_host;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400177 unsigned int wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 char reset;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400179 char stopped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 char used;
181};
182
183struct sdebug_host_info {
184 struct list_head host_list;
185 struct Scsi_Host *shost;
186 struct device dev;
187 struct list_head dev_info_list;
188};
189
190#define to_sdebug_host(d) \
191 container_of(d, struct sdebug_host_info, dev)
192
193static LIST_HEAD(sdebug_host_list);
194static DEFINE_SPINLOCK(sdebug_host_list_lock);
195
196typedef void (* done_funct_t) (struct scsi_cmnd *);
197
198struct sdebug_queued_cmd {
199 int in_use;
200 struct timer_list cmnd_timer;
201 done_funct_t done_funct;
202 struct scsi_cmnd * a_cmnd;
203 int scsi_result;
204};
205static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
206
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +0100207static struct scsi_host_template sdebug_driver_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 .proc_info = scsi_debug_proc_info,
209 .name = "SCSI DEBUG",
210 .info = scsi_debug_info,
211 .slave_alloc = scsi_debug_slave_alloc,
212 .slave_configure = scsi_debug_slave_configure,
213 .slave_destroy = scsi_debug_slave_destroy,
214 .ioctl = scsi_debug_ioctl,
215 .queuecommand = scsi_debug_queuecommand,
216 .eh_abort_handler = scsi_debug_abort,
217 .eh_bus_reset_handler = scsi_debug_bus_reset,
218 .eh_device_reset_handler = scsi_debug_device_reset,
219 .eh_host_reset_handler = scsi_debug_host_reset,
220 .bios_param = scsi_debug_biosparam,
221 .can_queue = SCSI_DEBUG_CANQUEUE,
222 .this_id = 7,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400223 .sg_tablesize = 256,
224 .cmd_per_lun = 16,
225 .max_sectors = 0xffff,
FUJITA Tomonoricbccc202008-02-16 23:57:15 +0900226 .use_clustering = DISABLE_CLUSTERING,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 .module = THIS_MODULE,
228};
229
230static unsigned char * fake_storep; /* ramdisk storage */
231
232static int num_aborts = 0;
233static int num_dev_resets = 0;
234static int num_bus_resets = 0;
235static int num_host_resets = 0;
236
237static DEFINE_SPINLOCK(queued_arr_lock);
238static DEFINE_RWLOCK(atomic_rw);
239
240static char sdebug_proc_name[] = "scsi_debug";
241
242static int sdebug_driver_probe(struct device *);
243static int sdebug_driver_remove(struct device *);
244static struct bus_type pseudo_lld_bus;
245
246static struct device_driver sdebug_driverfs_driver = {
247 .name = sdebug_proc_name,
248 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249};
250
251static const int check_condition_result =
252 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
253
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400254static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
255 0, 0, 0x2, 0x4b};
256static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
257 0, 0, 0x0, 0x0};
258
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259/* function declarations */
260static int resp_inquiry(struct scsi_cmnd * SCpnt, int target,
261 struct sdebug_dev_info * devip);
262static int resp_requests(struct scsi_cmnd * SCpnt,
263 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400264static int resp_start_stop(struct scsi_cmnd * scp,
265 struct sdebug_dev_info * devip);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200266static int resp_report_tgtpgs(struct scsi_cmnd * scp,
267 struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268static int resp_readcap(struct scsi_cmnd * SCpnt,
269 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400270static int resp_readcap16(struct scsi_cmnd * SCpnt,
271 struct sdebug_dev_info * devip);
272static int resp_mode_sense(struct scsi_cmnd * scp, int target,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400274static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
275 struct sdebug_dev_info * devip);
276static int resp_log_sense(struct scsi_cmnd * scp,
277 struct sdebug_dev_info * devip);
278static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
279 unsigned int num, struct sdebug_dev_info * devip);
280static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
281 unsigned int num, struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282static int resp_report_luns(struct scsi_cmnd * SCpnt,
283 struct sdebug_dev_info * devip);
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900284static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
285 unsigned int num, struct sdebug_dev_info *devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
287 int arr_len);
288static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
289 int max_arr_len);
290static void timer_intr_handler(unsigned long);
291static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev);
292static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
293 int asc, int asq);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400294static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
295 struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296static int schedule_resp(struct scsi_cmnd * cmnd,
297 struct sdebug_dev_info * devip,
298 done_funct_t done, int scsi_result, int delta_jiff);
299static void __init sdebug_build_parts(unsigned char * ramp);
300static void __init init_all_queued(void);
301static void stop_all_queued(void);
302static int stop_queued_cmnd(struct scsi_cmnd * cmnd);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200303static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
304 int target_dev_id, int dev_id_num,
305 const char * dev_id_str, int dev_id_str_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400306static int inquiry_evpd_88(unsigned char * arr, int target_dev_id);
Randy Dunlap6ecaff72006-07-11 20:53:22 -0700307static int do_create_driverfs_files(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308static void do_remove_driverfs_files(void);
309
310static int sdebug_add_adapter(void);
311static void sdebug_remove_adapter(void);
312static void sdebug_max_tgts_luns(void);
313
314static struct device pseudo_primary;
315static struct bus_type pseudo_lld_bus;
316
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900317static void get_data_transfer_info(unsigned char *cmd,
318 unsigned long long *lba, unsigned int *num)
319{
320 int i;
321
322 switch (*cmd) {
323 case WRITE_16:
324 case READ_16:
325 for (*lba = 0, i = 0; i < 8; ++i) {
326 if (i > 0)
327 *lba <<= 8;
328 *lba += cmd[2 + i];
329 }
330 *num = cmd[13] + (cmd[12] << 8) +
331 (cmd[11] << 16) + (cmd[10] << 24);
332 break;
333 case WRITE_12:
334 case READ_12:
335 *lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
336 *num = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
337 break;
338 case WRITE_10:
339 case READ_10:
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900340 case XDWRITEREAD_10:
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900341 *lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
342 *num = cmd[8] + (cmd[7] << 8);
343 break;
344 case WRITE_6:
345 case READ_6:
346 *lba = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
347 *num = (0 == cmd[4]) ? 256 : cmd[4];
348 break;
349 default:
350 break;
351 }
352}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
354static
355int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
356{
357 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900358 int len, k;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400359 unsigned int num;
360 unsigned long long lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 int errsts = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400362 int target = SCpnt->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 struct sdebug_dev_info * devip = NULL;
364 int inj_recovered = 0;
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500365 int inj_transport = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400366 int delay_override = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367
368 if (done == NULL)
369 return 0; /* assume mid level reprocessing command */
370
Boaz Harroshc73961e2007-09-07 06:50:20 +0900371 scsi_set_resid(SCpnt, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
373 printk(KERN_INFO "scsi_debug: cmd ");
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400374 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 printk("%02x ", (int)cmd[k]);
376 printk("\n");
377 }
378 if(target == sdebug_driver_template.this_id) {
379 printk(KERN_INFO "scsi_debug: initiator's id used as "
380 "target!\n");
381 return schedule_resp(SCpnt, NULL, done,
382 DID_NO_CONNECT << 16, 0);
383 }
384
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400385 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
386 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 return schedule_resp(SCpnt, NULL, done,
388 DID_NO_CONNECT << 16, 0);
389 devip = devInfoReg(SCpnt->device);
390 if (NULL == devip)
391 return schedule_resp(SCpnt, NULL, done,
392 DID_NO_CONNECT << 16, 0);
393
394 if ((scsi_debug_every_nth != 0) &&
395 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
396 scsi_debug_cmnd_count = 0;
397 if (scsi_debug_every_nth < -1)
398 scsi_debug_every_nth = -1;
399 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
400 return 0; /* ignore command causing timeout */
401 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
402 inj_recovered = 1; /* to reads and writes below */
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500403 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
404 inj_transport = 1; /* to reads and writes below */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 }
406
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400407 if (devip->wlun) {
408 switch (*cmd) {
409 case INQUIRY:
410 case REQUEST_SENSE:
411 case TEST_UNIT_READY:
412 case REPORT_LUNS:
413 break; /* only allowable wlun commands */
414 default:
415 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
416 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
417 "not supported for wlun\n", *cmd);
418 mk_sense_buffer(devip, ILLEGAL_REQUEST,
419 INVALID_OPCODE, 0);
420 errsts = check_condition_result;
421 return schedule_resp(SCpnt, devip, done, errsts,
422 0);
423 }
424 }
425
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 switch (*cmd) {
427 case INQUIRY: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400428 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 errsts = resp_inquiry(SCpnt, target, devip);
430 break;
431 case REQUEST_SENSE: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400432 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 errsts = resp_requests(SCpnt, devip);
434 break;
435 case REZERO_UNIT: /* actually this is REWIND for SSC */
436 case START_STOP:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400437 errsts = resp_start_stop(SCpnt, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 break;
439 case ALLOW_MEDIUM_REMOVAL:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400440 if ((errsts = check_readiness(SCpnt, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 break;
442 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
443 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
444 cmd[4] ? "inhibited" : "enabled");
445 break;
446 case SEND_DIAGNOSTIC: /* mandatory */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400447 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 break;
449 case TEST_UNIT_READY: /* mandatory */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400450 delay_override = 1;
451 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 break;
453 case RESERVE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400454 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 break;
456 case RESERVE_10:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400457 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 break;
459 case RELEASE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400460 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 break;
462 case RELEASE_10:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400463 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 break;
465 case READ_CAPACITY:
466 errsts = resp_readcap(SCpnt, devip);
467 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400468 case SERVICE_ACTION_IN:
469 if (SAI_READ_CAPACITY_16 != cmd[1]) {
470 mk_sense_buffer(devip, ILLEGAL_REQUEST,
471 INVALID_OPCODE, 0);
472 errsts = check_condition_result;
473 break;
474 }
475 errsts = resp_readcap16(SCpnt, devip);
476 break;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200477 case MAINTENANCE_IN:
478 if (MI_REPORT_TARGET_PGS != cmd[1]) {
479 mk_sense_buffer(devip, ILLEGAL_REQUEST,
480 INVALID_OPCODE, 0);
481 errsts = check_condition_result;
482 break;
483 }
484 errsts = resp_report_tgtpgs(SCpnt, devip);
485 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 case READ_16:
487 case READ_12:
488 case READ_10:
489 case READ_6:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400490 if ((errsts = check_readiness(SCpnt, 0, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 break;
Douglas Gilbert23183912006-09-16 20:30:47 -0400492 if (scsi_debug_fake_rw)
493 break;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900494 get_data_transfer_info(cmd, &lba, &num);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400495 errsts = resp_read(SCpnt, lba, num, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 if (inj_recovered && (0 == errsts)) {
497 mk_sense_buffer(devip, RECOVERED_ERROR,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400498 THRESHOLD_EXCEEDED, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 errsts = check_condition_result;
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500500 } else if (inj_transport && (0 == errsts)) {
501 mk_sense_buffer(devip, ABORTED_COMMAND,
502 TRANSPORT_PROBLEM, ACK_NAK_TO);
503 errsts = check_condition_result;
504 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 break;
506 case REPORT_LUNS: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400507 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 errsts = resp_report_luns(SCpnt, devip);
509 break;
510 case VERIFY: /* 10 byte SBC-2 command */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400511 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 break;
513 case WRITE_16:
514 case WRITE_12:
515 case WRITE_10:
516 case WRITE_6:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400517 if ((errsts = check_readiness(SCpnt, 0, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 break;
Douglas Gilbert23183912006-09-16 20:30:47 -0400519 if (scsi_debug_fake_rw)
520 break;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900521 get_data_transfer_info(cmd, &lba, &num);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400522 errsts = resp_write(SCpnt, lba, num, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 if (inj_recovered && (0 == errsts)) {
524 mk_sense_buffer(devip, RECOVERED_ERROR,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400525 THRESHOLD_EXCEEDED, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 errsts = check_condition_result;
527 }
528 break;
529 case MODE_SENSE:
530 case MODE_SENSE_10:
531 errsts = resp_mode_sense(SCpnt, target, devip);
532 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400533 case MODE_SELECT:
534 errsts = resp_mode_select(SCpnt, 1, devip);
535 break;
536 case MODE_SELECT_10:
537 errsts = resp_mode_select(SCpnt, 0, devip);
538 break;
539 case LOG_SENSE:
540 errsts = resp_log_sense(SCpnt, devip);
541 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 case SYNCHRONIZE_CACHE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400543 delay_override = 1;
544 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 break;
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500546 case WRITE_BUFFER:
547 errsts = check_readiness(SCpnt, 1, devip);
548 break;
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900549 case XDWRITEREAD_10:
550 if (!scsi_bidi_cmnd(SCpnt)) {
551 mk_sense_buffer(devip, ILLEGAL_REQUEST,
552 INVALID_FIELD_IN_CDB, 0);
553 errsts = check_condition_result;
554 break;
555 }
556
557 errsts = check_readiness(SCpnt, 0, devip);
558 if (errsts)
559 break;
560 if (scsi_debug_fake_rw)
561 break;
562 get_data_transfer_info(cmd, &lba, &num);
563 errsts = resp_read(SCpnt, lba, num, devip);
564 if (errsts)
565 break;
566 errsts = resp_write(SCpnt, lba, num, devip);
567 if (errsts)
568 break;
569 errsts = resp_xdwriteread(SCpnt, lba, num, devip);
570 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 default:
572 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
573 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
574 "supported\n", *cmd);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400575 if ((errsts = check_readiness(SCpnt, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 break; /* Unit attention takes precedence */
577 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
578 errsts = check_condition_result;
579 break;
580 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400581 return schedule_resp(SCpnt, devip, done, errsts,
582 (delay_override ? 0 : scsi_debug_delay));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583}
584
585static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
586{
587 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
588 printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
589 }
590 return -EINVAL;
591 /* return -ENOTTY; // correct return but upsets fdisk */
592}
593
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400594static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
595 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596{
597 if (devip->reset) {
598 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
599 printk(KERN_INFO "scsi_debug: Reporting Unit "
600 "attention: power on reset\n");
601 devip->reset = 0;
602 mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
603 return check_condition_result;
604 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400605 if ((0 == reset_only) && devip->stopped) {
606 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
607 printk(KERN_INFO "scsi_debug: Reporting Not "
608 "ready: initializing command required\n");
609 mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
610 0x2);
611 return check_condition_result;
612 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 return 0;
614}
615
616/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
617static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
618 int arr_len)
619{
620 int k, req_len, act_len, len, active;
621 void * kaddr;
622 void * kaddr_off;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900623 struct scatterlist *sg;
624 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900626 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900628 if (!sdb->table.sgl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 return (DID_ERROR << 16);
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900630 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 return (DID_ERROR << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 active = 1;
Jens Axboe852e0342007-07-16 10:19:24 +0200633 req_len = act_len = 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900634 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, k) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 if (active) {
636 kaddr = (unsigned char *)
Jens Axboe45711f12007-10-22 21:19:53 +0200637 kmap_atomic(sg_page(sg), KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 if (NULL == kaddr)
639 return (DID_ERROR << 16);
Jens Axboe852e0342007-07-16 10:19:24 +0200640 kaddr_off = (unsigned char *)kaddr + sg->offset;
641 len = sg->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 if ((req_len + len) > arr_len) {
643 active = 0;
644 len = arr_len - req_len;
645 }
646 memcpy(kaddr_off, arr + req_len, len);
647 kunmap_atomic(kaddr, KM_USER0);
648 act_len += len;
649 }
Jens Axboe852e0342007-07-16 10:19:24 +0200650 req_len += sg->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 }
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900652 if (sdb->resid)
653 sdb->resid -= act_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400654 else
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900655 sdb->resid = req_len - act_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 return 0;
657}
658
659/* Returns number of bytes fetched into 'arr' or -1 if error. */
660static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
661 int max_arr_len)
662{
663 int k, req_len, len, fin;
664 void * kaddr;
665 void * kaddr_off;
Jens Axboe852e0342007-07-16 10:19:24 +0200666 struct scatterlist * sg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
Boaz Harroshc73961e2007-09-07 06:50:20 +0900668 if (0 == scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 return 0;
Boaz Harroshc73961e2007-09-07 06:50:20 +0900670 if (NULL == scsi_sglist(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 return -1;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900672 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 return -1;
Jens Axboe852e0342007-07-16 10:19:24 +0200674 req_len = fin = 0;
Boaz Harroshc73961e2007-09-07 06:50:20 +0900675 scsi_for_each_sg(scp, sg, scsi_sg_count(scp), k) {
Jens Axboe45711f12007-10-22 21:19:53 +0200676 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 if (NULL == kaddr)
678 return -1;
Jens Axboe852e0342007-07-16 10:19:24 +0200679 kaddr_off = (unsigned char *)kaddr + sg->offset;
680 len = sg->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 if ((req_len + len) > max_arr_len) {
682 len = max_arr_len - req_len;
683 fin = 1;
684 }
685 memcpy(arr + req_len, kaddr_off, len);
686 kunmap_atomic(kaddr, KM_USER0);
687 if (fin)
688 return req_len + len;
Jens Axboe852e0342007-07-16 10:19:24 +0200689 req_len += sg->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 }
691 return req_len;
692}
693
694
695static const char * inq_vendor_id = "Linux ";
696static const char * inq_product_id = "scsi_debug ";
697static const char * inq_product_rev = "0004";
698
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200699static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
700 int target_dev_id, int dev_id_num,
701 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400702 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400704 int num, port_a;
705 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400707 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 /* T10 vendor identifier field format (faked) */
709 arr[0] = 0x2; /* ASCII */
710 arr[1] = 0x1;
711 arr[2] = 0x0;
712 memcpy(&arr[4], inq_vendor_id, 8);
713 memcpy(&arr[12], inq_product_id, 16);
714 memcpy(&arr[28], dev_id_str, dev_id_str_len);
715 num = 8 + 16 + dev_id_str_len;
716 arr[3] = num;
717 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400718 if (dev_id_num >= 0) {
719 /* NAA-5, Logical unit identifier (binary) */
720 arr[num++] = 0x1; /* binary (not necessarily sas) */
721 arr[num++] = 0x3; /* PIV=0, lu, naa */
722 arr[num++] = 0x0;
723 arr[num++] = 0x8;
724 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
725 arr[num++] = 0x33;
726 arr[num++] = 0x33;
727 arr[num++] = 0x30;
728 arr[num++] = (dev_id_num >> 24);
729 arr[num++] = (dev_id_num >> 16) & 0xff;
730 arr[num++] = (dev_id_num >> 8) & 0xff;
731 arr[num++] = dev_id_num & 0xff;
732 /* Target relative port number */
733 arr[num++] = 0x61; /* proto=sas, binary */
734 arr[num++] = 0x94; /* PIV=1, target port, rel port */
735 arr[num++] = 0x0; /* reserved */
736 arr[num++] = 0x4; /* length */
737 arr[num++] = 0x0; /* reserved */
738 arr[num++] = 0x0; /* reserved */
739 arr[num++] = 0x0;
740 arr[num++] = 0x1; /* relative port A */
741 }
742 /* NAA-5, Target port identifier */
743 arr[num++] = 0x61; /* proto=sas, binary */
744 arr[num++] = 0x93; /* piv=1, target port, naa */
745 arr[num++] = 0x0;
746 arr[num++] = 0x8;
747 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
748 arr[num++] = 0x22;
749 arr[num++] = 0x22;
750 arr[num++] = 0x20;
751 arr[num++] = (port_a >> 24);
752 arr[num++] = (port_a >> 16) & 0xff;
753 arr[num++] = (port_a >> 8) & 0xff;
754 arr[num++] = port_a & 0xff;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200755 /* NAA-5, Target port group identifier */
756 arr[num++] = 0x61; /* proto=sas, binary */
757 arr[num++] = 0x95; /* piv=1, target port group id */
758 arr[num++] = 0x0;
759 arr[num++] = 0x4;
760 arr[num++] = 0;
761 arr[num++] = 0;
762 arr[num++] = (port_group_id >> 8) & 0xff;
763 arr[num++] = port_group_id & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400764 /* NAA-5, Target device identifier */
765 arr[num++] = 0x61; /* proto=sas, binary */
766 arr[num++] = 0xa3; /* piv=1, target device, naa */
767 arr[num++] = 0x0;
768 arr[num++] = 0x8;
769 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
770 arr[num++] = 0x22;
771 arr[num++] = 0x22;
772 arr[num++] = 0x20;
773 arr[num++] = (target_dev_id >> 24);
774 arr[num++] = (target_dev_id >> 16) & 0xff;
775 arr[num++] = (target_dev_id >> 8) & 0xff;
776 arr[num++] = target_dev_id & 0xff;
777 /* SCSI name string: Target device identifier */
778 arr[num++] = 0x63; /* proto=sas, UTF-8 */
779 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
780 arr[num++] = 0x0;
781 arr[num++] = 24;
782 memcpy(arr + num, "naa.52222220", 12);
783 num += 12;
784 snprintf(b, sizeof(b), "%08X", target_dev_id);
785 memcpy(arr + num, b, 8);
786 num += 8;
787 memset(arr + num, 0, 4);
788 num += 4;
789 return num;
790}
791
792
793static unsigned char vpd84_data[] = {
794/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
795 0x22,0x22,0x22,0x0,0xbb,0x1,
796 0x22,0x22,0x22,0x0,0xbb,0x2,
797};
798
799static int inquiry_evpd_84(unsigned char * arr)
800{
801 memcpy(arr, vpd84_data, sizeof(vpd84_data));
802 return sizeof(vpd84_data);
803}
804
805static int inquiry_evpd_85(unsigned char * arr)
806{
807 int num = 0;
808 const char * na1 = "https://www.kernel.org/config";
809 const char * na2 = "http://www.kernel.org/log";
810 int plen, olen;
811
812 arr[num++] = 0x1; /* lu, storage config */
813 arr[num++] = 0x0; /* reserved */
814 arr[num++] = 0x0;
815 olen = strlen(na1);
816 plen = olen + 1;
817 if (plen % 4)
818 plen = ((plen / 4) + 1) * 4;
819 arr[num++] = plen; /* length, null termianted, padded */
820 memcpy(arr + num, na1, olen);
821 memset(arr + num + olen, 0, plen - olen);
822 num += plen;
823
824 arr[num++] = 0x4; /* lu, logging */
825 arr[num++] = 0x0; /* reserved */
826 arr[num++] = 0x0;
827 olen = strlen(na2);
828 plen = olen + 1;
829 if (plen % 4)
830 plen = ((plen / 4) + 1) * 4;
831 arr[num++] = plen; /* length, null terminated, padded */
832 memcpy(arr + num, na2, olen);
833 memset(arr + num + olen, 0, plen - olen);
834 num += plen;
835
836 return num;
837}
838
839/* SCSI ports VPD page */
840static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
841{
842 int num = 0;
843 int port_a, port_b;
844
845 port_a = target_dev_id + 1;
846 port_b = port_a + 1;
847 arr[num++] = 0x0; /* reserved */
848 arr[num++] = 0x0; /* reserved */
849 arr[num++] = 0x0;
850 arr[num++] = 0x1; /* relative port 1 (primary) */
851 memset(arr + num, 0, 6);
852 num += 6;
853 arr[num++] = 0x0;
854 arr[num++] = 12; /* length tp descriptor */
855 /* naa-5 target port identifier (A) */
856 arr[num++] = 0x61; /* proto=sas, binary */
857 arr[num++] = 0x93; /* PIV=1, target port, NAA */
858 arr[num++] = 0x0; /* reserved */
859 arr[num++] = 0x8; /* length */
860 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
861 arr[num++] = 0x22;
862 arr[num++] = 0x22;
863 arr[num++] = 0x20;
864 arr[num++] = (port_a >> 24);
865 arr[num++] = (port_a >> 16) & 0xff;
866 arr[num++] = (port_a >> 8) & 0xff;
867 arr[num++] = port_a & 0xff;
868
869 arr[num++] = 0x0; /* reserved */
870 arr[num++] = 0x0; /* reserved */
871 arr[num++] = 0x0;
872 arr[num++] = 0x2; /* relative port 2 (secondary) */
873 memset(arr + num, 0, 6);
874 num += 6;
875 arr[num++] = 0x0;
876 arr[num++] = 12; /* length tp descriptor */
877 /* naa-5 target port identifier (B) */
878 arr[num++] = 0x61; /* proto=sas, binary */
879 arr[num++] = 0x93; /* PIV=1, target port, NAA */
880 arr[num++] = 0x0; /* reserved */
881 arr[num++] = 0x8; /* length */
882 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
883 arr[num++] = 0x22;
884 arr[num++] = 0x22;
885 arr[num++] = 0x20;
886 arr[num++] = (port_b >> 24);
887 arr[num++] = (port_b >> 16) & 0xff;
888 arr[num++] = (port_b >> 8) & 0xff;
889 arr[num++] = port_b & 0xff;
890
891 return num;
892}
893
894
895static unsigned char vpd89_data[] = {
896/* from 4th byte */ 0,0,0,0,
897'l','i','n','u','x',' ',' ',' ',
898'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
899'1','2','3','4',
9000x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
9010xec,0,0,0,
9020x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
9030,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
9040x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
9050x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
9060x53,0x41,
9070x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
9080x20,0x20,
9090x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
9100x10,0x80,
9110,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
9120x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
9130x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
9140,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
9150x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
9160x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
9170,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
9180,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9190,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9210x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
9220,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
9230xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
9240,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,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,0,0,
9350,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9360,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
937};
938
939static int inquiry_evpd_89(unsigned char * arr)
940{
941 memcpy(arr, vpd89_data, sizeof(vpd89_data));
942 return sizeof(vpd89_data);
943}
944
945
946static unsigned char vpdb0_data[] = {
947 /* from 4th byte */ 0,0,0,4,
948 0,0,0x4,0,
949 0,0,0,64,
950};
951
952static int inquiry_evpd_b0(unsigned char * arr)
953{
954 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
955 if (sdebug_store_sectors > 0x400) {
956 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
957 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
958 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
959 arr[7] = sdebug_store_sectors & 0xff;
960 }
961 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962}
963
964
965#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400966#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967
968static int resp_inquiry(struct scsi_cmnd * scp, int target,
969 struct sdebug_dev_info * devip)
970{
971 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200972 unsigned char * arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 unsigned char *cmd = (unsigned char *)scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200974 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975
976 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500977 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
978 if (! arr)
979 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400980 if (devip->wlun)
981 pq_pdt = 0x1e; /* present, wlun */
982 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
983 pq_pdt = 0x7f; /* not present, no device type */
984 else
985 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 arr[0] = pq_pdt;
987 if (0x2 & cmd[1]) { /* CMDDT bit set */
988 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
989 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200990 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 return check_condition_result;
992 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200993 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400994 char lu_id_str[6];
995 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200997 port_group_id = (((host_no + 1) & 0x7f) << 8) +
998 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -0400999 if (0 == scsi_debug_vpd_use_hostno)
1000 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001001 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
1002 (devip->target * 1000) + devip->lun);
1003 target_dev_id = ((host_no + 1) * 2000) +
1004 (devip->target * 1000) - 3;
1005 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001007 arr[1] = cmd[2]; /*sanity */
1008 n = 4;
1009 arr[n++] = 0x0; /* this page */
1010 arr[n++] = 0x80; /* unit serial number */
1011 arr[n++] = 0x83; /* device identification */
1012 arr[n++] = 0x84; /* software interface ident. */
1013 arr[n++] = 0x85; /* management network addresses */
1014 arr[n++] = 0x86; /* extended inquiry */
1015 arr[n++] = 0x87; /* mode page policy */
1016 arr[n++] = 0x88; /* SCSI ports */
1017 arr[n++] = 0x89; /* ATA information */
1018 arr[n++] = 0xb0; /* Block limits (SBC) */
1019 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001021 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001023 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001025 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001026 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
1027 target_dev_id, lu_id_num,
1028 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001029 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1030 arr[1] = cmd[2]; /*sanity */
1031 arr[3] = inquiry_evpd_84(&arr[4]);
1032 } else if (0x85 == cmd[2]) { /* Management network addresses */
1033 arr[1] = cmd[2]; /*sanity */
1034 arr[3] = inquiry_evpd_85(&arr[4]);
1035 } else if (0x86 == cmd[2]) { /* extended inquiry */
1036 arr[1] = cmd[2]; /*sanity */
1037 arr[3] = 0x3c; /* number of following entries */
1038 arr[4] = 0x0; /* no protection stuff */
1039 arr[5] = 0x7; /* head of q, ordered + simple q's */
1040 } else if (0x87 == cmd[2]) { /* mode page policy */
1041 arr[1] = cmd[2]; /*sanity */
1042 arr[3] = 0x8; /* number of following entries */
1043 arr[4] = 0x2; /* disconnect-reconnect mp */
1044 arr[6] = 0x80; /* mlus, shared */
1045 arr[8] = 0x18; /* protocol specific lu */
1046 arr[10] = 0x82; /* mlus, per initiator port */
1047 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1048 arr[1] = cmd[2]; /*sanity */
1049 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
1050 } else if (0x89 == cmd[2]) { /* ATA information */
1051 arr[1] = cmd[2]; /*sanity */
1052 n = inquiry_evpd_89(&arr[4]);
1053 arr[2] = (n >> 8);
1054 arr[3] = (n & 0xff);
1055 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
1056 arr[1] = cmd[2]; /*sanity */
1057 arr[3] = inquiry_evpd_b0(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 } else {
1059 /* Illegal request, invalid field in cdb */
1060 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1061 INVALID_FIELD_IN_CDB, 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001062 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 return check_condition_result;
1064 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001065 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001066 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001067 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001068 kfree(arr);
1069 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 }
1071 /* drops through here for a standard inquiry */
1072 arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
1073 arr[2] = scsi_debug_scsi_level;
1074 arr[3] = 2; /* response_data_format==2 */
1075 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001076 if (0 == scsi_debug_vpd_use_hostno)
1077 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001078 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001080 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 memcpy(&arr[8], inq_vendor_id, 8);
1082 memcpy(&arr[16], inq_product_id, 16);
1083 memcpy(&arr[32], inq_product_rev, 4);
1084 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001085 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
1086 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
1087 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001089 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001091 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001093 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001094 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001096 kfree(arr);
1097 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098}
1099
1100static int resp_requests(struct scsi_cmnd * scp,
1101 struct sdebug_dev_info * devip)
1102{
1103 unsigned char * sbuff;
1104 unsigned char *cmd = (unsigned char *)scp->cmnd;
1105 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001106 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 int len = 18;
1108
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001109 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001111 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
1112 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001114 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1115 if (want_dsense) {
1116 arr[0] = 0x72;
1117 arr[1] = 0x0; /* NO_SENSE in sense_key */
1118 arr[2] = THRESHOLD_EXCEEDED;
1119 arr[3] = 0xff; /* TEST set and MRIE==6 */
1120 } else {
1121 arr[0] = 0x70;
1122 arr[2] = 0x0; /* NO_SENSE in sense_key */
1123 arr[7] = 0xa; /* 18 byte sense buffer */
1124 arr[12] = THRESHOLD_EXCEEDED;
1125 arr[13] = 0xff; /* TEST set and MRIE==6 */
1126 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001127 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001129 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
1130 /* DESC bit set and sense_buff in fixed format */
1131 memset(arr, 0, sizeof(arr));
1132 arr[0] = 0x72;
1133 arr[1] = sbuff[2]; /* sense key */
1134 arr[2] = sbuff[12]; /* asc */
1135 arr[3] = sbuff[13]; /* ascq */
1136 len = 8;
1137 }
1138 }
1139 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 return fill_from_dev_buffer(scp, arr, len);
1141}
1142
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001143static int resp_start_stop(struct scsi_cmnd * scp,
1144 struct sdebug_dev_info * devip)
1145{
1146 unsigned char *cmd = (unsigned char *)scp->cmnd;
1147 int power_cond, errsts, start;
1148
1149 if ((errsts = check_readiness(scp, 1, devip)))
1150 return errsts;
1151 power_cond = (cmd[4] & 0xf0) >> 4;
1152 if (power_cond) {
1153 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1154 0);
1155 return check_condition_result;
1156 }
1157 start = cmd[4] & 1;
1158 if (start == devip->stopped)
1159 devip->stopped = !start;
1160 return 0;
1161}
1162
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163#define SDEBUG_READCAP_ARR_SZ 8
1164static int resp_readcap(struct scsi_cmnd * scp,
1165 struct sdebug_dev_info * devip)
1166{
1167 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001168 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 int errsts;
1170
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001171 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001173 /* following just in case virtual_gb changed */
1174 if (scsi_debug_virtual_gb > 0) {
1175 sdebug_capacity = 2048 * 1024;
1176 sdebug_capacity *= scsi_debug_virtual_gb;
1177 } else
1178 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001180 if (sdebug_capacity < 0xffffffff) {
1181 capac = (unsigned int)sdebug_capacity - 1;
1182 arr[0] = (capac >> 24);
1183 arr[1] = (capac >> 16) & 0xff;
1184 arr[2] = (capac >> 8) & 0xff;
1185 arr[3] = capac & 0xff;
1186 } else {
1187 arr[0] = 0xff;
1188 arr[1] = 0xff;
1189 arr[2] = 0xff;
1190 arr[3] = 0xff;
1191 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1193 arr[7] = SECT_SIZE_PER(target) & 0xff;
1194 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1195}
1196
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001197#define SDEBUG_READCAP16_ARR_SZ 32
1198static int resp_readcap16(struct scsi_cmnd * scp,
1199 struct sdebug_dev_info * devip)
1200{
1201 unsigned char *cmd = (unsigned char *)scp->cmnd;
1202 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1203 unsigned long long capac;
1204 int errsts, k, alloc_len;
1205
1206 if ((errsts = check_readiness(scp, 1, devip)))
1207 return errsts;
1208 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1209 + cmd[13]);
1210 /* following just in case virtual_gb changed */
1211 if (scsi_debug_virtual_gb > 0) {
1212 sdebug_capacity = 2048 * 1024;
1213 sdebug_capacity *= scsi_debug_virtual_gb;
1214 } else
1215 sdebug_capacity = sdebug_store_sectors;
1216 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1217 capac = sdebug_capacity - 1;
1218 for (k = 0; k < 8; ++k, capac >>= 8)
1219 arr[7 - k] = capac & 0xff;
1220 arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff;
1221 arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff;
1222 arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1223 arr[11] = SECT_SIZE_PER(target) & 0xff;
1224 return fill_from_dev_buffer(scp, arr,
1225 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1226}
1227
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001228#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1229
1230static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1231 struct sdebug_dev_info * devip)
1232{
1233 unsigned char *cmd = (unsigned char *)scp->cmnd;
1234 unsigned char * arr;
1235 int host_no = devip->sdbg_host->shost->host_no;
1236 int n, ret, alen, rlen;
1237 int port_group_a, port_group_b, port_a, port_b;
1238
1239 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
1240 + cmd[9]);
1241
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001242 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1243 if (! arr)
1244 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001245 /*
1246 * EVPD page 0x88 states we have two ports, one
1247 * real and a fake port with no device connected.
1248 * So we create two port groups with one port each
1249 * and set the group with port B to unavailable.
1250 */
1251 port_a = 0x1; /* relative port A */
1252 port_b = 0x2; /* relative port B */
1253 port_group_a = (((host_no + 1) & 0x7f) << 8) +
1254 (devip->channel & 0x7f);
1255 port_group_b = (((host_no + 1) & 0x7f) << 8) +
1256 (devip->channel & 0x7f) + 0x80;
1257
1258 /*
1259 * The asymmetric access state is cycled according to the host_id.
1260 */
1261 n = 4;
1262 if (0 == scsi_debug_vpd_use_hostno) {
1263 arr[n++] = host_no % 3; /* Asymm access state */
1264 arr[n++] = 0x0F; /* claim: all states are supported */
1265 } else {
1266 arr[n++] = 0x0; /* Active/Optimized path */
1267 arr[n++] = 0x01; /* claim: only support active/optimized paths */
1268 }
1269 arr[n++] = (port_group_a >> 8) & 0xff;
1270 arr[n++] = port_group_a & 0xff;
1271 arr[n++] = 0; /* Reserved */
1272 arr[n++] = 0; /* Status code */
1273 arr[n++] = 0; /* Vendor unique */
1274 arr[n++] = 0x1; /* One port per group */
1275 arr[n++] = 0; /* Reserved */
1276 arr[n++] = 0; /* Reserved */
1277 arr[n++] = (port_a >> 8) & 0xff;
1278 arr[n++] = port_a & 0xff;
1279 arr[n++] = 3; /* Port unavailable */
1280 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1281 arr[n++] = (port_group_b >> 8) & 0xff;
1282 arr[n++] = port_group_b & 0xff;
1283 arr[n++] = 0; /* Reserved */
1284 arr[n++] = 0; /* Status code */
1285 arr[n++] = 0; /* Vendor unique */
1286 arr[n++] = 0x1; /* One port per group */
1287 arr[n++] = 0; /* Reserved */
1288 arr[n++] = 0; /* Reserved */
1289 arr[n++] = (port_b >> 8) & 0xff;
1290 arr[n++] = port_b & 0xff;
1291
1292 rlen = n - 4;
1293 arr[0] = (rlen >> 24) & 0xff;
1294 arr[1] = (rlen >> 16) & 0xff;
1295 arr[2] = (rlen >> 8) & 0xff;
1296 arr[3] = rlen & 0xff;
1297
1298 /*
1299 * Return the smallest value of either
1300 * - The allocated length
1301 * - The constructed command length
1302 * - The maximum array size
1303 */
1304 rlen = min(alen,n);
1305 ret = fill_from_dev_buffer(scp, arr,
1306 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1307 kfree(arr);
1308 return ret;
1309}
1310
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311/* <<Following mode page info copied from ST318451LW>> */
1312
1313static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1314{ /* Read-Write Error Recovery page for mode_sense */
1315 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1316 5, 0, 0xff, 0xff};
1317
1318 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1319 if (1 == pcontrol)
1320 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1321 return sizeof(err_recov_pg);
1322}
1323
1324static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1325{ /* Disconnect-Reconnect page for mode_sense */
1326 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1327 0, 0, 0, 0, 0, 0, 0, 0};
1328
1329 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1330 if (1 == pcontrol)
1331 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1332 return sizeof(disconnect_pg);
1333}
1334
1335static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1336{ /* Format device page for mode_sense */
1337 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1338 0, 0, 0, 0, 0, 0, 0, 0,
1339 0, 0, 0, 0, 0x40, 0, 0, 0};
1340
1341 memcpy(p, format_pg, sizeof(format_pg));
1342 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1343 p[11] = sdebug_sectors_per & 0xff;
1344 p[12] = (SECT_SIZE >> 8) & 0xff;
1345 p[13] = SECT_SIZE & 0xff;
1346 if (DEV_REMOVEABLE(target))
1347 p[20] |= 0x20; /* should agree with INQUIRY */
1348 if (1 == pcontrol)
1349 memset(p + 2, 0, sizeof(format_pg) - 2);
1350 return sizeof(format_pg);
1351}
1352
1353static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1354{ /* Caching page for mode_sense */
1355 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1356 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1357
1358 memcpy(p, caching_pg, sizeof(caching_pg));
1359 if (1 == pcontrol)
1360 memset(p + 2, 0, sizeof(caching_pg) - 2);
1361 return sizeof(caching_pg);
1362}
1363
1364static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1365{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001366 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1367 0, 0, 0, 0};
1368 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 0, 0, 0x2, 0x4b};
1370
1371 if (scsi_debug_dsense)
1372 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001373 else
1374 ctrl_m_pg[2] &= ~0x4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1376 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001377 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1378 else if (2 == pcontrol)
1379 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 return sizeof(ctrl_m_pg);
1381}
1382
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001383
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1385{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001386 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1387 0, 0, 0x0, 0x0};
1388 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1389 0, 0, 0x0, 0x0};
1390
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1392 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001393 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1394 else if (2 == pcontrol)
1395 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 return sizeof(iec_m_pg);
1397}
1398
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001399static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1400{ /* SAS SSP mode page - short format for mode_sense */
1401 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1402 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1403
1404 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1405 if (1 == pcontrol)
1406 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1407 return sizeof(sas_sf_m_pg);
1408}
1409
1410
1411static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1412 int target_dev_id)
1413{ /* SAS phy control and discover mode page for mode_sense */
1414 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1415 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1416 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1417 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1418 0x2, 0, 0, 0, 0, 0, 0, 0,
1419 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1420 0, 0, 0, 0, 0, 0, 0, 0,
1421 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1422 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1423 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1424 0x3, 0, 0, 0, 0, 0, 0, 0,
1425 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1426 0, 0, 0, 0, 0, 0, 0, 0,
1427 };
1428 int port_a, port_b;
1429
1430 port_a = target_dev_id + 1;
1431 port_b = port_a + 1;
1432 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1433 p[20] = (port_a >> 24);
1434 p[21] = (port_a >> 16) & 0xff;
1435 p[22] = (port_a >> 8) & 0xff;
1436 p[23] = port_a & 0xff;
1437 p[48 + 20] = (port_b >> 24);
1438 p[48 + 21] = (port_b >> 16) & 0xff;
1439 p[48 + 22] = (port_b >> 8) & 0xff;
1440 p[48 + 23] = port_b & 0xff;
1441 if (1 == pcontrol)
1442 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1443 return sizeof(sas_pcd_m_pg);
1444}
1445
1446static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1447{ /* SAS SSP shared protocol specific port mode subpage */
1448 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1449 0, 0, 0, 0, 0, 0, 0, 0,
1450 };
1451
1452 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1453 if (1 == pcontrol)
1454 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1455 return sizeof(sas_sha_m_pg);
1456}
1457
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458#define SDEBUG_MAX_MSENSE_SZ 256
1459
1460static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1461 struct sdebug_dev_info * devip)
1462{
Douglas Gilbert23183912006-09-16 20:30:47 -04001463 unsigned char dbd, llbaa;
1464 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001466 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 unsigned char * ap;
1468 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1469 unsigned char *cmd = (unsigned char *)scp->cmnd;
1470
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001471 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001473 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 pcontrol = (cmd[2] & 0xc0) >> 6;
1475 pcode = cmd[2] & 0x3f;
1476 subpcode = cmd[3];
1477 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001478 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1479 if ((0 == scsi_debug_ptype) && (0 == dbd))
1480 bd_len = llbaa ? 16 : 8;
1481 else
1482 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1484 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1485 if (0x3 == pcontrol) { /* Saving values not supported */
1486 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1487 0);
1488 return check_condition_result;
1489 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001490 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1491 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001492 /* set DPOFUA bit for disks */
1493 if (0 == scsi_debug_ptype)
1494 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1495 else
1496 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 if (msense_6) {
1498 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001499 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 offset = 4;
1501 } else {
1502 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001503 if (16 == bd_len)
1504 arr[4] = 0x1; /* set LONGLBA bit */
1505 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 offset = 8;
1507 }
1508 ap = arr + offset;
Douglas Gilbert23183912006-09-16 20:30:47 -04001509 if ((bd_len > 0) && (0 == sdebug_capacity)) {
1510 if (scsi_debug_virtual_gb > 0) {
1511 sdebug_capacity = 2048 * 1024;
1512 sdebug_capacity *= scsi_debug_virtual_gb;
1513 } else
1514 sdebug_capacity = sdebug_store_sectors;
1515 }
1516 if (8 == bd_len) {
1517 if (sdebug_capacity > 0xfffffffe) {
1518 ap[0] = 0xff;
1519 ap[1] = 0xff;
1520 ap[2] = 0xff;
1521 ap[3] = 0xff;
1522 } else {
1523 ap[0] = (sdebug_capacity >> 24) & 0xff;
1524 ap[1] = (sdebug_capacity >> 16) & 0xff;
1525 ap[2] = (sdebug_capacity >> 8) & 0xff;
1526 ap[3] = sdebug_capacity & 0xff;
1527 }
1528 ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1529 ap[7] = SECT_SIZE_PER(target) & 0xff;
1530 offset += bd_len;
1531 ap = arr + offset;
1532 } else if (16 == bd_len) {
1533 unsigned long long capac = sdebug_capacity;
1534
1535 for (k = 0; k < 8; ++k, capac >>= 8)
1536 ap[7 - k] = capac & 0xff;
1537 ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff;
1538 ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff;
1539 ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1540 ap[15] = SECT_SIZE_PER(target) & 0xff;
1541 offset += bd_len;
1542 ap = arr + offset;
1543 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001545 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1546 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1548 0);
1549 return check_condition_result;
1550 }
1551 switch (pcode) {
1552 case 0x1: /* Read-Write error recovery page, direct access */
1553 len = resp_err_recov_pg(ap, pcontrol, target);
1554 offset += len;
1555 break;
1556 case 0x2: /* Disconnect-Reconnect page, all devices */
1557 len = resp_disconnect_pg(ap, pcontrol, target);
1558 offset += len;
1559 break;
1560 case 0x3: /* Format device page, direct access */
1561 len = resp_format_pg(ap, pcontrol, target);
1562 offset += len;
1563 break;
1564 case 0x8: /* Caching page, direct access */
1565 len = resp_caching_pg(ap, pcontrol, target);
1566 offset += len;
1567 break;
1568 case 0xa: /* Control Mode page, all devices */
1569 len = resp_ctrl_m_pg(ap, pcontrol, target);
1570 offset += len;
1571 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001572 case 0x19: /* if spc==1 then sas phy, control+discover */
1573 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1574 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1575 INVALID_FIELD_IN_CDB, 0);
1576 return check_condition_result;
1577 }
1578 len = 0;
1579 if ((0x0 == subpcode) || (0xff == subpcode))
1580 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1581 if ((0x1 == subpcode) || (0xff == subpcode))
1582 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1583 target_dev_id);
1584 if ((0x2 == subpcode) || (0xff == subpcode))
1585 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1586 offset += len;
1587 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 case 0x1c: /* Informational Exceptions Mode page, all devices */
1589 len = resp_iec_m_pg(ap, pcontrol, target);
1590 offset += len;
1591 break;
1592 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001593 if ((0 == subpcode) || (0xff == subpcode)) {
1594 len = resp_err_recov_pg(ap, pcontrol, target);
1595 len += resp_disconnect_pg(ap + len, pcontrol, target);
1596 len += resp_format_pg(ap + len, pcontrol, target);
1597 len += resp_caching_pg(ap + len, pcontrol, target);
1598 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1599 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1600 if (0xff == subpcode) {
1601 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1602 target, target_dev_id);
1603 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1604 }
1605 len += resp_iec_m_pg(ap + len, pcontrol, target);
1606 } else {
1607 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1608 INVALID_FIELD_IN_CDB, 0);
1609 return check_condition_result;
1610 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 offset += len;
1612 break;
1613 default:
1614 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1615 0);
1616 return check_condition_result;
1617 }
1618 if (msense_6)
1619 arr[0] = offset - 1;
1620 else {
1621 arr[0] = ((offset - 2) >> 8) & 0xff;
1622 arr[1] = (offset - 2) & 0xff;
1623 }
1624 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1625}
1626
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001627#define SDEBUG_MAX_MSELECT_SZ 512
1628
1629static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1630 struct sdebug_dev_info * devip)
1631{
1632 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1633 int param_len, res, errsts, mpage;
1634 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1635 unsigned char *cmd = (unsigned char *)scp->cmnd;
1636
1637 if ((errsts = check_readiness(scp, 1, devip)))
1638 return errsts;
1639 memset(arr, 0, sizeof(arr));
1640 pf = cmd[1] & 0x10;
1641 sp = cmd[1] & 0x1;
1642 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1643 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1644 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1645 INVALID_FIELD_IN_CDB, 0);
1646 return check_condition_result;
1647 }
1648 res = fetch_to_dev_buffer(scp, arr, param_len);
1649 if (-1 == res)
1650 return (DID_ERROR << 16);
1651 else if ((res < param_len) &&
1652 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1653 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1654 " IO sent=%d bytes\n", param_len, res);
1655 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1656 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001657 if (md_len > 2) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001658 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1659 INVALID_FIELD_IN_PARAM_LIST, 0);
1660 return check_condition_result;
1661 }
1662 off = bd_len + (mselect6 ? 4 : 8);
1663 mpage = arr[off] & 0x3f;
1664 ps = !!(arr[off] & 0x80);
1665 if (ps) {
1666 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1667 INVALID_FIELD_IN_PARAM_LIST, 0);
1668 return check_condition_result;
1669 }
1670 spf = !!(arr[off] & 0x40);
1671 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1672 (arr[off + 1] + 2);
1673 if ((pg_len + off) > param_len) {
1674 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1675 PARAMETER_LIST_LENGTH_ERR, 0);
1676 return check_condition_result;
1677 }
1678 switch (mpage) {
1679 case 0xa: /* Control Mode page */
1680 if (ctrl_m_pg[1] == arr[off + 1]) {
1681 memcpy(ctrl_m_pg + 2, arr + off + 2,
1682 sizeof(ctrl_m_pg) - 2);
1683 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1684 return 0;
1685 }
1686 break;
1687 case 0x1c: /* Informational Exceptions Mode page */
1688 if (iec_m_pg[1] == arr[off + 1]) {
1689 memcpy(iec_m_pg + 2, arr + off + 2,
1690 sizeof(iec_m_pg) - 2);
1691 return 0;
1692 }
1693 break;
1694 default:
1695 break;
1696 }
1697 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1698 INVALID_FIELD_IN_PARAM_LIST, 0);
1699 return check_condition_result;
1700}
1701
1702static int resp_temp_l_pg(unsigned char * arr)
1703{
1704 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1705 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1706 };
1707
1708 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1709 return sizeof(temp_l_pg);
1710}
1711
1712static int resp_ie_l_pg(unsigned char * arr)
1713{
1714 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1715 };
1716
1717 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1718 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1719 arr[4] = THRESHOLD_EXCEEDED;
1720 arr[5] = 0xff;
1721 }
1722 return sizeof(ie_l_pg);
1723}
1724
1725#define SDEBUG_MAX_LSENSE_SZ 512
1726
1727static int resp_log_sense(struct scsi_cmnd * scp,
1728 struct sdebug_dev_info * devip)
1729{
Douglas Gilbert23183912006-09-16 20:30:47 -04001730 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001731 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1732 unsigned char *cmd = (unsigned char *)scp->cmnd;
1733
1734 if ((errsts = check_readiness(scp, 1, devip)))
1735 return errsts;
1736 memset(arr, 0, sizeof(arr));
1737 ppc = cmd[1] & 0x2;
1738 sp = cmd[1] & 0x1;
1739 if (ppc || sp) {
1740 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1741 INVALID_FIELD_IN_CDB, 0);
1742 return check_condition_result;
1743 }
1744 pcontrol = (cmd[2] & 0xc0) >> 6;
1745 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001746 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001747 alloc_len = (cmd[7] << 8) + cmd[8];
1748 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001749 if (0 == subpcode) {
1750 switch (pcode) {
1751 case 0x0: /* Supported log pages log page */
1752 n = 4;
1753 arr[n++] = 0x0; /* this page */
1754 arr[n++] = 0xd; /* Temperature */
1755 arr[n++] = 0x2f; /* Informational exceptions */
1756 arr[3] = n - 4;
1757 break;
1758 case 0xd: /* Temperature log page */
1759 arr[3] = resp_temp_l_pg(arr + 4);
1760 break;
1761 case 0x2f: /* Informational exceptions log page */
1762 arr[3] = resp_ie_l_pg(arr + 4);
1763 break;
1764 default:
1765 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1766 INVALID_FIELD_IN_CDB, 0);
1767 return check_condition_result;
1768 }
1769 } else if (0xff == subpcode) {
1770 arr[0] |= 0x40;
1771 arr[1] = subpcode;
1772 switch (pcode) {
1773 case 0x0: /* Supported log pages and subpages log page */
1774 n = 4;
1775 arr[n++] = 0x0;
1776 arr[n++] = 0x0; /* 0,0 page */
1777 arr[n++] = 0x0;
1778 arr[n++] = 0xff; /* this page */
1779 arr[n++] = 0xd;
1780 arr[n++] = 0x0; /* Temperature */
1781 arr[n++] = 0x2f;
1782 arr[n++] = 0x0; /* Informational exceptions */
1783 arr[3] = n - 4;
1784 break;
1785 case 0xd: /* Temperature subpages */
1786 n = 4;
1787 arr[n++] = 0xd;
1788 arr[n++] = 0x0; /* Temperature */
1789 arr[3] = n - 4;
1790 break;
1791 case 0x2f: /* Informational exceptions subpages */
1792 n = 4;
1793 arr[n++] = 0x2f;
1794 arr[n++] = 0x0; /* Informational exceptions */
1795 arr[3] = n - 4;
1796 break;
1797 default:
1798 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1799 INVALID_FIELD_IN_CDB, 0);
1800 return check_condition_result;
1801 }
1802 } else {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001803 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1804 INVALID_FIELD_IN_CDB, 0);
1805 return check_condition_result;
1806 }
1807 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1808 return fill_from_dev_buffer(scp, arr,
1809 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1810}
1811
1812static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
1813 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814{
1815 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001816 unsigned int block, from_bottom;
1817 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 int ret;
1819
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001820 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1822 0);
1823 return check_condition_result;
1824 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001825 /* transfer length excessive (tie in to block limits VPD page) */
1826 if (num > sdebug_store_sectors) {
1827 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1828 0);
1829 return check_condition_result;
1830 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001832 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1833 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1834 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1836 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001837 /* set info field and valid bit for fixed descriptor */
1838 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1839 devip->sense_buff[0] |= 0x80; /* Valid bit */
1840 ret = OPT_MEDIUM_ERR_ADDR;
1841 devip->sense_buff[3] = (ret >> 24) & 0xff;
1842 devip->sense_buff[4] = (ret >> 16) & 0xff;
1843 devip->sense_buff[5] = (ret >> 8) & 0xff;
1844 devip->sense_buff[6] = ret & 0xff;
1845 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 return check_condition_result;
1847 }
1848 read_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001849 if ((lba + num) <= sdebug_store_sectors)
1850 ret = fill_from_dev_buffer(SCpnt,
1851 fake_storep + (lba * SECT_SIZE),
1852 num * SECT_SIZE);
1853 else {
1854 /* modulo when one arg is 64 bits needs do_div() */
1855 u = lba;
1856 block = do_div(u, sdebug_store_sectors);
1857 from_bottom = 0;
1858 if ((block + num) > sdebug_store_sectors)
1859 from_bottom = (block + num) - sdebug_store_sectors;
1860 ret = fill_from_dev_buffer(SCpnt,
1861 fake_storep + (block * SECT_SIZE),
1862 (num - from_bottom) * SECT_SIZE);
1863 if ((0 == ret) && (from_bottom > 0))
1864 ret = fill_from_dev_buffer(SCpnt, fake_storep,
1865 from_bottom * SECT_SIZE);
1866 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 read_unlock_irqrestore(&atomic_rw, iflags);
1868 return ret;
1869}
1870
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001871static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
1872 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873{
1874 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001875 unsigned int block, to_bottom;
1876 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 int res;
1878
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001879 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1881 0);
1882 return check_condition_result;
1883 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001884 /* transfer length excessive (tie in to block limits VPD page) */
1885 if (num > sdebug_store_sectors) {
1886 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1887 0);
1888 return check_condition_result;
1889 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890
1891 write_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001892 if ((lba + num) <= sdebug_store_sectors)
1893 res = fetch_to_dev_buffer(SCpnt,
1894 fake_storep + (lba * SECT_SIZE),
1895 num * SECT_SIZE);
1896 else {
1897 /* modulo when one arg is 64 bits needs do_div() */
1898 u = lba;
1899 block = do_div(u, sdebug_store_sectors);
1900 to_bottom = 0;
1901 if ((block + num) > sdebug_store_sectors)
1902 to_bottom = (block + num) - sdebug_store_sectors;
1903 res = fetch_to_dev_buffer(SCpnt,
1904 fake_storep + (block * SECT_SIZE),
1905 (num - to_bottom) * SECT_SIZE);
1906 if ((0 == res) && (to_bottom > 0))
1907 res = fetch_to_dev_buffer(SCpnt, fake_storep,
1908 to_bottom * SECT_SIZE);
1909 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 write_unlock_irqrestore(&atomic_rw, iflags);
1911 if (-1 == res)
1912 return (DID_ERROR << 16);
1913 else if ((res < (num * SECT_SIZE)) &&
1914 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001915 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 " IO sent=%d bytes\n", num * SECT_SIZE, res);
1917 return 0;
1918}
1919
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001920#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921
1922static int resp_report_luns(struct scsi_cmnd * scp,
1923 struct sdebug_dev_info * devip)
1924{
1925 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001926 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 unsigned char *cmd = (unsigned char *)scp->cmnd;
1928 int select_report = (int)cmd[2];
1929 struct scsi_lun *one_lun;
1930 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001931 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932
1933 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001934 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1936 0);
1937 return check_condition_result;
1938 }
1939 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
1940 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
1941 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001942 if (1 == select_report)
1943 lun_cnt = 0;
1944 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
1945 --lun_cnt;
1946 wlun = (select_report > 0) ? 1 : 0;
1947 num = lun_cnt + wlun;
1948 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
1949 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
1950 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
1951 sizeof(struct scsi_lun)), num);
1952 if (n < num) {
1953 wlun = 0;
1954 lun_cnt = n;
1955 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001957 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
1958 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
1959 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
1960 i++, lun++) {
1961 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 if (upper)
1963 one_lun[i].scsi_lun[0] =
1964 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001965 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001967 if (wlun) {
1968 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
1969 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
1970 i++;
1971 }
1972 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 return fill_from_dev_buffer(scp, arr,
1974 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
1975}
1976
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001977static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
1978 unsigned int num, struct sdebug_dev_info *devip)
1979{
1980 int i, j, ret = -1;
1981 unsigned char *kaddr, *buf;
1982 unsigned int offset;
1983 struct scatterlist *sg;
1984 struct scsi_data_buffer *sdb = scsi_in(scp);
1985
1986 /* better not to use temporary buffer. */
1987 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
1988 if (!buf)
1989 return ret;
1990
1991 offset = 0;
1992 scsi_for_each_sg(scp, sg, scsi_sg_count(scp), i) {
1993 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
1994 if (!kaddr)
1995 goto out;
1996
1997 memcpy(buf + offset, kaddr + sg->offset, sg->length);
1998 offset += sg->length;
1999 kunmap_atomic(kaddr, KM_USER0);
2000 }
2001
2002 offset = 0;
2003 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
2004 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
2005 if (!kaddr)
2006 goto out;
2007
2008 for (j = 0; j < sg->length; j++)
2009 *(kaddr + sg->offset + j) ^= *(buf + offset + j);
2010
2011 offset += sg->length;
2012 kunmap_atomic(kaddr, KM_USER0);
2013 }
2014 ret = 0;
2015out:
2016 kfree(buf);
2017
2018 return ret;
2019}
2020
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021/* When timer goes off this function is called. */
2022static void timer_intr_handler(unsigned long indx)
2023{
2024 struct sdebug_queued_cmd * sqcp;
2025 unsigned long iflags;
2026
2027 if (indx >= SCSI_DEBUG_CANQUEUE) {
2028 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
2029 "large\n");
2030 return;
2031 }
2032 spin_lock_irqsave(&queued_arr_lock, iflags);
2033 sqcp = &queued_arr[(int)indx];
2034 if (! sqcp->in_use) {
2035 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
2036 "interrupt\n");
2037 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2038 return;
2039 }
2040 sqcp->in_use = 0;
2041 if (sqcp->done_funct) {
2042 sqcp->a_cmnd->result = sqcp->scsi_result;
2043 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
2044 }
2045 sqcp->done_funct = NULL;
2046 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2047}
2048
2049static int scsi_debug_slave_alloc(struct scsi_device * sdp)
2050{
2051 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002052 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
2053 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002054 set_bit(QUEUE_FLAG_BIDI, &sdp->request_queue->queue_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 return 0;
2056}
2057
2058static int scsi_debug_slave_configure(struct scsi_device * sdp)
2059{
2060 struct sdebug_dev_info * devip;
2061
2062 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002063 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
2064 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
2066 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
2067 devip = devInfoReg(sdp);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002068 if (NULL == devip)
2069 return 1; /* no resources, will be marked offline */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 sdp->hostdata = devip;
2071 if (sdp->host->cmd_per_lun)
2072 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
2073 sdp->host->cmd_per_lun);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002074 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 return 0;
2076}
2077
2078static void scsi_debug_slave_destroy(struct scsi_device * sdp)
2079{
2080 struct sdebug_dev_info * devip =
2081 (struct sdebug_dev_info *)sdp->hostdata;
2082
2083 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002084 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
2085 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 if (devip) {
2087 /* make this slot avaliable for re-use */
2088 devip->used = 0;
2089 sdp->hostdata = NULL;
2090 }
2091}
2092
2093static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
2094{
2095 struct sdebug_host_info * sdbg_host;
2096 struct sdebug_dev_info * open_devip = NULL;
2097 struct sdebug_dev_info * devip =
2098 (struct sdebug_dev_info *)sdev->hostdata;
2099
2100 if (devip)
2101 return devip;
2102 sdbg_host = *(struct sdebug_host_info **) sdev->host->hostdata;
2103 if(! sdbg_host) {
2104 printk(KERN_ERR "Host info NULL\n");
2105 return NULL;
2106 }
2107 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
2108 if ((devip->used) && (devip->channel == sdev->channel) &&
2109 (devip->target == sdev->id) &&
2110 (devip->lun == sdev->lun))
2111 return devip;
2112 else {
2113 if ((!devip->used) && (!open_devip))
2114 open_devip = devip;
2115 }
2116 }
2117 if (NULL == open_devip) { /* try and make a new one */
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002118 open_devip = kzalloc(sizeof(*open_devip),GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 if (NULL == open_devip) {
2120 printk(KERN_ERR "%s: out of memory at line %d\n",
2121 __FUNCTION__, __LINE__);
2122 return NULL;
2123 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 open_devip->sdbg_host = sdbg_host;
2125 list_add_tail(&open_devip->dev_list,
2126 &sdbg_host->dev_info_list);
2127 }
2128 if (open_devip) {
2129 open_devip->channel = sdev->channel;
2130 open_devip->target = sdev->id;
2131 open_devip->lun = sdev->lun;
2132 open_devip->sdbg_host = sdbg_host;
2133 open_devip->reset = 1;
2134 open_devip->used = 1;
2135 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
2136 if (scsi_debug_dsense)
2137 open_devip->sense_buff[0] = 0x72;
2138 else {
2139 open_devip->sense_buff[0] = 0x70;
2140 open_devip->sense_buff[7] = 0xa;
2141 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002142 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2143 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 return open_devip;
2145 }
2146 return NULL;
2147}
2148
2149static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
2150 int asc, int asq)
2151{
2152 unsigned char * sbuff;
2153
2154 sbuff = devip->sense_buff;
2155 memset(sbuff, 0, SDEBUG_SENSE_LEN);
2156 if (scsi_debug_dsense) {
2157 sbuff[0] = 0x72; /* descriptor, current */
2158 sbuff[1] = key;
2159 sbuff[2] = asc;
2160 sbuff[3] = asq;
2161 } else {
2162 sbuff[0] = 0x70; /* fixed, current */
2163 sbuff[2] = key;
2164 sbuff[7] = 0xa; /* implies 18 byte sense buffer */
2165 sbuff[12] = asc;
2166 sbuff[13] = asq;
2167 }
2168 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2169 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
2170 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
2171}
2172
2173static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
2174{
2175 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2176 printk(KERN_INFO "scsi_debug: abort\n");
2177 ++num_aborts;
2178 stop_queued_cmnd(SCpnt);
2179 return SUCCESS;
2180}
2181
2182static int scsi_debug_biosparam(struct scsi_device *sdev,
2183 struct block_device * bdev, sector_t capacity, int *info)
2184{
2185 int res;
2186 unsigned char *buf;
2187
2188 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2189 printk(KERN_INFO "scsi_debug: biosparam\n");
2190 buf = scsi_bios_ptable(bdev);
2191 if (buf) {
2192 res = scsi_partsize(buf, capacity,
2193 &info[2], &info[0], &info[1]);
2194 kfree(buf);
2195 if (! res)
2196 return res;
2197 }
2198 info[0] = sdebug_heads;
2199 info[1] = sdebug_sectors_per;
2200 info[2] = sdebug_cylinders_per;
2201 return 0;
2202}
2203
2204static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
2205{
2206 struct sdebug_dev_info * devip;
2207
2208 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2209 printk(KERN_INFO "scsi_debug: device_reset\n");
2210 ++num_dev_resets;
2211 if (SCpnt) {
2212 devip = devInfoReg(SCpnt->device);
2213 if (devip)
2214 devip->reset = 1;
2215 }
2216 return SUCCESS;
2217}
2218
2219static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
2220{
2221 struct sdebug_host_info *sdbg_host;
2222 struct sdebug_dev_info * dev_info;
2223 struct scsi_device * sdp;
2224 struct Scsi_Host * hp;
2225
2226 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2227 printk(KERN_INFO "scsi_debug: bus_reset\n");
2228 ++num_bus_resets;
2229 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
2230 sdbg_host = *(struct sdebug_host_info **) hp->hostdata;
2231 if (sdbg_host) {
2232 list_for_each_entry(dev_info,
2233 &sdbg_host->dev_info_list,
2234 dev_list)
2235 dev_info->reset = 1;
2236 }
2237 }
2238 return SUCCESS;
2239}
2240
2241static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
2242{
2243 struct sdebug_host_info * sdbg_host;
2244 struct sdebug_dev_info * dev_info;
2245
2246 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2247 printk(KERN_INFO "scsi_debug: host_reset\n");
2248 ++num_host_resets;
2249 spin_lock(&sdebug_host_list_lock);
2250 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
2251 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
2252 dev_list)
2253 dev_info->reset = 1;
2254 }
2255 spin_unlock(&sdebug_host_list_lock);
2256 stop_all_queued();
2257 return SUCCESS;
2258}
2259
2260/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
2261static int stop_queued_cmnd(struct scsi_cmnd * cmnd)
2262{
2263 unsigned long iflags;
2264 int k;
2265 struct sdebug_queued_cmd * sqcp;
2266
2267 spin_lock_irqsave(&queued_arr_lock, iflags);
2268 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2269 sqcp = &queued_arr[k];
2270 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
2271 del_timer_sync(&sqcp->cmnd_timer);
2272 sqcp->in_use = 0;
2273 sqcp->a_cmnd = NULL;
2274 break;
2275 }
2276 }
2277 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2278 return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
2279}
2280
2281/* Deletes (stops) timers of all queued commands */
2282static void stop_all_queued(void)
2283{
2284 unsigned long iflags;
2285 int k;
2286 struct sdebug_queued_cmd * sqcp;
2287
2288 spin_lock_irqsave(&queued_arr_lock, iflags);
2289 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2290 sqcp = &queued_arr[k];
2291 if (sqcp->in_use && sqcp->a_cmnd) {
2292 del_timer_sync(&sqcp->cmnd_timer);
2293 sqcp->in_use = 0;
2294 sqcp->a_cmnd = NULL;
2295 }
2296 }
2297 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2298}
2299
2300/* Initializes timers in queued array */
2301static void __init init_all_queued(void)
2302{
2303 unsigned long iflags;
2304 int k;
2305 struct sdebug_queued_cmd * sqcp;
2306
2307 spin_lock_irqsave(&queued_arr_lock, iflags);
2308 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2309 sqcp = &queued_arr[k];
2310 init_timer(&sqcp->cmnd_timer);
2311 sqcp->in_use = 0;
2312 sqcp->a_cmnd = NULL;
2313 }
2314 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2315}
2316
2317static void __init sdebug_build_parts(unsigned char * ramp)
2318{
2319 struct partition * pp;
2320 int starts[SDEBUG_MAX_PARTS + 2];
2321 int sectors_per_part, num_sectors, k;
2322 int heads_by_sects, start_sec, end_sec;
2323
2324 /* assume partition table already zeroed */
2325 if ((scsi_debug_num_parts < 1) || (sdebug_store_size < 1048576))
2326 return;
2327 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
2328 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
2329 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
2330 "partitions to %d\n", SDEBUG_MAX_PARTS);
2331 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002332 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 sectors_per_part = (num_sectors - sdebug_sectors_per)
2334 / scsi_debug_num_parts;
2335 heads_by_sects = sdebug_heads * sdebug_sectors_per;
2336 starts[0] = sdebug_sectors_per;
2337 for (k = 1; k < scsi_debug_num_parts; ++k)
2338 starts[k] = ((k * sectors_per_part) / heads_by_sects)
2339 * heads_by_sects;
2340 starts[scsi_debug_num_parts] = num_sectors;
2341 starts[scsi_debug_num_parts + 1] = 0;
2342
2343 ramp[510] = 0x55; /* magic partition markings */
2344 ramp[511] = 0xAA;
2345 pp = (struct partition *)(ramp + 0x1be);
2346 for (k = 0; starts[k + 1]; ++k, ++pp) {
2347 start_sec = starts[k];
2348 end_sec = starts[k + 1] - 1;
2349 pp->boot_ind = 0;
2350
2351 pp->cyl = start_sec / heads_by_sects;
2352 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2353 / sdebug_sectors_per;
2354 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2355
2356 pp->end_cyl = end_sec / heads_by_sects;
2357 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2358 / sdebug_sectors_per;
2359 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2360
2361 pp->start_sect = start_sec;
2362 pp->nr_sects = end_sec - start_sec + 1;
2363 pp->sys_ind = 0x83; /* plain Linux partition */
2364 }
2365}
2366
2367static int schedule_resp(struct scsi_cmnd * cmnd,
2368 struct sdebug_dev_info * devip,
2369 done_funct_t done, int scsi_result, int delta_jiff)
2370{
2371 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2372 if (scsi_result) {
2373 struct scsi_device * sdp = cmnd->device;
2374
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002375 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2376 "non-zero result=0x%x\n", sdp->host->host_no,
2377 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378 }
2379 }
2380 if (cmnd && devip) {
2381 /* simulate autosense by this driver */
2382 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2383 memcpy(cmnd->sense_buffer, devip->sense_buff,
2384 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2385 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2386 }
2387 if (delta_jiff <= 0) {
2388 if (cmnd)
2389 cmnd->result = scsi_result;
2390 if (done)
2391 done(cmnd);
2392 return 0;
2393 } else {
2394 unsigned long iflags;
2395 int k;
2396 struct sdebug_queued_cmd * sqcp = NULL;
2397
2398 spin_lock_irqsave(&queued_arr_lock, iflags);
2399 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2400 sqcp = &queued_arr[k];
2401 if (! sqcp->in_use)
2402 break;
2403 }
2404 if (k >= SCSI_DEBUG_CANQUEUE) {
2405 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2406 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2407 return 1; /* report busy to mid level */
2408 }
2409 sqcp->in_use = 1;
2410 sqcp->a_cmnd = cmnd;
2411 sqcp->scsi_result = scsi_result;
2412 sqcp->done_funct = done;
2413 sqcp->cmnd_timer.function = timer_intr_handler;
2414 sqcp->cmnd_timer.data = k;
2415 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2416 add_timer(&sqcp->cmnd_timer);
2417 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2418 if (cmnd)
2419 cmnd->result = 0;
2420 return 0;
2421 }
2422}
2423
Douglas Gilbert23183912006-09-16 20:30:47 -04002424/* Note: The following macros create attribute files in the
2425 /sys/module/scsi_debug/parameters directory. Unfortunately this
2426 driver is unaware of a change and cannot trigger auxiliary actions
2427 as it can when the corresponding attribute in the
2428 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2429 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002430module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2431module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2432module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2433module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2434module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002435module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002436module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2437module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2438module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2439module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2440module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2441module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2442module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2443module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002444module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2445 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446
2447MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2448MODULE_DESCRIPTION("SCSI debug adapter driver");
2449MODULE_LICENSE("GPL");
2450MODULE_VERSION(SCSI_DEBUG_VERSION);
2451
2452MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2453MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002454MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2455MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07002456MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002457MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002458MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2459MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002461MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002462MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2464MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002465MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002466MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467
2468
2469static char sdebug_info[256];
2470
2471static const char * scsi_debug_info(struct Scsi_Host * shp)
2472{
2473 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2474 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2475 scsi_debug_version_date, scsi_debug_dev_size_mb,
2476 scsi_debug_opts);
2477 return sdebug_info;
2478}
2479
2480/* scsi_debug_proc_info
2481 * Used if the driver currently has no own support for /proc/scsi
2482 */
2483static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2484 int length, int inout)
2485{
2486 int len, pos, begin;
2487 int orig_length;
2488
2489 orig_length = length;
2490
2491 if (inout == 1) {
2492 char arr[16];
2493 int minLen = length > 15 ? 15 : length;
2494
2495 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2496 return -EACCES;
2497 memcpy(arr, buffer, minLen);
2498 arr[minLen] = '\0';
2499 if (1 != sscanf(arr, "%d", &pos))
2500 return -EINVAL;
2501 scsi_debug_opts = pos;
2502 if (scsi_debug_every_nth != 0)
2503 scsi_debug_cmnd_count = 0;
2504 return length;
2505 }
2506 begin = 0;
2507 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2508 "%s [%s]\n"
2509 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2510 "every_nth=%d(curr:%d)\n"
2511 "delay=%d, max_luns=%d, scsi_level=%d\n"
2512 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2513 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
2514 "host_resets=%d\n",
2515 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2516 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2517 scsi_debug_cmnd_count, scsi_debug_delay,
2518 scsi_debug_max_luns, scsi_debug_scsi_level,
2519 SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
2520 num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
2521 if (pos < offset) {
2522 len = 0;
2523 begin = pos;
2524 }
2525 *start = buffer + (offset - begin); /* Start of wanted data */
2526 len -= (offset - begin);
2527 if (len > length)
2528 len = length;
2529 return len;
2530}
2531
2532static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2533{
2534 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2535}
2536
2537static ssize_t sdebug_delay_store(struct device_driver * ddp,
2538 const char * buf, size_t count)
2539{
2540 int delay;
2541 char work[20];
2542
2543 if (1 == sscanf(buf, "%10s", work)) {
2544 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2545 scsi_debug_delay = delay;
2546 return count;
2547 }
2548 }
2549 return -EINVAL;
2550}
2551DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2552 sdebug_delay_store);
2553
2554static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2555{
2556 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2557}
2558
2559static ssize_t sdebug_opts_store(struct device_driver * ddp,
2560 const char * buf, size_t count)
2561{
2562 int opts;
2563 char work[20];
2564
2565 if (1 == sscanf(buf, "%10s", work)) {
2566 if (0 == strnicmp(work,"0x", 2)) {
2567 if (1 == sscanf(&work[2], "%x", &opts))
2568 goto opts_done;
2569 } else {
2570 if (1 == sscanf(work, "%d", &opts))
2571 goto opts_done;
2572 }
2573 }
2574 return -EINVAL;
2575opts_done:
2576 scsi_debug_opts = opts;
2577 scsi_debug_cmnd_count = 0;
2578 return count;
2579}
2580DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2581 sdebug_opts_store);
2582
2583static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2584{
2585 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2586}
2587static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2588 const char * buf, size_t count)
2589{
2590 int n;
2591
2592 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2593 scsi_debug_ptype = n;
2594 return count;
2595 }
2596 return -EINVAL;
2597}
2598DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2599
2600static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2601{
2602 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2603}
2604static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2605 const char * buf, size_t count)
2606{
2607 int n;
2608
2609 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2610 scsi_debug_dsense = n;
2611 return count;
2612 }
2613 return -EINVAL;
2614}
2615DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2616 sdebug_dsense_store);
2617
Douglas Gilbert23183912006-09-16 20:30:47 -04002618static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2619{
2620 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2621}
2622static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2623 const char * buf, size_t count)
2624{
2625 int n;
2626
2627 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2628 scsi_debug_fake_rw = n;
2629 return count;
2630 }
2631 return -EINVAL;
2632}
2633DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2634 sdebug_fake_rw_store);
2635
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002636static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2637{
2638 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2639}
2640static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2641 const char * buf, size_t count)
2642{
2643 int n;
2644
2645 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2646 scsi_debug_no_lun_0 = n;
2647 return count;
2648 }
2649 return -EINVAL;
2650}
2651DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2652 sdebug_no_lun_0_store);
2653
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2655{
2656 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2657}
2658static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2659 const char * buf, size_t count)
2660{
2661 int n;
2662
2663 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2664 scsi_debug_num_tgts = n;
2665 sdebug_max_tgts_luns();
2666 return count;
2667 }
2668 return -EINVAL;
2669}
2670DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2671 sdebug_num_tgts_store);
2672
2673static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2674{
2675 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2676}
2677DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2678
2679static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2680{
2681 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2682}
2683DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2684
2685static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2686{
2687 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2688}
2689static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2690 const char * buf, size_t count)
2691{
2692 int nth;
2693
2694 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2695 scsi_debug_every_nth = nth;
2696 scsi_debug_cmnd_count = 0;
2697 return count;
2698 }
2699 return -EINVAL;
2700}
2701DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2702 sdebug_every_nth_store);
2703
2704static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2705{
2706 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2707}
2708static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2709 const char * buf, size_t count)
2710{
2711 int n;
2712
2713 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2714 scsi_debug_max_luns = n;
2715 sdebug_max_tgts_luns();
2716 return count;
2717 }
2718 return -EINVAL;
2719}
2720DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2721 sdebug_max_luns_store);
2722
2723static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
2724{
2725 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
2726}
2727DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
2728
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002729static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2730{
2731 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2732}
2733static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2734 const char * buf, size_t count)
2735{
2736 int n;
2737
2738 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2739 scsi_debug_virtual_gb = n;
2740 if (scsi_debug_virtual_gb > 0) {
2741 sdebug_capacity = 2048 * 1024;
2742 sdebug_capacity *= scsi_debug_virtual_gb;
2743 } else
2744 sdebug_capacity = sdebug_store_sectors;
2745 return count;
2746 }
2747 return -EINVAL;
2748}
2749DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2750 sdebug_virtual_gb_store);
2751
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
2753{
2754 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
2755}
2756
2757static ssize_t sdebug_add_host_store(struct device_driver * ddp,
2758 const char * buf, size_t count)
2759{
2760 int delta_hosts;
2761 char work[20];
2762
2763 if (1 != sscanf(buf, "%10s", work))
2764 return -EINVAL;
2765 { /* temporary hack around sscanf() problem with -ve nums */
2766 int neg = 0;
2767
2768 if ('-' == *work)
2769 neg = 1;
2770 if (1 != sscanf(work + neg, "%d", &delta_hosts))
2771 return -EINVAL;
2772 if (neg)
2773 delta_hosts = -delta_hosts;
2774 }
2775 if (delta_hosts > 0) {
2776 do {
2777 sdebug_add_adapter();
2778 } while (--delta_hosts);
2779 } else if (delta_hosts < 0) {
2780 do {
2781 sdebug_remove_adapter();
2782 } while (++delta_hosts);
2783 }
2784 return count;
2785}
2786DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
2787 sdebug_add_host_store);
2788
Douglas Gilbert23183912006-09-16 20:30:47 -04002789static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
2790 char * buf)
2791{
2792 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
2793}
2794static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
2795 const char * buf, size_t count)
2796{
2797 int n;
2798
2799 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2800 scsi_debug_vpd_use_hostno = n;
2801 return count;
2802 }
2803 return -EINVAL;
2804}
2805DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
2806 sdebug_vpd_use_hostno_store);
2807
2808/* Note: The following function creates attribute files in the
2809 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
2810 files (over those found in the /sys/module/scsi_debug/parameters
2811 directory) is that auxiliary actions can be triggered when an attribute
2812 is changed. For example see: sdebug_add_host_store() above.
2813 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002814static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002816 int ret;
2817
2818 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2819 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
2820 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2821 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2822 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04002823 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002824 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002825 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002826 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002827 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002828 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
2829 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
2830 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04002831 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
2832 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002833 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834}
2835
2836static void do_remove_driverfs_files(void)
2837{
Douglas Gilbert23183912006-09-16 20:30:47 -04002838 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
2839 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
2841 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
2842 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002844 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
2845 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002847 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
2849 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2850 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2851 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
2852 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2853}
2854
2855static int __init scsi_debug_init(void)
2856{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002857 unsigned int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 int host_to_add;
2859 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002860 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861
2862 if (scsi_debug_dev_size_mb < 1)
2863 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002864 sdebug_store_size = (unsigned int)scsi_debug_dev_size_mb * 1048576;
2865 sdebug_store_sectors = sdebug_store_size / SECT_SIZE;
2866 if (scsi_debug_virtual_gb > 0) {
2867 sdebug_capacity = 2048 * 1024;
2868 sdebug_capacity *= scsi_debug_virtual_gb;
2869 } else
2870 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871
2872 /* play around with geometry, don't waste too much on track 0 */
2873 sdebug_heads = 8;
2874 sdebug_sectors_per = 32;
2875 if (scsi_debug_dev_size_mb >= 16)
2876 sdebug_heads = 32;
2877 else if (scsi_debug_dev_size_mb >= 256)
2878 sdebug_heads = 64;
2879 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2880 (sdebug_sectors_per * sdebug_heads);
2881 if (sdebug_cylinders_per >= 1024) {
2882 /* other LLDs do this; implies >= 1GB ram disk ... */
2883 sdebug_heads = 255;
2884 sdebug_sectors_per = 63;
2885 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2886 (sdebug_sectors_per * sdebug_heads);
2887 }
2888
2889 sz = sdebug_store_size;
2890 fake_storep = vmalloc(sz);
2891 if (NULL == fake_storep) {
2892 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
2893 return -ENOMEM;
2894 }
2895 memset(fake_storep, 0, sz);
2896 if (scsi_debug_num_parts > 0)
2897 sdebug_build_parts(fake_storep);
2898
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002899 ret = device_register(&pseudo_primary);
2900 if (ret < 0) {
2901 printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
2902 ret);
2903 goto free_vm;
2904 }
2905 ret = bus_register(&pseudo_lld_bus);
2906 if (ret < 0) {
2907 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
2908 ret);
2909 goto dev_unreg;
2910 }
2911 ret = driver_register(&sdebug_driverfs_driver);
2912 if (ret < 0) {
2913 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
2914 ret);
2915 goto bus_unreg;
2916 }
2917 ret = do_create_driverfs_files();
2918 if (ret < 0) {
2919 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
2920 ret);
2921 goto del_files;
2922 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002924 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925
Kristian Høgsbergb02b6bc2007-05-09 19:23:12 -04002926 sdebug_driver_template.proc_name = sdebug_proc_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927
2928 host_to_add = scsi_debug_add_host;
2929 scsi_debug_add_host = 0;
2930
2931 for (k = 0; k < host_to_add; k++) {
2932 if (sdebug_add_adapter()) {
2933 printk(KERN_ERR "scsi_debug_init: "
2934 "sdebug_add_adapter failed k=%d\n", k);
2935 break;
2936 }
2937 }
2938
2939 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
2940 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
2941 scsi_debug_add_host);
2942 }
2943 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002944
2945del_files:
2946 do_remove_driverfs_files();
2947 driver_unregister(&sdebug_driverfs_driver);
2948bus_unreg:
2949 bus_unregister(&pseudo_lld_bus);
2950dev_unreg:
2951 device_unregister(&pseudo_primary);
2952free_vm:
2953 vfree(fake_storep);
2954
2955 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956}
2957
2958static void __exit scsi_debug_exit(void)
2959{
2960 int k = scsi_debug_add_host;
2961
2962 stop_all_queued();
2963 for (; k; k--)
2964 sdebug_remove_adapter();
2965 do_remove_driverfs_files();
2966 driver_unregister(&sdebug_driverfs_driver);
2967 bus_unregister(&pseudo_lld_bus);
2968 device_unregister(&pseudo_primary);
2969
2970 vfree(fake_storep);
2971}
2972
2973device_initcall(scsi_debug_init);
2974module_exit(scsi_debug_exit);
2975
Adrian Bunk52c1da32005-06-23 22:05:33 -07002976static void pseudo_0_release(struct device * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977{
2978 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2979 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
2980}
2981
2982static struct device pseudo_primary = {
2983 .bus_id = "pseudo_0",
2984 .release = pseudo_0_release,
2985};
2986
2987static int pseudo_lld_bus_match(struct device *dev,
2988 struct device_driver *dev_driver)
2989{
2990 return 1;
2991}
2992
2993static struct bus_type pseudo_lld_bus = {
2994 .name = "pseudo",
2995 .match = pseudo_lld_bus_match,
Russell Kingbbbe3a42006-01-05 14:44:46 +00002996 .probe = sdebug_driver_probe,
2997 .remove = sdebug_driver_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998};
2999
3000static void sdebug_release_adapter(struct device * dev)
3001{
3002 struct sdebug_host_info *sdbg_host;
3003
3004 sdbg_host = to_sdebug_host(dev);
3005 kfree(sdbg_host);
3006}
3007
3008static int sdebug_add_adapter(void)
3009{
3010 int k, devs_per_host;
3011 int error = 0;
3012 struct sdebug_host_info *sdbg_host;
3013 struct sdebug_dev_info *sdbg_devinfo;
3014 struct list_head *lh, *lh_sf;
3015
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003016 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 if (NULL == sdbg_host) {
3018 printk(KERN_ERR "%s: out of memory at line %d\n",
3019 __FUNCTION__, __LINE__);
3020 return -ENOMEM;
3021 }
3022
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
3024
3025 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
3026 for (k = 0; k < devs_per_host; k++) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003027 sdbg_devinfo = kzalloc(sizeof(*sdbg_devinfo),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028 if (NULL == sdbg_devinfo) {
3029 printk(KERN_ERR "%s: out of memory at line %d\n",
3030 __FUNCTION__, __LINE__);
3031 error = -ENOMEM;
3032 goto clean;
3033 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 sdbg_devinfo->sdbg_host = sdbg_host;
3035 list_add_tail(&sdbg_devinfo->dev_list,
3036 &sdbg_host->dev_info_list);
3037 }
3038
3039 spin_lock(&sdebug_host_list_lock);
3040 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
3041 spin_unlock(&sdebug_host_list_lock);
3042
3043 sdbg_host->dev.bus = &pseudo_lld_bus;
3044 sdbg_host->dev.parent = &pseudo_primary;
3045 sdbg_host->dev.release = &sdebug_release_adapter;
3046 sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host);
3047
3048 error = device_register(&sdbg_host->dev);
3049
3050 if (error)
3051 goto clean;
3052
3053 ++scsi_debug_add_host;
3054 return error;
3055
3056clean:
3057 list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) {
3058 sdbg_devinfo = list_entry(lh, struct sdebug_dev_info,
3059 dev_list);
3060 list_del(&sdbg_devinfo->dev_list);
3061 kfree(sdbg_devinfo);
3062 }
3063
3064 kfree(sdbg_host);
3065 return error;
3066}
3067
3068static void sdebug_remove_adapter(void)
3069{
3070 struct sdebug_host_info * sdbg_host = NULL;
3071
3072 spin_lock(&sdebug_host_list_lock);
3073 if (!list_empty(&sdebug_host_list)) {
3074 sdbg_host = list_entry(sdebug_host_list.prev,
3075 struct sdebug_host_info, host_list);
3076 list_del(&sdbg_host->host_list);
3077 }
3078 spin_unlock(&sdebug_host_list_lock);
3079
3080 if (!sdbg_host)
3081 return;
3082
3083 device_unregister(&sdbg_host->dev);
3084 --scsi_debug_add_host;
3085}
3086
3087static int sdebug_driver_probe(struct device * dev)
3088{
3089 int error = 0;
3090 struct sdebug_host_info *sdbg_host;
3091 struct Scsi_Host *hpnt;
3092
3093 sdbg_host = to_sdebug_host(dev);
3094
3095 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
3096 if (NULL == hpnt) {
3097 printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__);
3098 error = -ENODEV;
3099 return error;
3100 }
3101
3102 sdbg_host->shost = hpnt;
3103 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
3104 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
3105 hpnt->max_id = scsi_debug_num_tgts + 1;
3106 else
3107 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003108 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109
3110 error = scsi_add_host(hpnt, &sdbg_host->dev);
3111 if (error) {
3112 printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
3113 error = -ENODEV;
3114 scsi_host_put(hpnt);
3115 } else
3116 scsi_scan_host(hpnt);
3117
3118
3119 return error;
3120}
3121
3122static int sdebug_driver_remove(struct device * dev)
3123{
3124 struct list_head *lh, *lh_sf;
3125 struct sdebug_host_info *sdbg_host;
3126 struct sdebug_dev_info *sdbg_devinfo;
3127
3128 sdbg_host = to_sdebug_host(dev);
3129
3130 if (!sdbg_host) {
3131 printk(KERN_ERR "%s: Unable to locate host info\n",
3132 __FUNCTION__);
3133 return -ENODEV;
3134 }
3135
3136 scsi_remove_host(sdbg_host->shost);
3137
3138 list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) {
3139 sdbg_devinfo = list_entry(lh, struct sdebug_dev_info,
3140 dev_list);
3141 list_del(&sdbg_devinfo->dev_list);
3142 kfree(sdbg_devinfo);
3143 }
3144
3145 scsi_host_put(sdbg_host->shost);
3146 return 0;
3147}
3148
3149static void sdebug_max_tgts_luns(void)
3150{
3151 struct sdebug_host_info * sdbg_host;
3152 struct Scsi_Host *hpnt;
3153
3154 spin_lock(&sdebug_host_list_lock);
3155 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3156 hpnt = sdbg_host->shost;
3157 if ((hpnt->this_id >= 0) &&
3158 (scsi_debug_num_tgts > hpnt->this_id))
3159 hpnt->max_id = scsi_debug_num_tgts + 1;
3160 else
3161 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003162 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163 }
3164 spin_unlock(&sdebug_host_list_lock);
3165}