blob: 3e2930b7ee2397bef4207dbf545a75667907893c [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>
39#include <linux/smp_lock.h>
40#include <linux/vmalloc.h>
41#include <linux/moduleparam.h>
42
43#include <linux/blkdev.h>
44#include "scsi.h"
45#include <scsi/scsi_host.h>
46#include <scsi/scsicam.h>
47
48#include <linux/stat.h>
49
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include "scsi_logging.h"
51#include "scsi_debug.h"
52
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050053#define SCSI_DEBUG_VERSION "1.81"
54static const char * scsi_debug_version_date = "20070104";
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050056/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040057#define NO_ADDITIONAL_SENSE 0x0
58#define LOGICAL_UNIT_NOT_READY 0x4
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040060#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#define INVALID_OPCODE 0x20
62#define ADDR_OUT_OF_RANGE 0x21
63#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040064#define INVALID_FIELD_IN_PARAM_LIST 0x26
Linus Torvalds1da177e2005-04-16 15:20:36 -070065#define POWERON_RESET 0x29
66#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050067#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040068#define THRESHOLD_EXCEEDED 0x5d
69#define LOW_POWER_COND_ON 0x5e
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050071/* Additional Sense Code Qualifier (ASCQ) */
72#define ACK_NAK_TO 0x3
73
Linus Torvalds1da177e2005-04-16 15:20:36 -070074#define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
75
76/* Default values for driver parameters */
77#define DEF_NUM_HOST 1
78#define DEF_NUM_TGTS 1
79#define DEF_MAX_LUNS 1
80/* With these defaults, this driver will make 1 host with 1 target
81 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
82 */
83#define DEF_DELAY 1
84#define DEF_DEV_SIZE_MB 8
85#define DEF_EVERY_NTH 0
86#define DEF_NUM_PARTS 0
87#define DEF_OPTS 0
88#define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */
89#define DEF_PTYPE 0
90#define DEF_D_SENSE 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -040091#define DEF_NO_LUN_0 0
92#define DEF_VIRTUAL_GB 0
Douglas Gilbert23183912006-09-16 20:30:47 -040093#define DEF_FAKE_RW 0
94#define DEF_VPD_USE_HOSTNO 1
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
96/* bit mask values for scsi_debug_opts */
97#define SCSI_DEBUG_OPT_NOISE 1
98#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
99#define SCSI_DEBUG_OPT_TIMEOUT 4
100#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500101#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102/* When "every_nth" > 0 then modulo "every_nth" commands:
103 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
104 * - a RECOVERED_ERROR is simulated on successful read and write
105 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500106 * - a TRANSPORT_ERROR is simulated on successful read and write
107 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 *
109 * When "every_nth" < 0 then after "- every_nth" commands:
110 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
111 * - a RECOVERED_ERROR is simulated on successful read and write
112 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500113 * - a TRANSPORT_ERROR is simulated on successful read and write
114 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 * This will continue until some other action occurs (e.g. the user
116 * writing a new value (other than -1 or 1) to every_nth via sysfs).
117 */
118
119/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
120 * sector on read commands: */
121#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
122
123/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
124 * or "peripheral device" addressing (value 0) */
125#define SAM2_LUN_ADDRESS_METHOD 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400126#define SAM2_WLUN_REPORT_LUNS 0xc101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127
128static int scsi_debug_add_host = DEF_NUM_HOST;
129static int scsi_debug_delay = DEF_DELAY;
130static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
131static int scsi_debug_every_nth = DEF_EVERY_NTH;
132static int scsi_debug_max_luns = DEF_MAX_LUNS;
133static int scsi_debug_num_parts = DEF_NUM_PARTS;
134static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
135static int scsi_debug_opts = DEF_OPTS;
136static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
137static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
138static int scsi_debug_dsense = DEF_D_SENSE;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400139static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
140static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
Douglas Gilbert23183912006-09-16 20:30:47 -0400141static int scsi_debug_fake_rw = DEF_FAKE_RW;
142static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
144static int scsi_debug_cmnd_count = 0;
145
146#define DEV_READONLY(TGT) (0)
147#define DEV_REMOVEABLE(TGT) (0)
148
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400149static unsigned int sdebug_store_size; /* in bytes */
150static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151static sector_t sdebug_capacity; /* in sectors */
152
153/* old BIOS stuff, kernel may get rid of them but some mode sense pages
154 may still need them */
155static int sdebug_heads; /* heads per disk */
156static int sdebug_cylinders_per; /* cylinders per surface */
157static int sdebug_sectors_per; /* sectors per cylinder */
158
159/* default sector size is 512 bytes, 2**9 bytes */
160#define POW2_SECT_SIZE 9
161#define SECT_SIZE (1 << POW2_SECT_SIZE)
162#define SECT_SIZE_PER(TGT) SECT_SIZE
163
164#define SDEBUG_MAX_PARTS 4
165
166#define SDEBUG_SENSE_LEN 32
167
168struct sdebug_dev_info {
169 struct list_head dev_list;
170 unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */
171 unsigned int channel;
172 unsigned int target;
173 unsigned int lun;
174 struct sdebug_host_info *sdbg_host;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400175 unsigned int wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 char reset;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400177 char stopped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 char used;
179};
180
181struct sdebug_host_info {
182 struct list_head host_list;
183 struct Scsi_Host *shost;
184 struct device dev;
185 struct list_head dev_info_list;
186};
187
188#define to_sdebug_host(d) \
189 container_of(d, struct sdebug_host_info, dev)
190
191static LIST_HEAD(sdebug_host_list);
192static DEFINE_SPINLOCK(sdebug_host_list_lock);
193
194typedef void (* done_funct_t) (struct scsi_cmnd *);
195
196struct sdebug_queued_cmd {
197 int in_use;
198 struct timer_list cmnd_timer;
199 done_funct_t done_funct;
200 struct scsi_cmnd * a_cmnd;
201 int scsi_result;
202};
203static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
204
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +0100205static struct scsi_host_template sdebug_driver_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 .proc_info = scsi_debug_proc_info,
207 .name = "SCSI DEBUG",
208 .info = scsi_debug_info,
209 .slave_alloc = scsi_debug_slave_alloc,
210 .slave_configure = scsi_debug_slave_configure,
211 .slave_destroy = scsi_debug_slave_destroy,
212 .ioctl = scsi_debug_ioctl,
213 .queuecommand = scsi_debug_queuecommand,
214 .eh_abort_handler = scsi_debug_abort,
215 .eh_bus_reset_handler = scsi_debug_bus_reset,
216 .eh_device_reset_handler = scsi_debug_device_reset,
217 .eh_host_reset_handler = scsi_debug_host_reset,
218 .bios_param = scsi_debug_biosparam,
219 .can_queue = SCSI_DEBUG_CANQUEUE,
220 .this_id = 7,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400221 .sg_tablesize = 256,
222 .cmd_per_lun = 16,
223 .max_sectors = 0xffff,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 .unchecked_isa_dma = 0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400225 .use_clustering = ENABLE_CLUSTERING,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 .module = THIS_MODULE,
227};
228
229static unsigned char * fake_storep; /* ramdisk storage */
230
231static int num_aborts = 0;
232static int num_dev_resets = 0;
233static int num_bus_resets = 0;
234static int num_host_resets = 0;
235
236static DEFINE_SPINLOCK(queued_arr_lock);
237static DEFINE_RWLOCK(atomic_rw);
238
239static char sdebug_proc_name[] = "scsi_debug";
240
241static int sdebug_driver_probe(struct device *);
242static int sdebug_driver_remove(struct device *);
243static struct bus_type pseudo_lld_bus;
244
245static struct device_driver sdebug_driverfs_driver = {
246 .name = sdebug_proc_name,
247 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248};
249
250static const int check_condition_result =
251 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
252
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400253static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
254 0, 0, 0x2, 0x4b};
255static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
256 0, 0, 0x0, 0x0};
257
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258/* function declarations */
259static int resp_inquiry(struct scsi_cmnd * SCpnt, int target,
260 struct sdebug_dev_info * devip);
261static int resp_requests(struct scsi_cmnd * SCpnt,
262 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400263static int resp_start_stop(struct scsi_cmnd * scp,
264 struct sdebug_dev_info * devip);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200265static int resp_report_tgtpgs(struct scsi_cmnd * scp,
266 struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267static int resp_readcap(struct scsi_cmnd * SCpnt,
268 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400269static int resp_readcap16(struct scsi_cmnd * SCpnt,
270 struct sdebug_dev_info * devip);
271static int resp_mode_sense(struct scsi_cmnd * scp, int target,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400273static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
274 struct sdebug_dev_info * devip);
275static int resp_log_sense(struct scsi_cmnd * scp,
276 struct sdebug_dev_info * devip);
277static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
278 unsigned int num, struct sdebug_dev_info * devip);
279static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
280 unsigned int num, struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281static int resp_report_luns(struct scsi_cmnd * SCpnt,
282 struct sdebug_dev_info * devip);
283static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
284 int arr_len);
285static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
286 int max_arr_len);
287static void timer_intr_handler(unsigned long);
288static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev);
289static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
290 int asc, int asq);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400291static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
292 struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293static int schedule_resp(struct scsi_cmnd * cmnd,
294 struct sdebug_dev_info * devip,
295 done_funct_t done, int scsi_result, int delta_jiff);
296static void __init sdebug_build_parts(unsigned char * ramp);
297static void __init init_all_queued(void);
298static void stop_all_queued(void);
299static int stop_queued_cmnd(struct scsi_cmnd * cmnd);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200300static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
301 int target_dev_id, int dev_id_num,
302 const char * dev_id_str, int dev_id_str_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400303static int inquiry_evpd_88(unsigned char * arr, int target_dev_id);
Randy Dunlap6ecaff72006-07-11 20:53:22 -0700304static int do_create_driverfs_files(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305static void do_remove_driverfs_files(void);
306
307static int sdebug_add_adapter(void);
308static void sdebug_remove_adapter(void);
309static void sdebug_max_tgts_luns(void);
310
311static struct device pseudo_primary;
312static struct bus_type pseudo_lld_bus;
313
314
315static
316int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
317{
318 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400319 int len, k, j;
320 unsigned int num;
321 unsigned long long lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 int errsts = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400323 int target = SCpnt->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 struct sdebug_dev_info * devip = NULL;
325 int inj_recovered = 0;
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500326 int inj_transport = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400327 int delay_override = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
329 if (done == NULL)
330 return 0; /* assume mid level reprocessing command */
331
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400332 SCpnt->resid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
334 printk(KERN_INFO "scsi_debug: cmd ");
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400335 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 printk("%02x ", (int)cmd[k]);
337 printk("\n");
338 }
339 if(target == sdebug_driver_template.this_id) {
340 printk(KERN_INFO "scsi_debug: initiator's id used as "
341 "target!\n");
342 return schedule_resp(SCpnt, NULL, done,
343 DID_NO_CONNECT << 16, 0);
344 }
345
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400346 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
347 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 return schedule_resp(SCpnt, NULL, done,
349 DID_NO_CONNECT << 16, 0);
350 devip = devInfoReg(SCpnt->device);
351 if (NULL == devip)
352 return schedule_resp(SCpnt, NULL, done,
353 DID_NO_CONNECT << 16, 0);
354
355 if ((scsi_debug_every_nth != 0) &&
356 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
357 scsi_debug_cmnd_count = 0;
358 if (scsi_debug_every_nth < -1)
359 scsi_debug_every_nth = -1;
360 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
361 return 0; /* ignore command causing timeout */
362 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
363 inj_recovered = 1; /* to reads and writes below */
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500364 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
365 inj_transport = 1; /* to reads and writes below */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 }
367
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400368 if (devip->wlun) {
369 switch (*cmd) {
370 case INQUIRY:
371 case REQUEST_SENSE:
372 case TEST_UNIT_READY:
373 case REPORT_LUNS:
374 break; /* only allowable wlun commands */
375 default:
376 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
377 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
378 "not supported for wlun\n", *cmd);
379 mk_sense_buffer(devip, ILLEGAL_REQUEST,
380 INVALID_OPCODE, 0);
381 errsts = check_condition_result;
382 return schedule_resp(SCpnt, devip, done, errsts,
383 0);
384 }
385 }
386
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 switch (*cmd) {
388 case INQUIRY: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400389 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 errsts = resp_inquiry(SCpnt, target, devip);
391 break;
392 case REQUEST_SENSE: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400393 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 errsts = resp_requests(SCpnt, devip);
395 break;
396 case REZERO_UNIT: /* actually this is REWIND for SSC */
397 case START_STOP:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400398 errsts = resp_start_stop(SCpnt, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 break;
400 case ALLOW_MEDIUM_REMOVAL:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400401 if ((errsts = check_readiness(SCpnt, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 break;
403 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
404 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
405 cmd[4] ? "inhibited" : "enabled");
406 break;
407 case SEND_DIAGNOSTIC: /* mandatory */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400408 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 break;
410 case TEST_UNIT_READY: /* mandatory */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400411 delay_override = 1;
412 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 break;
414 case RESERVE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400415 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 break;
417 case RESERVE_10:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400418 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 break;
420 case RELEASE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400421 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 break;
423 case RELEASE_10:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400424 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 break;
426 case READ_CAPACITY:
427 errsts = resp_readcap(SCpnt, devip);
428 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400429 case SERVICE_ACTION_IN:
430 if (SAI_READ_CAPACITY_16 != cmd[1]) {
431 mk_sense_buffer(devip, ILLEGAL_REQUEST,
432 INVALID_OPCODE, 0);
433 errsts = check_condition_result;
434 break;
435 }
436 errsts = resp_readcap16(SCpnt, devip);
437 break;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200438 case MAINTENANCE_IN:
439 if (MI_REPORT_TARGET_PGS != cmd[1]) {
440 mk_sense_buffer(devip, ILLEGAL_REQUEST,
441 INVALID_OPCODE, 0);
442 errsts = check_condition_result;
443 break;
444 }
445 errsts = resp_report_tgtpgs(SCpnt, devip);
446 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 case READ_16:
448 case READ_12:
449 case READ_10:
450 case READ_6:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400451 if ((errsts = check_readiness(SCpnt, 0, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 break;
Douglas Gilbert23183912006-09-16 20:30:47 -0400453 if (scsi_debug_fake_rw)
454 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 if ((*cmd) == READ_16) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400456 for (lba = 0, j = 0; j < 8; ++j) {
457 if (j > 0)
458 lba <<= 8;
459 lba += cmd[2 + j];
460 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 num = cmd[13] + (cmd[12] << 8) +
462 (cmd[11] << 16) + (cmd[10] << 24);
463 } else if ((*cmd) == READ_12) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400464 lba = cmd[5] + (cmd[4] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 (cmd[3] << 16) + (cmd[2] << 24);
466 num = cmd[9] + (cmd[8] << 8) +
467 (cmd[7] << 16) + (cmd[6] << 24);
468 } else if ((*cmd) == READ_10) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400469 lba = cmd[5] + (cmd[4] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 (cmd[3] << 16) + (cmd[2] << 24);
471 num = cmd[8] + (cmd[7] << 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400472 } else { /* READ (6) */
473 lba = cmd[3] + (cmd[2] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 ((cmd[1] & 0x1f) << 16);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400475 num = (0 == cmd[4]) ? 256 : cmd[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400477 errsts = resp_read(SCpnt, lba, num, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 if (inj_recovered && (0 == errsts)) {
479 mk_sense_buffer(devip, RECOVERED_ERROR,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400480 THRESHOLD_EXCEEDED, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 errsts = check_condition_result;
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500482 } else if (inj_transport && (0 == errsts)) {
483 mk_sense_buffer(devip, ABORTED_COMMAND,
484 TRANSPORT_PROBLEM, ACK_NAK_TO);
485 errsts = check_condition_result;
486 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 break;
488 case REPORT_LUNS: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400489 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 errsts = resp_report_luns(SCpnt, devip);
491 break;
492 case VERIFY: /* 10 byte SBC-2 command */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400493 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 break;
495 case WRITE_16:
496 case WRITE_12:
497 case WRITE_10:
498 case WRITE_6:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400499 if ((errsts = check_readiness(SCpnt, 0, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 break;
Douglas Gilbert23183912006-09-16 20:30:47 -0400501 if (scsi_debug_fake_rw)
502 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 if ((*cmd) == WRITE_16) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400504 for (lba = 0, j = 0; j < 8; ++j) {
505 if (j > 0)
506 lba <<= 8;
507 lba += cmd[2 + j];
508 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 num = cmd[13] + (cmd[12] << 8) +
510 (cmd[11] << 16) + (cmd[10] << 24);
511 } else if ((*cmd) == WRITE_12) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400512 lba = cmd[5] + (cmd[4] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 (cmd[3] << 16) + (cmd[2] << 24);
514 num = cmd[9] + (cmd[8] << 8) +
515 (cmd[7] << 16) + (cmd[6] << 24);
516 } else if ((*cmd) == WRITE_10) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400517 lba = cmd[5] + (cmd[4] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 (cmd[3] << 16) + (cmd[2] << 24);
519 num = cmd[8] + (cmd[7] << 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400520 } else { /* WRITE (6) */
521 lba = cmd[3] + (cmd[2] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 ((cmd[1] & 0x1f) << 16);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400523 num = (0 == cmd[4]) ? 256 : cmd[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400525 errsts = resp_write(SCpnt, lba, num, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 if (inj_recovered && (0 == errsts)) {
527 mk_sense_buffer(devip, RECOVERED_ERROR,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400528 THRESHOLD_EXCEEDED, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 errsts = check_condition_result;
530 }
531 break;
532 case MODE_SENSE:
533 case MODE_SENSE_10:
534 errsts = resp_mode_sense(SCpnt, target, devip);
535 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400536 case MODE_SELECT:
537 errsts = resp_mode_select(SCpnt, 1, devip);
538 break;
539 case MODE_SELECT_10:
540 errsts = resp_mode_select(SCpnt, 0, devip);
541 break;
542 case LOG_SENSE:
543 errsts = resp_log_sense(SCpnt, devip);
544 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 case SYNCHRONIZE_CACHE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400546 delay_override = 1;
547 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 break;
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500549 case WRITE_BUFFER:
550 errsts = check_readiness(SCpnt, 1, devip);
551 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 default:
553 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
554 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
555 "supported\n", *cmd);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400556 if ((errsts = check_readiness(SCpnt, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 break; /* Unit attention takes precedence */
558 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
559 errsts = check_condition_result;
560 break;
561 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400562 return schedule_resp(SCpnt, devip, done, errsts,
563 (delay_override ? 0 : scsi_debug_delay));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564}
565
566static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
567{
568 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
569 printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
570 }
571 return -EINVAL;
572 /* return -ENOTTY; // correct return but upsets fdisk */
573}
574
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400575static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
576 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577{
578 if (devip->reset) {
579 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
580 printk(KERN_INFO "scsi_debug: Reporting Unit "
581 "attention: power on reset\n");
582 devip->reset = 0;
583 mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
584 return check_condition_result;
585 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400586 if ((0 == reset_only) && devip->stopped) {
587 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
588 printk(KERN_INFO "scsi_debug: Reporting Not "
589 "ready: initializing command required\n");
590 mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
591 0x2);
592 return check_condition_result;
593 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 return 0;
595}
596
597/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
598static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
599 int arr_len)
600{
601 int k, req_len, act_len, len, active;
602 void * kaddr;
603 void * kaddr_off;
604 struct scatterlist * sgpnt;
605
606 if (0 == scp->request_bufflen)
607 return 0;
608 if (NULL == scp->request_buffer)
609 return (DID_ERROR << 16);
610 if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
611 (scp->sc_data_direction == DMA_FROM_DEVICE)))
612 return (DID_ERROR << 16);
613 if (0 == scp->use_sg) {
614 req_len = scp->request_bufflen;
615 act_len = (req_len < arr_len) ? req_len : arr_len;
616 memcpy(scp->request_buffer, arr, act_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400617 if (scp->resid)
618 scp->resid -= act_len;
619 else
620 scp->resid = req_len - act_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 return 0;
622 }
623 sgpnt = (struct scatterlist *)scp->request_buffer;
624 active = 1;
625 for (k = 0, req_len = 0, act_len = 0; k < scp->use_sg; ++k, ++sgpnt) {
626 if (active) {
627 kaddr = (unsigned char *)
628 kmap_atomic(sgpnt->page, KM_USER0);
629 if (NULL == kaddr)
630 return (DID_ERROR << 16);
631 kaddr_off = (unsigned char *)kaddr + sgpnt->offset;
632 len = sgpnt->length;
633 if ((req_len + len) > arr_len) {
634 active = 0;
635 len = arr_len - req_len;
636 }
637 memcpy(kaddr_off, arr + req_len, len);
638 kunmap_atomic(kaddr, KM_USER0);
639 act_len += len;
640 }
641 req_len += sgpnt->length;
642 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400643 if (scp->resid)
644 scp->resid -= act_len;
645 else
646 scp->resid = req_len - act_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 return 0;
648}
649
650/* Returns number of bytes fetched into 'arr' or -1 if error. */
651static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
652 int max_arr_len)
653{
654 int k, req_len, len, fin;
655 void * kaddr;
656 void * kaddr_off;
657 struct scatterlist * sgpnt;
658
659 if (0 == scp->request_bufflen)
660 return 0;
661 if (NULL == scp->request_buffer)
662 return -1;
663 if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
664 (scp->sc_data_direction == DMA_TO_DEVICE)))
665 return -1;
666 if (0 == scp->use_sg) {
667 req_len = scp->request_bufflen;
668 len = (req_len < max_arr_len) ? req_len : max_arr_len;
669 memcpy(arr, scp->request_buffer, len);
670 return len;
671 }
672 sgpnt = (struct scatterlist *)scp->request_buffer;
673 for (k = 0, req_len = 0, fin = 0; k < scp->use_sg; ++k, ++sgpnt) {
674 kaddr = (unsigned char *)kmap_atomic(sgpnt->page, KM_USER0);
675 if (NULL == kaddr)
676 return -1;
677 kaddr_off = (unsigned char *)kaddr + sgpnt->offset;
678 len = sgpnt->length;
679 if ((req_len + len) > max_arr_len) {
680 len = max_arr_len - req_len;
681 fin = 1;
682 }
683 memcpy(arr + req_len, kaddr_off, len);
684 kunmap_atomic(kaddr, KM_USER0);
685 if (fin)
686 return req_len + len;
687 req_len += sgpnt->length;
688 }
689 return req_len;
690}
691
692
693static const char * inq_vendor_id = "Linux ";
694static const char * inq_product_id = "scsi_debug ";
695static const char * inq_product_rev = "0004";
696
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200697static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
698 int target_dev_id, int dev_id_num,
699 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400700 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400702 int num, port_a;
703 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400705 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 /* T10 vendor identifier field format (faked) */
707 arr[0] = 0x2; /* ASCII */
708 arr[1] = 0x1;
709 arr[2] = 0x0;
710 memcpy(&arr[4], inq_vendor_id, 8);
711 memcpy(&arr[12], inq_product_id, 16);
712 memcpy(&arr[28], dev_id_str, dev_id_str_len);
713 num = 8 + 16 + dev_id_str_len;
714 arr[3] = num;
715 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400716 if (dev_id_num >= 0) {
717 /* NAA-5, Logical unit identifier (binary) */
718 arr[num++] = 0x1; /* binary (not necessarily sas) */
719 arr[num++] = 0x3; /* PIV=0, lu, naa */
720 arr[num++] = 0x0;
721 arr[num++] = 0x8;
722 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
723 arr[num++] = 0x33;
724 arr[num++] = 0x33;
725 arr[num++] = 0x30;
726 arr[num++] = (dev_id_num >> 24);
727 arr[num++] = (dev_id_num >> 16) & 0xff;
728 arr[num++] = (dev_id_num >> 8) & 0xff;
729 arr[num++] = dev_id_num & 0xff;
730 /* Target relative port number */
731 arr[num++] = 0x61; /* proto=sas, binary */
732 arr[num++] = 0x94; /* PIV=1, target port, rel port */
733 arr[num++] = 0x0; /* reserved */
734 arr[num++] = 0x4; /* length */
735 arr[num++] = 0x0; /* reserved */
736 arr[num++] = 0x0; /* reserved */
737 arr[num++] = 0x0;
738 arr[num++] = 0x1; /* relative port A */
739 }
740 /* NAA-5, Target port identifier */
741 arr[num++] = 0x61; /* proto=sas, binary */
742 arr[num++] = 0x93; /* piv=1, target port, naa */
743 arr[num++] = 0x0;
744 arr[num++] = 0x8;
745 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
746 arr[num++] = 0x22;
747 arr[num++] = 0x22;
748 arr[num++] = 0x20;
749 arr[num++] = (port_a >> 24);
750 arr[num++] = (port_a >> 16) & 0xff;
751 arr[num++] = (port_a >> 8) & 0xff;
752 arr[num++] = port_a & 0xff;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200753 /* NAA-5, Target port group identifier */
754 arr[num++] = 0x61; /* proto=sas, binary */
755 arr[num++] = 0x95; /* piv=1, target port group id */
756 arr[num++] = 0x0;
757 arr[num++] = 0x4;
758 arr[num++] = 0;
759 arr[num++] = 0;
760 arr[num++] = (port_group_id >> 8) & 0xff;
761 arr[num++] = port_group_id & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400762 /* NAA-5, Target device identifier */
763 arr[num++] = 0x61; /* proto=sas, binary */
764 arr[num++] = 0xa3; /* piv=1, target device, naa */
765 arr[num++] = 0x0;
766 arr[num++] = 0x8;
767 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
768 arr[num++] = 0x22;
769 arr[num++] = 0x22;
770 arr[num++] = 0x20;
771 arr[num++] = (target_dev_id >> 24);
772 arr[num++] = (target_dev_id >> 16) & 0xff;
773 arr[num++] = (target_dev_id >> 8) & 0xff;
774 arr[num++] = target_dev_id & 0xff;
775 /* SCSI name string: Target device identifier */
776 arr[num++] = 0x63; /* proto=sas, UTF-8 */
777 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
778 arr[num++] = 0x0;
779 arr[num++] = 24;
780 memcpy(arr + num, "naa.52222220", 12);
781 num += 12;
782 snprintf(b, sizeof(b), "%08X", target_dev_id);
783 memcpy(arr + num, b, 8);
784 num += 8;
785 memset(arr + num, 0, 4);
786 num += 4;
787 return num;
788}
789
790
791static unsigned char vpd84_data[] = {
792/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
793 0x22,0x22,0x22,0x0,0xbb,0x1,
794 0x22,0x22,0x22,0x0,0xbb,0x2,
795};
796
797static int inquiry_evpd_84(unsigned char * arr)
798{
799 memcpy(arr, vpd84_data, sizeof(vpd84_data));
800 return sizeof(vpd84_data);
801}
802
803static int inquiry_evpd_85(unsigned char * arr)
804{
805 int num = 0;
806 const char * na1 = "https://www.kernel.org/config";
807 const char * na2 = "http://www.kernel.org/log";
808 int plen, olen;
809
810 arr[num++] = 0x1; /* lu, storage config */
811 arr[num++] = 0x0; /* reserved */
812 arr[num++] = 0x0;
813 olen = strlen(na1);
814 plen = olen + 1;
815 if (plen % 4)
816 plen = ((plen / 4) + 1) * 4;
817 arr[num++] = plen; /* length, null termianted, padded */
818 memcpy(arr + num, na1, olen);
819 memset(arr + num + olen, 0, plen - olen);
820 num += plen;
821
822 arr[num++] = 0x4; /* lu, logging */
823 arr[num++] = 0x0; /* reserved */
824 arr[num++] = 0x0;
825 olen = strlen(na2);
826 plen = olen + 1;
827 if (plen % 4)
828 plen = ((plen / 4) + 1) * 4;
829 arr[num++] = plen; /* length, null terminated, padded */
830 memcpy(arr + num, na2, olen);
831 memset(arr + num + olen, 0, plen - olen);
832 num += plen;
833
834 return num;
835}
836
837/* SCSI ports VPD page */
838static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
839{
840 int num = 0;
841 int port_a, port_b;
842
843 port_a = target_dev_id + 1;
844 port_b = port_a + 1;
845 arr[num++] = 0x0; /* reserved */
846 arr[num++] = 0x0; /* reserved */
847 arr[num++] = 0x0;
848 arr[num++] = 0x1; /* relative port 1 (primary) */
849 memset(arr + num, 0, 6);
850 num += 6;
851 arr[num++] = 0x0;
852 arr[num++] = 12; /* length tp descriptor */
853 /* naa-5 target port identifier (A) */
854 arr[num++] = 0x61; /* proto=sas, binary */
855 arr[num++] = 0x93; /* PIV=1, target port, NAA */
856 arr[num++] = 0x0; /* reserved */
857 arr[num++] = 0x8; /* length */
858 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
859 arr[num++] = 0x22;
860 arr[num++] = 0x22;
861 arr[num++] = 0x20;
862 arr[num++] = (port_a >> 24);
863 arr[num++] = (port_a >> 16) & 0xff;
864 arr[num++] = (port_a >> 8) & 0xff;
865 arr[num++] = port_a & 0xff;
866
867 arr[num++] = 0x0; /* reserved */
868 arr[num++] = 0x0; /* reserved */
869 arr[num++] = 0x0;
870 arr[num++] = 0x2; /* relative port 2 (secondary) */
871 memset(arr + num, 0, 6);
872 num += 6;
873 arr[num++] = 0x0;
874 arr[num++] = 12; /* length tp descriptor */
875 /* naa-5 target port identifier (B) */
876 arr[num++] = 0x61; /* proto=sas, binary */
877 arr[num++] = 0x93; /* PIV=1, target port, NAA */
878 arr[num++] = 0x0; /* reserved */
879 arr[num++] = 0x8; /* length */
880 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
881 arr[num++] = 0x22;
882 arr[num++] = 0x22;
883 arr[num++] = 0x20;
884 arr[num++] = (port_b >> 24);
885 arr[num++] = (port_b >> 16) & 0xff;
886 arr[num++] = (port_b >> 8) & 0xff;
887 arr[num++] = port_b & 0xff;
888
889 return num;
890}
891
892
893static unsigned char vpd89_data[] = {
894/* from 4th byte */ 0,0,0,0,
895'l','i','n','u','x',' ',' ',' ',
896'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
897'1','2','3','4',
8980x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
8990xec,0,0,0,
9000x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
9010,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
9020x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
9030x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
9040x53,0x41,
9050x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
9060x20,0x20,
9070x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
9080x10,0x80,
9090,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
9100x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
9110x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
9120,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
9130x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
9140x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
9150,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
9160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9170,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9180,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9190x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
9200,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
9210xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
9220,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
9230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9240,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9250,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9260,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9270,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9280,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9290,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9300,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9310,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9320,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9330,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9340,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
935};
936
937static int inquiry_evpd_89(unsigned char * arr)
938{
939 memcpy(arr, vpd89_data, sizeof(vpd89_data));
940 return sizeof(vpd89_data);
941}
942
943
944static unsigned char vpdb0_data[] = {
945 /* from 4th byte */ 0,0,0,4,
946 0,0,0x4,0,
947 0,0,0,64,
948};
949
950static int inquiry_evpd_b0(unsigned char * arr)
951{
952 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
953 if (sdebug_store_sectors > 0x400) {
954 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
955 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
956 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
957 arr[7] = sdebug_store_sectors & 0xff;
958 }
959 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960}
961
962
963#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400964#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
966static int resp_inquiry(struct scsi_cmnd * scp, int target,
967 struct sdebug_dev_info * devip)
968{
969 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200970 unsigned char * arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 unsigned char *cmd = (unsigned char *)scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200972 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973
974 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500975 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
976 if (! arr)
977 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400978 if (devip->wlun)
979 pq_pdt = 0x1e; /* present, wlun */
980 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
981 pq_pdt = 0x7f; /* not present, no device type */
982 else
983 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 arr[0] = pq_pdt;
985 if (0x2 & cmd[1]) { /* CMDDT bit set */
986 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
987 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200988 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 return check_condition_result;
990 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200991 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400992 char lu_id_str[6];
993 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200995 port_group_id = (((host_no + 1) & 0x7f) << 8) +
996 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -0400997 if (0 == scsi_debug_vpd_use_hostno)
998 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400999 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
1000 (devip->target * 1000) + devip->lun);
1001 target_dev_id = ((host_no + 1) * 2000) +
1002 (devip->target * 1000) - 3;
1003 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001005 arr[1] = cmd[2]; /*sanity */
1006 n = 4;
1007 arr[n++] = 0x0; /* this page */
1008 arr[n++] = 0x80; /* unit serial number */
1009 arr[n++] = 0x83; /* device identification */
1010 arr[n++] = 0x84; /* software interface ident. */
1011 arr[n++] = 0x85; /* management network addresses */
1012 arr[n++] = 0x86; /* extended inquiry */
1013 arr[n++] = 0x87; /* mode page policy */
1014 arr[n++] = 0x88; /* SCSI ports */
1015 arr[n++] = 0x89; /* ATA information */
1016 arr[n++] = 0xb0; /* Block limits (SBC) */
1017 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001019 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001021 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001023 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001024 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
1025 target_dev_id, lu_id_num,
1026 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001027 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1028 arr[1] = cmd[2]; /*sanity */
1029 arr[3] = inquiry_evpd_84(&arr[4]);
1030 } else if (0x85 == cmd[2]) { /* Management network addresses */
1031 arr[1] = cmd[2]; /*sanity */
1032 arr[3] = inquiry_evpd_85(&arr[4]);
1033 } else if (0x86 == cmd[2]) { /* extended inquiry */
1034 arr[1] = cmd[2]; /*sanity */
1035 arr[3] = 0x3c; /* number of following entries */
1036 arr[4] = 0x0; /* no protection stuff */
1037 arr[5] = 0x7; /* head of q, ordered + simple q's */
1038 } else if (0x87 == cmd[2]) { /* mode page policy */
1039 arr[1] = cmd[2]; /*sanity */
1040 arr[3] = 0x8; /* number of following entries */
1041 arr[4] = 0x2; /* disconnect-reconnect mp */
1042 arr[6] = 0x80; /* mlus, shared */
1043 arr[8] = 0x18; /* protocol specific lu */
1044 arr[10] = 0x82; /* mlus, per initiator port */
1045 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1046 arr[1] = cmd[2]; /*sanity */
1047 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
1048 } else if (0x89 == cmd[2]) { /* ATA information */
1049 arr[1] = cmd[2]; /*sanity */
1050 n = inquiry_evpd_89(&arr[4]);
1051 arr[2] = (n >> 8);
1052 arr[3] = (n & 0xff);
1053 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
1054 arr[1] = cmd[2]; /*sanity */
1055 arr[3] = inquiry_evpd_b0(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 } else {
1057 /* Illegal request, invalid field in cdb */
1058 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1059 INVALID_FIELD_IN_CDB, 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001060 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 return check_condition_result;
1062 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001063 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001064 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001065 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001066 kfree(arr);
1067 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 }
1069 /* drops through here for a standard inquiry */
1070 arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
1071 arr[2] = scsi_debug_scsi_level;
1072 arr[3] = 2; /* response_data_format==2 */
1073 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001074 if (0 == scsi_debug_vpd_use_hostno)
1075 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001076 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001078 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 memcpy(&arr[8], inq_vendor_id, 8);
1080 memcpy(&arr[16], inq_product_id, 16);
1081 memcpy(&arr[32], inq_product_rev, 4);
1082 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001083 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
1084 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
1085 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001087 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001089 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001091 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001092 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001094 kfree(arr);
1095 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096}
1097
1098static int resp_requests(struct scsi_cmnd * scp,
1099 struct sdebug_dev_info * devip)
1100{
1101 unsigned char * sbuff;
1102 unsigned char *cmd = (unsigned char *)scp->cmnd;
1103 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001104 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 int len = 18;
1106
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001107 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001109 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
1110 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001112 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1113 if (want_dsense) {
1114 arr[0] = 0x72;
1115 arr[1] = 0x0; /* NO_SENSE in sense_key */
1116 arr[2] = THRESHOLD_EXCEEDED;
1117 arr[3] = 0xff; /* TEST set and MRIE==6 */
1118 } else {
1119 arr[0] = 0x70;
1120 arr[2] = 0x0; /* NO_SENSE in sense_key */
1121 arr[7] = 0xa; /* 18 byte sense buffer */
1122 arr[12] = THRESHOLD_EXCEEDED;
1123 arr[13] = 0xff; /* TEST set and MRIE==6 */
1124 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001125 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001127 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
1128 /* DESC bit set and sense_buff in fixed format */
1129 memset(arr, 0, sizeof(arr));
1130 arr[0] = 0x72;
1131 arr[1] = sbuff[2]; /* sense key */
1132 arr[2] = sbuff[12]; /* asc */
1133 arr[3] = sbuff[13]; /* ascq */
1134 len = 8;
1135 }
1136 }
1137 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 return fill_from_dev_buffer(scp, arr, len);
1139}
1140
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001141static int resp_start_stop(struct scsi_cmnd * scp,
1142 struct sdebug_dev_info * devip)
1143{
1144 unsigned char *cmd = (unsigned char *)scp->cmnd;
1145 int power_cond, errsts, start;
1146
1147 if ((errsts = check_readiness(scp, 1, devip)))
1148 return errsts;
1149 power_cond = (cmd[4] & 0xf0) >> 4;
1150 if (power_cond) {
1151 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1152 0);
1153 return check_condition_result;
1154 }
1155 start = cmd[4] & 1;
1156 if (start == devip->stopped)
1157 devip->stopped = !start;
1158 return 0;
1159}
1160
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161#define SDEBUG_READCAP_ARR_SZ 8
1162static int resp_readcap(struct scsi_cmnd * scp,
1163 struct sdebug_dev_info * devip)
1164{
1165 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001166 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 int errsts;
1168
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001169 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001171 /* following just in case virtual_gb changed */
1172 if (scsi_debug_virtual_gb > 0) {
1173 sdebug_capacity = 2048 * 1024;
1174 sdebug_capacity *= scsi_debug_virtual_gb;
1175 } else
1176 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001178 if (sdebug_capacity < 0xffffffff) {
1179 capac = (unsigned int)sdebug_capacity - 1;
1180 arr[0] = (capac >> 24);
1181 arr[1] = (capac >> 16) & 0xff;
1182 arr[2] = (capac >> 8) & 0xff;
1183 arr[3] = capac & 0xff;
1184 } else {
1185 arr[0] = 0xff;
1186 arr[1] = 0xff;
1187 arr[2] = 0xff;
1188 arr[3] = 0xff;
1189 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1191 arr[7] = SECT_SIZE_PER(target) & 0xff;
1192 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1193}
1194
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001195#define SDEBUG_READCAP16_ARR_SZ 32
1196static int resp_readcap16(struct scsi_cmnd * scp,
1197 struct sdebug_dev_info * devip)
1198{
1199 unsigned char *cmd = (unsigned char *)scp->cmnd;
1200 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1201 unsigned long long capac;
1202 int errsts, k, alloc_len;
1203
1204 if ((errsts = check_readiness(scp, 1, devip)))
1205 return errsts;
1206 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1207 + cmd[13]);
1208 /* following just in case virtual_gb changed */
1209 if (scsi_debug_virtual_gb > 0) {
1210 sdebug_capacity = 2048 * 1024;
1211 sdebug_capacity *= scsi_debug_virtual_gb;
1212 } else
1213 sdebug_capacity = sdebug_store_sectors;
1214 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1215 capac = sdebug_capacity - 1;
1216 for (k = 0; k < 8; ++k, capac >>= 8)
1217 arr[7 - k] = capac & 0xff;
1218 arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff;
1219 arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff;
1220 arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1221 arr[11] = SECT_SIZE_PER(target) & 0xff;
1222 return fill_from_dev_buffer(scp, arr,
1223 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1224}
1225
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001226#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1227
1228static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1229 struct sdebug_dev_info * devip)
1230{
1231 unsigned char *cmd = (unsigned char *)scp->cmnd;
1232 unsigned char * arr;
1233 int host_no = devip->sdbg_host->shost->host_no;
1234 int n, ret, alen, rlen;
1235 int port_group_a, port_group_b, port_a, port_b;
1236
1237 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
1238 + cmd[9]);
1239
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001240 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1241 if (! arr)
1242 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001243 /*
1244 * EVPD page 0x88 states we have two ports, one
1245 * real and a fake port with no device connected.
1246 * So we create two port groups with one port each
1247 * and set the group with port B to unavailable.
1248 */
1249 port_a = 0x1; /* relative port A */
1250 port_b = 0x2; /* relative port B */
1251 port_group_a = (((host_no + 1) & 0x7f) << 8) +
1252 (devip->channel & 0x7f);
1253 port_group_b = (((host_no + 1) & 0x7f) << 8) +
1254 (devip->channel & 0x7f) + 0x80;
1255
1256 /*
1257 * The asymmetric access state is cycled according to the host_id.
1258 */
1259 n = 4;
1260 if (0 == scsi_debug_vpd_use_hostno) {
1261 arr[n++] = host_no % 3; /* Asymm access state */
1262 arr[n++] = 0x0F; /* claim: all states are supported */
1263 } else {
1264 arr[n++] = 0x0; /* Active/Optimized path */
1265 arr[n++] = 0x01; /* claim: only support active/optimized paths */
1266 }
1267 arr[n++] = (port_group_a >> 8) & 0xff;
1268 arr[n++] = port_group_a & 0xff;
1269 arr[n++] = 0; /* Reserved */
1270 arr[n++] = 0; /* Status code */
1271 arr[n++] = 0; /* Vendor unique */
1272 arr[n++] = 0x1; /* One port per group */
1273 arr[n++] = 0; /* Reserved */
1274 arr[n++] = 0; /* Reserved */
1275 arr[n++] = (port_a >> 8) & 0xff;
1276 arr[n++] = port_a & 0xff;
1277 arr[n++] = 3; /* Port unavailable */
1278 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1279 arr[n++] = (port_group_b >> 8) & 0xff;
1280 arr[n++] = port_group_b & 0xff;
1281 arr[n++] = 0; /* Reserved */
1282 arr[n++] = 0; /* Status code */
1283 arr[n++] = 0; /* Vendor unique */
1284 arr[n++] = 0x1; /* One port per group */
1285 arr[n++] = 0; /* Reserved */
1286 arr[n++] = 0; /* Reserved */
1287 arr[n++] = (port_b >> 8) & 0xff;
1288 arr[n++] = port_b & 0xff;
1289
1290 rlen = n - 4;
1291 arr[0] = (rlen >> 24) & 0xff;
1292 arr[1] = (rlen >> 16) & 0xff;
1293 arr[2] = (rlen >> 8) & 0xff;
1294 arr[3] = rlen & 0xff;
1295
1296 /*
1297 * Return the smallest value of either
1298 * - The allocated length
1299 * - The constructed command length
1300 * - The maximum array size
1301 */
1302 rlen = min(alen,n);
1303 ret = fill_from_dev_buffer(scp, arr,
1304 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1305 kfree(arr);
1306 return ret;
1307}
1308
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309/* <<Following mode page info copied from ST318451LW>> */
1310
1311static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1312{ /* Read-Write Error Recovery page for mode_sense */
1313 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1314 5, 0, 0xff, 0xff};
1315
1316 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1317 if (1 == pcontrol)
1318 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1319 return sizeof(err_recov_pg);
1320}
1321
1322static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1323{ /* Disconnect-Reconnect page for mode_sense */
1324 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1325 0, 0, 0, 0, 0, 0, 0, 0};
1326
1327 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1328 if (1 == pcontrol)
1329 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1330 return sizeof(disconnect_pg);
1331}
1332
1333static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1334{ /* Format device page for mode_sense */
1335 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1336 0, 0, 0, 0, 0, 0, 0, 0,
1337 0, 0, 0, 0, 0x40, 0, 0, 0};
1338
1339 memcpy(p, format_pg, sizeof(format_pg));
1340 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1341 p[11] = sdebug_sectors_per & 0xff;
1342 p[12] = (SECT_SIZE >> 8) & 0xff;
1343 p[13] = SECT_SIZE & 0xff;
1344 if (DEV_REMOVEABLE(target))
1345 p[20] |= 0x20; /* should agree with INQUIRY */
1346 if (1 == pcontrol)
1347 memset(p + 2, 0, sizeof(format_pg) - 2);
1348 return sizeof(format_pg);
1349}
1350
1351static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1352{ /* Caching page for mode_sense */
1353 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1354 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1355
1356 memcpy(p, caching_pg, sizeof(caching_pg));
1357 if (1 == pcontrol)
1358 memset(p + 2, 0, sizeof(caching_pg) - 2);
1359 return sizeof(caching_pg);
1360}
1361
1362static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1363{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001364 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1365 0, 0, 0, 0};
1366 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 0, 0, 0x2, 0x4b};
1368
1369 if (scsi_debug_dsense)
1370 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001371 else
1372 ctrl_m_pg[2] &= ~0x4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1374 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001375 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1376 else if (2 == pcontrol)
1377 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 return sizeof(ctrl_m_pg);
1379}
1380
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001381
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1383{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001384 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1385 0, 0, 0x0, 0x0};
1386 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1387 0, 0, 0x0, 0x0};
1388
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1390 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001391 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1392 else if (2 == pcontrol)
1393 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 return sizeof(iec_m_pg);
1395}
1396
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001397static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1398{ /* SAS SSP mode page - short format for mode_sense */
1399 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1400 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1401
1402 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1403 if (1 == pcontrol)
1404 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1405 return sizeof(sas_sf_m_pg);
1406}
1407
1408
1409static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1410 int target_dev_id)
1411{ /* SAS phy control and discover mode page for mode_sense */
1412 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1413 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1414 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1415 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1416 0x2, 0, 0, 0, 0, 0, 0, 0,
1417 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1418 0, 0, 0, 0, 0, 0, 0, 0,
1419 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1420 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1421 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1422 0x3, 0, 0, 0, 0, 0, 0, 0,
1423 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1424 0, 0, 0, 0, 0, 0, 0, 0,
1425 };
1426 int port_a, port_b;
1427
1428 port_a = target_dev_id + 1;
1429 port_b = port_a + 1;
1430 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1431 p[20] = (port_a >> 24);
1432 p[21] = (port_a >> 16) & 0xff;
1433 p[22] = (port_a >> 8) & 0xff;
1434 p[23] = port_a & 0xff;
1435 p[48 + 20] = (port_b >> 24);
1436 p[48 + 21] = (port_b >> 16) & 0xff;
1437 p[48 + 22] = (port_b >> 8) & 0xff;
1438 p[48 + 23] = port_b & 0xff;
1439 if (1 == pcontrol)
1440 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1441 return sizeof(sas_pcd_m_pg);
1442}
1443
1444static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1445{ /* SAS SSP shared protocol specific port mode subpage */
1446 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1447 0, 0, 0, 0, 0, 0, 0, 0,
1448 };
1449
1450 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1451 if (1 == pcontrol)
1452 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1453 return sizeof(sas_sha_m_pg);
1454}
1455
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456#define SDEBUG_MAX_MSENSE_SZ 256
1457
1458static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1459 struct sdebug_dev_info * devip)
1460{
Douglas Gilbert23183912006-09-16 20:30:47 -04001461 unsigned char dbd, llbaa;
1462 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001464 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 unsigned char * ap;
1466 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1467 unsigned char *cmd = (unsigned char *)scp->cmnd;
1468
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001469 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001471 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 pcontrol = (cmd[2] & 0xc0) >> 6;
1473 pcode = cmd[2] & 0x3f;
1474 subpcode = cmd[3];
1475 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001476 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1477 if ((0 == scsi_debug_ptype) && (0 == dbd))
1478 bd_len = llbaa ? 16 : 8;
1479 else
1480 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1482 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1483 if (0x3 == pcontrol) { /* Saving values not supported */
1484 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1485 0);
1486 return check_condition_result;
1487 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001488 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1489 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001490 /* set DPOFUA bit for disks */
1491 if (0 == scsi_debug_ptype)
1492 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1493 else
1494 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 if (msense_6) {
1496 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001497 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 offset = 4;
1499 } else {
1500 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001501 if (16 == bd_len)
1502 arr[4] = 0x1; /* set LONGLBA bit */
1503 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 offset = 8;
1505 }
1506 ap = arr + offset;
Douglas Gilbert23183912006-09-16 20:30:47 -04001507 if ((bd_len > 0) && (0 == sdebug_capacity)) {
1508 if (scsi_debug_virtual_gb > 0) {
1509 sdebug_capacity = 2048 * 1024;
1510 sdebug_capacity *= scsi_debug_virtual_gb;
1511 } else
1512 sdebug_capacity = sdebug_store_sectors;
1513 }
1514 if (8 == bd_len) {
1515 if (sdebug_capacity > 0xfffffffe) {
1516 ap[0] = 0xff;
1517 ap[1] = 0xff;
1518 ap[2] = 0xff;
1519 ap[3] = 0xff;
1520 } else {
1521 ap[0] = (sdebug_capacity >> 24) & 0xff;
1522 ap[1] = (sdebug_capacity >> 16) & 0xff;
1523 ap[2] = (sdebug_capacity >> 8) & 0xff;
1524 ap[3] = sdebug_capacity & 0xff;
1525 }
1526 ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1527 ap[7] = SECT_SIZE_PER(target) & 0xff;
1528 offset += bd_len;
1529 ap = arr + offset;
1530 } else if (16 == bd_len) {
1531 unsigned long long capac = sdebug_capacity;
1532
1533 for (k = 0; k < 8; ++k, capac >>= 8)
1534 ap[7 - k] = capac & 0xff;
1535 ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff;
1536 ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff;
1537 ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1538 ap[15] = SECT_SIZE_PER(target) & 0xff;
1539 offset += bd_len;
1540 ap = arr + offset;
1541 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001543 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1544 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1546 0);
1547 return check_condition_result;
1548 }
1549 switch (pcode) {
1550 case 0x1: /* Read-Write error recovery page, direct access */
1551 len = resp_err_recov_pg(ap, pcontrol, target);
1552 offset += len;
1553 break;
1554 case 0x2: /* Disconnect-Reconnect page, all devices */
1555 len = resp_disconnect_pg(ap, pcontrol, target);
1556 offset += len;
1557 break;
1558 case 0x3: /* Format device page, direct access */
1559 len = resp_format_pg(ap, pcontrol, target);
1560 offset += len;
1561 break;
1562 case 0x8: /* Caching page, direct access */
1563 len = resp_caching_pg(ap, pcontrol, target);
1564 offset += len;
1565 break;
1566 case 0xa: /* Control Mode page, all devices */
1567 len = resp_ctrl_m_pg(ap, pcontrol, target);
1568 offset += len;
1569 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001570 case 0x19: /* if spc==1 then sas phy, control+discover */
1571 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1572 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1573 INVALID_FIELD_IN_CDB, 0);
1574 return check_condition_result;
1575 }
1576 len = 0;
1577 if ((0x0 == subpcode) || (0xff == subpcode))
1578 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1579 if ((0x1 == subpcode) || (0xff == subpcode))
1580 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1581 target_dev_id);
1582 if ((0x2 == subpcode) || (0xff == subpcode))
1583 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1584 offset += len;
1585 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 case 0x1c: /* Informational Exceptions Mode page, all devices */
1587 len = resp_iec_m_pg(ap, pcontrol, target);
1588 offset += len;
1589 break;
1590 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001591 if ((0 == subpcode) || (0xff == subpcode)) {
1592 len = resp_err_recov_pg(ap, pcontrol, target);
1593 len += resp_disconnect_pg(ap + len, pcontrol, target);
1594 len += resp_format_pg(ap + len, pcontrol, target);
1595 len += resp_caching_pg(ap + len, pcontrol, target);
1596 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1597 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1598 if (0xff == subpcode) {
1599 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1600 target, target_dev_id);
1601 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1602 }
1603 len += resp_iec_m_pg(ap + len, pcontrol, target);
1604 } else {
1605 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1606 INVALID_FIELD_IN_CDB, 0);
1607 return check_condition_result;
1608 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 offset += len;
1610 break;
1611 default:
1612 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1613 0);
1614 return check_condition_result;
1615 }
1616 if (msense_6)
1617 arr[0] = offset - 1;
1618 else {
1619 arr[0] = ((offset - 2) >> 8) & 0xff;
1620 arr[1] = (offset - 2) & 0xff;
1621 }
1622 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1623}
1624
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001625#define SDEBUG_MAX_MSELECT_SZ 512
1626
1627static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1628 struct sdebug_dev_info * devip)
1629{
1630 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1631 int param_len, res, errsts, mpage;
1632 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1633 unsigned char *cmd = (unsigned char *)scp->cmnd;
1634
1635 if ((errsts = check_readiness(scp, 1, devip)))
1636 return errsts;
1637 memset(arr, 0, sizeof(arr));
1638 pf = cmd[1] & 0x10;
1639 sp = cmd[1] & 0x1;
1640 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1641 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1642 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1643 INVALID_FIELD_IN_CDB, 0);
1644 return check_condition_result;
1645 }
1646 res = fetch_to_dev_buffer(scp, arr, param_len);
1647 if (-1 == res)
1648 return (DID_ERROR << 16);
1649 else if ((res < param_len) &&
1650 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1651 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1652 " IO sent=%d bytes\n", param_len, res);
1653 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1654 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001655 if (md_len > 2) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001656 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1657 INVALID_FIELD_IN_PARAM_LIST, 0);
1658 return check_condition_result;
1659 }
1660 off = bd_len + (mselect6 ? 4 : 8);
1661 mpage = arr[off] & 0x3f;
1662 ps = !!(arr[off] & 0x80);
1663 if (ps) {
1664 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1665 INVALID_FIELD_IN_PARAM_LIST, 0);
1666 return check_condition_result;
1667 }
1668 spf = !!(arr[off] & 0x40);
1669 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1670 (arr[off + 1] + 2);
1671 if ((pg_len + off) > param_len) {
1672 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1673 PARAMETER_LIST_LENGTH_ERR, 0);
1674 return check_condition_result;
1675 }
1676 switch (mpage) {
1677 case 0xa: /* Control Mode page */
1678 if (ctrl_m_pg[1] == arr[off + 1]) {
1679 memcpy(ctrl_m_pg + 2, arr + off + 2,
1680 sizeof(ctrl_m_pg) - 2);
1681 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1682 return 0;
1683 }
1684 break;
1685 case 0x1c: /* Informational Exceptions Mode page */
1686 if (iec_m_pg[1] == arr[off + 1]) {
1687 memcpy(iec_m_pg + 2, arr + off + 2,
1688 sizeof(iec_m_pg) - 2);
1689 return 0;
1690 }
1691 break;
1692 default:
1693 break;
1694 }
1695 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1696 INVALID_FIELD_IN_PARAM_LIST, 0);
1697 return check_condition_result;
1698}
1699
1700static int resp_temp_l_pg(unsigned char * arr)
1701{
1702 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1703 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1704 };
1705
1706 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1707 return sizeof(temp_l_pg);
1708}
1709
1710static int resp_ie_l_pg(unsigned char * arr)
1711{
1712 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1713 };
1714
1715 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1716 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1717 arr[4] = THRESHOLD_EXCEEDED;
1718 arr[5] = 0xff;
1719 }
1720 return sizeof(ie_l_pg);
1721}
1722
1723#define SDEBUG_MAX_LSENSE_SZ 512
1724
1725static int resp_log_sense(struct scsi_cmnd * scp,
1726 struct sdebug_dev_info * devip)
1727{
Douglas Gilbert23183912006-09-16 20:30:47 -04001728 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001729 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1730 unsigned char *cmd = (unsigned char *)scp->cmnd;
1731
1732 if ((errsts = check_readiness(scp, 1, devip)))
1733 return errsts;
1734 memset(arr, 0, sizeof(arr));
1735 ppc = cmd[1] & 0x2;
1736 sp = cmd[1] & 0x1;
1737 if (ppc || sp) {
1738 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1739 INVALID_FIELD_IN_CDB, 0);
1740 return check_condition_result;
1741 }
1742 pcontrol = (cmd[2] & 0xc0) >> 6;
1743 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001744 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001745 alloc_len = (cmd[7] << 8) + cmd[8];
1746 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001747 if (0 == subpcode) {
1748 switch (pcode) {
1749 case 0x0: /* Supported log pages log page */
1750 n = 4;
1751 arr[n++] = 0x0; /* this page */
1752 arr[n++] = 0xd; /* Temperature */
1753 arr[n++] = 0x2f; /* Informational exceptions */
1754 arr[3] = n - 4;
1755 break;
1756 case 0xd: /* Temperature log page */
1757 arr[3] = resp_temp_l_pg(arr + 4);
1758 break;
1759 case 0x2f: /* Informational exceptions log page */
1760 arr[3] = resp_ie_l_pg(arr + 4);
1761 break;
1762 default:
1763 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1764 INVALID_FIELD_IN_CDB, 0);
1765 return check_condition_result;
1766 }
1767 } else if (0xff == subpcode) {
1768 arr[0] |= 0x40;
1769 arr[1] = subpcode;
1770 switch (pcode) {
1771 case 0x0: /* Supported log pages and subpages log page */
1772 n = 4;
1773 arr[n++] = 0x0;
1774 arr[n++] = 0x0; /* 0,0 page */
1775 arr[n++] = 0x0;
1776 arr[n++] = 0xff; /* this page */
1777 arr[n++] = 0xd;
1778 arr[n++] = 0x0; /* Temperature */
1779 arr[n++] = 0x2f;
1780 arr[n++] = 0x0; /* Informational exceptions */
1781 arr[3] = n - 4;
1782 break;
1783 case 0xd: /* Temperature subpages */
1784 n = 4;
1785 arr[n++] = 0xd;
1786 arr[n++] = 0x0; /* Temperature */
1787 arr[3] = n - 4;
1788 break;
1789 case 0x2f: /* Informational exceptions subpages */
1790 n = 4;
1791 arr[n++] = 0x2f;
1792 arr[n++] = 0x0; /* Informational exceptions */
1793 arr[3] = n - 4;
1794 break;
1795 default:
1796 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1797 INVALID_FIELD_IN_CDB, 0);
1798 return check_condition_result;
1799 }
1800 } else {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001801 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1802 INVALID_FIELD_IN_CDB, 0);
1803 return check_condition_result;
1804 }
1805 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1806 return fill_from_dev_buffer(scp, arr,
1807 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1808}
1809
1810static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
1811 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812{
1813 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001814 unsigned int block, from_bottom;
1815 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 int ret;
1817
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001818 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1820 0);
1821 return check_condition_result;
1822 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001823 /* transfer length excessive (tie in to block limits VPD page) */
1824 if (num > sdebug_store_sectors) {
1825 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1826 0);
1827 return check_condition_result;
1828 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001830 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1831 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1832 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1834 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001835 /* set info field and valid bit for fixed descriptor */
1836 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1837 devip->sense_buff[0] |= 0x80; /* Valid bit */
1838 ret = OPT_MEDIUM_ERR_ADDR;
1839 devip->sense_buff[3] = (ret >> 24) & 0xff;
1840 devip->sense_buff[4] = (ret >> 16) & 0xff;
1841 devip->sense_buff[5] = (ret >> 8) & 0xff;
1842 devip->sense_buff[6] = ret & 0xff;
1843 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 return check_condition_result;
1845 }
1846 read_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001847 if ((lba + num) <= sdebug_store_sectors)
1848 ret = fill_from_dev_buffer(SCpnt,
1849 fake_storep + (lba * SECT_SIZE),
1850 num * SECT_SIZE);
1851 else {
1852 /* modulo when one arg is 64 bits needs do_div() */
1853 u = lba;
1854 block = do_div(u, sdebug_store_sectors);
1855 from_bottom = 0;
1856 if ((block + num) > sdebug_store_sectors)
1857 from_bottom = (block + num) - sdebug_store_sectors;
1858 ret = fill_from_dev_buffer(SCpnt,
1859 fake_storep + (block * SECT_SIZE),
1860 (num - from_bottom) * SECT_SIZE);
1861 if ((0 == ret) && (from_bottom > 0))
1862 ret = fill_from_dev_buffer(SCpnt, fake_storep,
1863 from_bottom * SECT_SIZE);
1864 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 read_unlock_irqrestore(&atomic_rw, iflags);
1866 return ret;
1867}
1868
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001869static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
1870 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871{
1872 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001873 unsigned int block, to_bottom;
1874 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 int res;
1876
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001877 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1879 0);
1880 return check_condition_result;
1881 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001882 /* transfer length excessive (tie in to block limits VPD page) */
1883 if (num > sdebug_store_sectors) {
1884 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1885 0);
1886 return check_condition_result;
1887 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888
1889 write_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001890 if ((lba + num) <= sdebug_store_sectors)
1891 res = fetch_to_dev_buffer(SCpnt,
1892 fake_storep + (lba * SECT_SIZE),
1893 num * SECT_SIZE);
1894 else {
1895 /* modulo when one arg is 64 bits needs do_div() */
1896 u = lba;
1897 block = do_div(u, sdebug_store_sectors);
1898 to_bottom = 0;
1899 if ((block + num) > sdebug_store_sectors)
1900 to_bottom = (block + num) - sdebug_store_sectors;
1901 res = fetch_to_dev_buffer(SCpnt,
1902 fake_storep + (block * SECT_SIZE),
1903 (num - to_bottom) * SECT_SIZE);
1904 if ((0 == res) && (to_bottom > 0))
1905 res = fetch_to_dev_buffer(SCpnt, fake_storep,
1906 to_bottom * SECT_SIZE);
1907 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 write_unlock_irqrestore(&atomic_rw, iflags);
1909 if (-1 == res)
1910 return (DID_ERROR << 16);
1911 else if ((res < (num * SECT_SIZE)) &&
1912 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001913 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 " IO sent=%d bytes\n", num * SECT_SIZE, res);
1915 return 0;
1916}
1917
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001918#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919
1920static int resp_report_luns(struct scsi_cmnd * scp,
1921 struct sdebug_dev_info * devip)
1922{
1923 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001924 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 unsigned char *cmd = (unsigned char *)scp->cmnd;
1926 int select_report = (int)cmd[2];
1927 struct scsi_lun *one_lun;
1928 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001929 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930
1931 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001932 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1934 0);
1935 return check_condition_result;
1936 }
1937 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
1938 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
1939 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001940 if (1 == select_report)
1941 lun_cnt = 0;
1942 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
1943 --lun_cnt;
1944 wlun = (select_report > 0) ? 1 : 0;
1945 num = lun_cnt + wlun;
1946 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
1947 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
1948 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
1949 sizeof(struct scsi_lun)), num);
1950 if (n < num) {
1951 wlun = 0;
1952 lun_cnt = n;
1953 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001955 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
1956 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
1957 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
1958 i++, lun++) {
1959 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 if (upper)
1961 one_lun[i].scsi_lun[0] =
1962 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001963 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001965 if (wlun) {
1966 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
1967 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
1968 i++;
1969 }
1970 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 return fill_from_dev_buffer(scp, arr,
1972 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
1973}
1974
1975/* When timer goes off this function is called. */
1976static void timer_intr_handler(unsigned long indx)
1977{
1978 struct sdebug_queued_cmd * sqcp;
1979 unsigned long iflags;
1980
1981 if (indx >= SCSI_DEBUG_CANQUEUE) {
1982 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
1983 "large\n");
1984 return;
1985 }
1986 spin_lock_irqsave(&queued_arr_lock, iflags);
1987 sqcp = &queued_arr[(int)indx];
1988 if (! sqcp->in_use) {
1989 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
1990 "interrupt\n");
1991 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1992 return;
1993 }
1994 sqcp->in_use = 0;
1995 if (sqcp->done_funct) {
1996 sqcp->a_cmnd->result = sqcp->scsi_result;
1997 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
1998 }
1999 sqcp->done_funct = NULL;
2000 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2001}
2002
2003static int scsi_debug_slave_alloc(struct scsi_device * sdp)
2004{
2005 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002006 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
2007 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 return 0;
2009}
2010
2011static int scsi_debug_slave_configure(struct scsi_device * sdp)
2012{
2013 struct sdebug_dev_info * devip;
2014
2015 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002016 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
2017 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
2019 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
2020 devip = devInfoReg(sdp);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002021 if (NULL == devip)
2022 return 1; /* no resources, will be marked offline */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 sdp->hostdata = devip;
2024 if (sdp->host->cmd_per_lun)
2025 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
2026 sdp->host->cmd_per_lun);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002027 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 return 0;
2029}
2030
2031static void scsi_debug_slave_destroy(struct scsi_device * sdp)
2032{
2033 struct sdebug_dev_info * devip =
2034 (struct sdebug_dev_info *)sdp->hostdata;
2035
2036 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002037 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
2038 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 if (devip) {
2040 /* make this slot avaliable for re-use */
2041 devip->used = 0;
2042 sdp->hostdata = NULL;
2043 }
2044}
2045
2046static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
2047{
2048 struct sdebug_host_info * sdbg_host;
2049 struct sdebug_dev_info * open_devip = NULL;
2050 struct sdebug_dev_info * devip =
2051 (struct sdebug_dev_info *)sdev->hostdata;
2052
2053 if (devip)
2054 return devip;
2055 sdbg_host = *(struct sdebug_host_info **) sdev->host->hostdata;
2056 if(! sdbg_host) {
2057 printk(KERN_ERR "Host info NULL\n");
2058 return NULL;
2059 }
2060 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
2061 if ((devip->used) && (devip->channel == sdev->channel) &&
2062 (devip->target == sdev->id) &&
2063 (devip->lun == sdev->lun))
2064 return devip;
2065 else {
2066 if ((!devip->used) && (!open_devip))
2067 open_devip = devip;
2068 }
2069 }
2070 if (NULL == open_devip) { /* try and make a new one */
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002071 open_devip = kzalloc(sizeof(*open_devip),GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 if (NULL == open_devip) {
2073 printk(KERN_ERR "%s: out of memory at line %d\n",
2074 __FUNCTION__, __LINE__);
2075 return NULL;
2076 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077 open_devip->sdbg_host = sdbg_host;
2078 list_add_tail(&open_devip->dev_list,
2079 &sdbg_host->dev_info_list);
2080 }
2081 if (open_devip) {
2082 open_devip->channel = sdev->channel;
2083 open_devip->target = sdev->id;
2084 open_devip->lun = sdev->lun;
2085 open_devip->sdbg_host = sdbg_host;
2086 open_devip->reset = 1;
2087 open_devip->used = 1;
2088 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
2089 if (scsi_debug_dsense)
2090 open_devip->sense_buff[0] = 0x72;
2091 else {
2092 open_devip->sense_buff[0] = 0x70;
2093 open_devip->sense_buff[7] = 0xa;
2094 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002095 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2096 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 return open_devip;
2098 }
2099 return NULL;
2100}
2101
2102static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
2103 int asc, int asq)
2104{
2105 unsigned char * sbuff;
2106
2107 sbuff = devip->sense_buff;
2108 memset(sbuff, 0, SDEBUG_SENSE_LEN);
2109 if (scsi_debug_dsense) {
2110 sbuff[0] = 0x72; /* descriptor, current */
2111 sbuff[1] = key;
2112 sbuff[2] = asc;
2113 sbuff[3] = asq;
2114 } else {
2115 sbuff[0] = 0x70; /* fixed, current */
2116 sbuff[2] = key;
2117 sbuff[7] = 0xa; /* implies 18 byte sense buffer */
2118 sbuff[12] = asc;
2119 sbuff[13] = asq;
2120 }
2121 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2122 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
2123 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
2124}
2125
2126static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
2127{
2128 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2129 printk(KERN_INFO "scsi_debug: abort\n");
2130 ++num_aborts;
2131 stop_queued_cmnd(SCpnt);
2132 return SUCCESS;
2133}
2134
2135static int scsi_debug_biosparam(struct scsi_device *sdev,
2136 struct block_device * bdev, sector_t capacity, int *info)
2137{
2138 int res;
2139 unsigned char *buf;
2140
2141 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2142 printk(KERN_INFO "scsi_debug: biosparam\n");
2143 buf = scsi_bios_ptable(bdev);
2144 if (buf) {
2145 res = scsi_partsize(buf, capacity,
2146 &info[2], &info[0], &info[1]);
2147 kfree(buf);
2148 if (! res)
2149 return res;
2150 }
2151 info[0] = sdebug_heads;
2152 info[1] = sdebug_sectors_per;
2153 info[2] = sdebug_cylinders_per;
2154 return 0;
2155}
2156
2157static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
2158{
2159 struct sdebug_dev_info * devip;
2160
2161 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2162 printk(KERN_INFO "scsi_debug: device_reset\n");
2163 ++num_dev_resets;
2164 if (SCpnt) {
2165 devip = devInfoReg(SCpnt->device);
2166 if (devip)
2167 devip->reset = 1;
2168 }
2169 return SUCCESS;
2170}
2171
2172static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
2173{
2174 struct sdebug_host_info *sdbg_host;
2175 struct sdebug_dev_info * dev_info;
2176 struct scsi_device * sdp;
2177 struct Scsi_Host * hp;
2178
2179 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2180 printk(KERN_INFO "scsi_debug: bus_reset\n");
2181 ++num_bus_resets;
2182 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
2183 sdbg_host = *(struct sdebug_host_info **) hp->hostdata;
2184 if (sdbg_host) {
2185 list_for_each_entry(dev_info,
2186 &sdbg_host->dev_info_list,
2187 dev_list)
2188 dev_info->reset = 1;
2189 }
2190 }
2191 return SUCCESS;
2192}
2193
2194static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
2195{
2196 struct sdebug_host_info * sdbg_host;
2197 struct sdebug_dev_info * dev_info;
2198
2199 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2200 printk(KERN_INFO "scsi_debug: host_reset\n");
2201 ++num_host_resets;
2202 spin_lock(&sdebug_host_list_lock);
2203 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
2204 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
2205 dev_list)
2206 dev_info->reset = 1;
2207 }
2208 spin_unlock(&sdebug_host_list_lock);
2209 stop_all_queued();
2210 return SUCCESS;
2211}
2212
2213/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
2214static int stop_queued_cmnd(struct scsi_cmnd * cmnd)
2215{
2216 unsigned long iflags;
2217 int k;
2218 struct sdebug_queued_cmd * sqcp;
2219
2220 spin_lock_irqsave(&queued_arr_lock, iflags);
2221 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2222 sqcp = &queued_arr[k];
2223 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
2224 del_timer_sync(&sqcp->cmnd_timer);
2225 sqcp->in_use = 0;
2226 sqcp->a_cmnd = NULL;
2227 break;
2228 }
2229 }
2230 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2231 return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
2232}
2233
2234/* Deletes (stops) timers of all queued commands */
2235static void stop_all_queued(void)
2236{
2237 unsigned long iflags;
2238 int k;
2239 struct sdebug_queued_cmd * sqcp;
2240
2241 spin_lock_irqsave(&queued_arr_lock, iflags);
2242 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2243 sqcp = &queued_arr[k];
2244 if (sqcp->in_use && sqcp->a_cmnd) {
2245 del_timer_sync(&sqcp->cmnd_timer);
2246 sqcp->in_use = 0;
2247 sqcp->a_cmnd = NULL;
2248 }
2249 }
2250 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2251}
2252
2253/* Initializes timers in queued array */
2254static void __init init_all_queued(void)
2255{
2256 unsigned long iflags;
2257 int k;
2258 struct sdebug_queued_cmd * sqcp;
2259
2260 spin_lock_irqsave(&queued_arr_lock, iflags);
2261 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2262 sqcp = &queued_arr[k];
2263 init_timer(&sqcp->cmnd_timer);
2264 sqcp->in_use = 0;
2265 sqcp->a_cmnd = NULL;
2266 }
2267 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2268}
2269
2270static void __init sdebug_build_parts(unsigned char * ramp)
2271{
2272 struct partition * pp;
2273 int starts[SDEBUG_MAX_PARTS + 2];
2274 int sectors_per_part, num_sectors, k;
2275 int heads_by_sects, start_sec, end_sec;
2276
2277 /* assume partition table already zeroed */
2278 if ((scsi_debug_num_parts < 1) || (sdebug_store_size < 1048576))
2279 return;
2280 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
2281 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
2282 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
2283 "partitions to %d\n", SDEBUG_MAX_PARTS);
2284 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002285 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 sectors_per_part = (num_sectors - sdebug_sectors_per)
2287 / scsi_debug_num_parts;
2288 heads_by_sects = sdebug_heads * sdebug_sectors_per;
2289 starts[0] = sdebug_sectors_per;
2290 for (k = 1; k < scsi_debug_num_parts; ++k)
2291 starts[k] = ((k * sectors_per_part) / heads_by_sects)
2292 * heads_by_sects;
2293 starts[scsi_debug_num_parts] = num_sectors;
2294 starts[scsi_debug_num_parts + 1] = 0;
2295
2296 ramp[510] = 0x55; /* magic partition markings */
2297 ramp[511] = 0xAA;
2298 pp = (struct partition *)(ramp + 0x1be);
2299 for (k = 0; starts[k + 1]; ++k, ++pp) {
2300 start_sec = starts[k];
2301 end_sec = starts[k + 1] - 1;
2302 pp->boot_ind = 0;
2303
2304 pp->cyl = start_sec / heads_by_sects;
2305 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2306 / sdebug_sectors_per;
2307 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2308
2309 pp->end_cyl = end_sec / heads_by_sects;
2310 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2311 / sdebug_sectors_per;
2312 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2313
2314 pp->start_sect = start_sec;
2315 pp->nr_sects = end_sec - start_sec + 1;
2316 pp->sys_ind = 0x83; /* plain Linux partition */
2317 }
2318}
2319
2320static int schedule_resp(struct scsi_cmnd * cmnd,
2321 struct sdebug_dev_info * devip,
2322 done_funct_t done, int scsi_result, int delta_jiff)
2323{
2324 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2325 if (scsi_result) {
2326 struct scsi_device * sdp = cmnd->device;
2327
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002328 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2329 "non-zero result=0x%x\n", sdp->host->host_no,
2330 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 }
2332 }
2333 if (cmnd && devip) {
2334 /* simulate autosense by this driver */
2335 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2336 memcpy(cmnd->sense_buffer, devip->sense_buff,
2337 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2338 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2339 }
2340 if (delta_jiff <= 0) {
2341 if (cmnd)
2342 cmnd->result = scsi_result;
2343 if (done)
2344 done(cmnd);
2345 return 0;
2346 } else {
2347 unsigned long iflags;
2348 int k;
2349 struct sdebug_queued_cmd * sqcp = NULL;
2350
2351 spin_lock_irqsave(&queued_arr_lock, iflags);
2352 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2353 sqcp = &queued_arr[k];
2354 if (! sqcp->in_use)
2355 break;
2356 }
2357 if (k >= SCSI_DEBUG_CANQUEUE) {
2358 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2359 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2360 return 1; /* report busy to mid level */
2361 }
2362 sqcp->in_use = 1;
2363 sqcp->a_cmnd = cmnd;
2364 sqcp->scsi_result = scsi_result;
2365 sqcp->done_funct = done;
2366 sqcp->cmnd_timer.function = timer_intr_handler;
2367 sqcp->cmnd_timer.data = k;
2368 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2369 add_timer(&sqcp->cmnd_timer);
2370 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2371 if (cmnd)
2372 cmnd->result = 0;
2373 return 0;
2374 }
2375}
2376
Douglas Gilbert23183912006-09-16 20:30:47 -04002377/* Note: The following macros create attribute files in the
2378 /sys/module/scsi_debug/parameters directory. Unfortunately this
2379 driver is unaware of a change and cannot trigger auxiliary actions
2380 as it can when the corresponding attribute in the
2381 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2382 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002383module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2384module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2385module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2386module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2387module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002388module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002389module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2390module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2391module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2392module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2393module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2394module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2395module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2396module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002397module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2398 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399
2400MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2401MODULE_DESCRIPTION("SCSI debug adapter driver");
2402MODULE_LICENSE("GPL");
2403MODULE_VERSION(SCSI_DEBUG_VERSION);
2404
2405MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2406MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002407MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2408MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409MODULE_PARM_DESC(every_nth, "timeout every nth command(def=100)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002410MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002411MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2412MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002414MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002415MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2417MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002418MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002419MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420
2421
2422static char sdebug_info[256];
2423
2424static const char * scsi_debug_info(struct Scsi_Host * shp)
2425{
2426 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2427 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2428 scsi_debug_version_date, scsi_debug_dev_size_mb,
2429 scsi_debug_opts);
2430 return sdebug_info;
2431}
2432
2433/* scsi_debug_proc_info
2434 * Used if the driver currently has no own support for /proc/scsi
2435 */
2436static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2437 int length, int inout)
2438{
2439 int len, pos, begin;
2440 int orig_length;
2441
2442 orig_length = length;
2443
2444 if (inout == 1) {
2445 char arr[16];
2446 int minLen = length > 15 ? 15 : length;
2447
2448 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2449 return -EACCES;
2450 memcpy(arr, buffer, minLen);
2451 arr[minLen] = '\0';
2452 if (1 != sscanf(arr, "%d", &pos))
2453 return -EINVAL;
2454 scsi_debug_opts = pos;
2455 if (scsi_debug_every_nth != 0)
2456 scsi_debug_cmnd_count = 0;
2457 return length;
2458 }
2459 begin = 0;
2460 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2461 "%s [%s]\n"
2462 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2463 "every_nth=%d(curr:%d)\n"
2464 "delay=%d, max_luns=%d, scsi_level=%d\n"
2465 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2466 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
2467 "host_resets=%d\n",
2468 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2469 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2470 scsi_debug_cmnd_count, scsi_debug_delay,
2471 scsi_debug_max_luns, scsi_debug_scsi_level,
2472 SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
2473 num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
2474 if (pos < offset) {
2475 len = 0;
2476 begin = pos;
2477 }
2478 *start = buffer + (offset - begin); /* Start of wanted data */
2479 len -= (offset - begin);
2480 if (len > length)
2481 len = length;
2482 return len;
2483}
2484
2485static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2486{
2487 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2488}
2489
2490static ssize_t sdebug_delay_store(struct device_driver * ddp,
2491 const char * buf, size_t count)
2492{
2493 int delay;
2494 char work[20];
2495
2496 if (1 == sscanf(buf, "%10s", work)) {
2497 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2498 scsi_debug_delay = delay;
2499 return count;
2500 }
2501 }
2502 return -EINVAL;
2503}
2504DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2505 sdebug_delay_store);
2506
2507static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2508{
2509 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2510}
2511
2512static ssize_t sdebug_opts_store(struct device_driver * ddp,
2513 const char * buf, size_t count)
2514{
2515 int opts;
2516 char work[20];
2517
2518 if (1 == sscanf(buf, "%10s", work)) {
2519 if (0 == strnicmp(work,"0x", 2)) {
2520 if (1 == sscanf(&work[2], "%x", &opts))
2521 goto opts_done;
2522 } else {
2523 if (1 == sscanf(work, "%d", &opts))
2524 goto opts_done;
2525 }
2526 }
2527 return -EINVAL;
2528opts_done:
2529 scsi_debug_opts = opts;
2530 scsi_debug_cmnd_count = 0;
2531 return count;
2532}
2533DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2534 sdebug_opts_store);
2535
2536static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2537{
2538 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2539}
2540static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2541 const char * buf, size_t count)
2542{
2543 int n;
2544
2545 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2546 scsi_debug_ptype = n;
2547 return count;
2548 }
2549 return -EINVAL;
2550}
2551DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2552
2553static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2554{
2555 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2556}
2557static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2558 const char * buf, size_t count)
2559{
2560 int n;
2561
2562 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2563 scsi_debug_dsense = n;
2564 return count;
2565 }
2566 return -EINVAL;
2567}
2568DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2569 sdebug_dsense_store);
2570
Douglas Gilbert23183912006-09-16 20:30:47 -04002571static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2572{
2573 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2574}
2575static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2576 const char * buf, size_t count)
2577{
2578 int n;
2579
2580 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2581 scsi_debug_fake_rw = n;
2582 return count;
2583 }
2584 return -EINVAL;
2585}
2586DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2587 sdebug_fake_rw_store);
2588
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002589static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2590{
2591 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2592}
2593static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2594 const char * buf, size_t count)
2595{
2596 int n;
2597
2598 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2599 scsi_debug_no_lun_0 = n;
2600 return count;
2601 }
2602 return -EINVAL;
2603}
2604DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2605 sdebug_no_lun_0_store);
2606
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2608{
2609 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2610}
2611static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2612 const char * buf, size_t count)
2613{
2614 int n;
2615
2616 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2617 scsi_debug_num_tgts = n;
2618 sdebug_max_tgts_luns();
2619 return count;
2620 }
2621 return -EINVAL;
2622}
2623DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2624 sdebug_num_tgts_store);
2625
2626static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2627{
2628 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2629}
2630DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2631
2632static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2633{
2634 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2635}
2636DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2637
2638static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2639{
2640 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2641}
2642static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2643 const char * buf, size_t count)
2644{
2645 int nth;
2646
2647 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2648 scsi_debug_every_nth = nth;
2649 scsi_debug_cmnd_count = 0;
2650 return count;
2651 }
2652 return -EINVAL;
2653}
2654DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2655 sdebug_every_nth_store);
2656
2657static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2658{
2659 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2660}
2661static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2662 const char * buf, size_t count)
2663{
2664 int n;
2665
2666 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2667 scsi_debug_max_luns = n;
2668 sdebug_max_tgts_luns();
2669 return count;
2670 }
2671 return -EINVAL;
2672}
2673DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2674 sdebug_max_luns_store);
2675
2676static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
2677{
2678 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
2679}
2680DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
2681
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002682static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2683{
2684 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2685}
2686static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2687 const char * buf, size_t count)
2688{
2689 int n;
2690
2691 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2692 scsi_debug_virtual_gb = n;
2693 if (scsi_debug_virtual_gb > 0) {
2694 sdebug_capacity = 2048 * 1024;
2695 sdebug_capacity *= scsi_debug_virtual_gb;
2696 } else
2697 sdebug_capacity = sdebug_store_sectors;
2698 return count;
2699 }
2700 return -EINVAL;
2701}
2702DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2703 sdebug_virtual_gb_store);
2704
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
2706{
2707 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
2708}
2709
2710static ssize_t sdebug_add_host_store(struct device_driver * ddp,
2711 const char * buf, size_t count)
2712{
2713 int delta_hosts;
2714 char work[20];
2715
2716 if (1 != sscanf(buf, "%10s", work))
2717 return -EINVAL;
2718 { /* temporary hack around sscanf() problem with -ve nums */
2719 int neg = 0;
2720
2721 if ('-' == *work)
2722 neg = 1;
2723 if (1 != sscanf(work + neg, "%d", &delta_hosts))
2724 return -EINVAL;
2725 if (neg)
2726 delta_hosts = -delta_hosts;
2727 }
2728 if (delta_hosts > 0) {
2729 do {
2730 sdebug_add_adapter();
2731 } while (--delta_hosts);
2732 } else if (delta_hosts < 0) {
2733 do {
2734 sdebug_remove_adapter();
2735 } while (++delta_hosts);
2736 }
2737 return count;
2738}
2739DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
2740 sdebug_add_host_store);
2741
Douglas Gilbert23183912006-09-16 20:30:47 -04002742static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
2743 char * buf)
2744{
2745 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
2746}
2747static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
2748 const char * buf, size_t count)
2749{
2750 int n;
2751
2752 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2753 scsi_debug_vpd_use_hostno = n;
2754 return count;
2755 }
2756 return -EINVAL;
2757}
2758DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
2759 sdebug_vpd_use_hostno_store);
2760
2761/* Note: The following function creates attribute files in the
2762 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
2763 files (over those found in the /sys/module/scsi_debug/parameters
2764 directory) is that auxiliary actions can be triggered when an attribute
2765 is changed. For example see: sdebug_add_host_store() above.
2766 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002767static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002769 int ret;
2770
2771 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2772 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
2773 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2774 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2775 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04002776 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002777 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002778 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002779 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002780 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002781 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
2782 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
2783 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04002784 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
2785 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002786 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787}
2788
2789static void do_remove_driverfs_files(void)
2790{
Douglas Gilbert23183912006-09-16 20:30:47 -04002791 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
2792 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
2794 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
2795 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002797 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
2798 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002800 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
2802 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2803 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2804 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
2805 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2806}
2807
2808static int __init scsi_debug_init(void)
2809{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002810 unsigned int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 int host_to_add;
2812 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002813 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814
2815 if (scsi_debug_dev_size_mb < 1)
2816 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002817 sdebug_store_size = (unsigned int)scsi_debug_dev_size_mb * 1048576;
2818 sdebug_store_sectors = sdebug_store_size / SECT_SIZE;
2819 if (scsi_debug_virtual_gb > 0) {
2820 sdebug_capacity = 2048 * 1024;
2821 sdebug_capacity *= scsi_debug_virtual_gb;
2822 } else
2823 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824
2825 /* play around with geometry, don't waste too much on track 0 */
2826 sdebug_heads = 8;
2827 sdebug_sectors_per = 32;
2828 if (scsi_debug_dev_size_mb >= 16)
2829 sdebug_heads = 32;
2830 else if (scsi_debug_dev_size_mb >= 256)
2831 sdebug_heads = 64;
2832 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2833 (sdebug_sectors_per * sdebug_heads);
2834 if (sdebug_cylinders_per >= 1024) {
2835 /* other LLDs do this; implies >= 1GB ram disk ... */
2836 sdebug_heads = 255;
2837 sdebug_sectors_per = 63;
2838 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2839 (sdebug_sectors_per * sdebug_heads);
2840 }
2841
2842 sz = sdebug_store_size;
2843 fake_storep = vmalloc(sz);
2844 if (NULL == fake_storep) {
2845 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
2846 return -ENOMEM;
2847 }
2848 memset(fake_storep, 0, sz);
2849 if (scsi_debug_num_parts > 0)
2850 sdebug_build_parts(fake_storep);
2851
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002852 ret = device_register(&pseudo_primary);
2853 if (ret < 0) {
2854 printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
2855 ret);
2856 goto free_vm;
2857 }
2858 ret = bus_register(&pseudo_lld_bus);
2859 if (ret < 0) {
2860 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
2861 ret);
2862 goto dev_unreg;
2863 }
2864 ret = driver_register(&sdebug_driverfs_driver);
2865 if (ret < 0) {
2866 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
2867 ret);
2868 goto bus_unreg;
2869 }
2870 ret = do_create_driverfs_files();
2871 if (ret < 0) {
2872 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
2873 ret);
2874 goto del_files;
2875 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002877 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878
2879 sdebug_driver_template.proc_name = (char *)sdebug_proc_name;
2880
2881 host_to_add = scsi_debug_add_host;
2882 scsi_debug_add_host = 0;
2883
2884 for (k = 0; k < host_to_add; k++) {
2885 if (sdebug_add_adapter()) {
2886 printk(KERN_ERR "scsi_debug_init: "
2887 "sdebug_add_adapter failed k=%d\n", k);
2888 break;
2889 }
2890 }
2891
2892 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
2893 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
2894 scsi_debug_add_host);
2895 }
2896 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002897
2898del_files:
2899 do_remove_driverfs_files();
2900 driver_unregister(&sdebug_driverfs_driver);
2901bus_unreg:
2902 bus_unregister(&pseudo_lld_bus);
2903dev_unreg:
2904 device_unregister(&pseudo_primary);
2905free_vm:
2906 vfree(fake_storep);
2907
2908 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909}
2910
2911static void __exit scsi_debug_exit(void)
2912{
2913 int k = scsi_debug_add_host;
2914
2915 stop_all_queued();
2916 for (; k; k--)
2917 sdebug_remove_adapter();
2918 do_remove_driverfs_files();
2919 driver_unregister(&sdebug_driverfs_driver);
2920 bus_unregister(&pseudo_lld_bus);
2921 device_unregister(&pseudo_primary);
2922
2923 vfree(fake_storep);
2924}
2925
2926device_initcall(scsi_debug_init);
2927module_exit(scsi_debug_exit);
2928
Adrian Bunk52c1da32005-06-23 22:05:33 -07002929static void pseudo_0_release(struct device * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930{
2931 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2932 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
2933}
2934
2935static struct device pseudo_primary = {
2936 .bus_id = "pseudo_0",
2937 .release = pseudo_0_release,
2938};
2939
2940static int pseudo_lld_bus_match(struct device *dev,
2941 struct device_driver *dev_driver)
2942{
2943 return 1;
2944}
2945
2946static struct bus_type pseudo_lld_bus = {
2947 .name = "pseudo",
2948 .match = pseudo_lld_bus_match,
Russell Kingbbbe3a42006-01-05 14:44:46 +00002949 .probe = sdebug_driver_probe,
2950 .remove = sdebug_driver_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951};
2952
2953static void sdebug_release_adapter(struct device * dev)
2954{
2955 struct sdebug_host_info *sdbg_host;
2956
2957 sdbg_host = to_sdebug_host(dev);
2958 kfree(sdbg_host);
2959}
2960
2961static int sdebug_add_adapter(void)
2962{
2963 int k, devs_per_host;
2964 int error = 0;
2965 struct sdebug_host_info *sdbg_host;
2966 struct sdebug_dev_info *sdbg_devinfo;
2967 struct list_head *lh, *lh_sf;
2968
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002969 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 if (NULL == sdbg_host) {
2971 printk(KERN_ERR "%s: out of memory at line %d\n",
2972 __FUNCTION__, __LINE__);
2973 return -ENOMEM;
2974 }
2975
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
2977
2978 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
2979 for (k = 0; k < devs_per_host; k++) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002980 sdbg_devinfo = kzalloc(sizeof(*sdbg_devinfo),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 if (NULL == sdbg_devinfo) {
2982 printk(KERN_ERR "%s: out of memory at line %d\n",
2983 __FUNCTION__, __LINE__);
2984 error = -ENOMEM;
2985 goto clean;
2986 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 sdbg_devinfo->sdbg_host = sdbg_host;
2988 list_add_tail(&sdbg_devinfo->dev_list,
2989 &sdbg_host->dev_info_list);
2990 }
2991
2992 spin_lock(&sdebug_host_list_lock);
2993 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
2994 spin_unlock(&sdebug_host_list_lock);
2995
2996 sdbg_host->dev.bus = &pseudo_lld_bus;
2997 sdbg_host->dev.parent = &pseudo_primary;
2998 sdbg_host->dev.release = &sdebug_release_adapter;
2999 sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host);
3000
3001 error = device_register(&sdbg_host->dev);
3002
3003 if (error)
3004 goto clean;
3005
3006 ++scsi_debug_add_host;
3007 return error;
3008
3009clean:
3010 list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) {
3011 sdbg_devinfo = list_entry(lh, struct sdebug_dev_info,
3012 dev_list);
3013 list_del(&sdbg_devinfo->dev_list);
3014 kfree(sdbg_devinfo);
3015 }
3016
3017 kfree(sdbg_host);
3018 return error;
3019}
3020
3021static void sdebug_remove_adapter(void)
3022{
3023 struct sdebug_host_info * sdbg_host = NULL;
3024
3025 spin_lock(&sdebug_host_list_lock);
3026 if (!list_empty(&sdebug_host_list)) {
3027 sdbg_host = list_entry(sdebug_host_list.prev,
3028 struct sdebug_host_info, host_list);
3029 list_del(&sdbg_host->host_list);
3030 }
3031 spin_unlock(&sdebug_host_list_lock);
3032
3033 if (!sdbg_host)
3034 return;
3035
3036 device_unregister(&sdbg_host->dev);
3037 --scsi_debug_add_host;
3038}
3039
3040static int sdebug_driver_probe(struct device * dev)
3041{
3042 int error = 0;
3043 struct sdebug_host_info *sdbg_host;
3044 struct Scsi_Host *hpnt;
3045
3046 sdbg_host = to_sdebug_host(dev);
3047
3048 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
3049 if (NULL == hpnt) {
3050 printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__);
3051 error = -ENODEV;
3052 return error;
3053 }
3054
3055 sdbg_host->shost = hpnt;
3056 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
3057 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
3058 hpnt->max_id = scsi_debug_num_tgts + 1;
3059 else
3060 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003061 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062
3063 error = scsi_add_host(hpnt, &sdbg_host->dev);
3064 if (error) {
3065 printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
3066 error = -ENODEV;
3067 scsi_host_put(hpnt);
3068 } else
3069 scsi_scan_host(hpnt);
3070
3071
3072 return error;
3073}
3074
3075static int sdebug_driver_remove(struct device * dev)
3076{
3077 struct list_head *lh, *lh_sf;
3078 struct sdebug_host_info *sdbg_host;
3079 struct sdebug_dev_info *sdbg_devinfo;
3080
3081 sdbg_host = to_sdebug_host(dev);
3082
3083 if (!sdbg_host) {
3084 printk(KERN_ERR "%s: Unable to locate host info\n",
3085 __FUNCTION__);
3086 return -ENODEV;
3087 }
3088
3089 scsi_remove_host(sdbg_host->shost);
3090
3091 list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) {
3092 sdbg_devinfo = list_entry(lh, struct sdebug_dev_info,
3093 dev_list);
3094 list_del(&sdbg_devinfo->dev_list);
3095 kfree(sdbg_devinfo);
3096 }
3097
3098 scsi_host_put(sdbg_host->shost);
3099 return 0;
3100}
3101
3102static void sdebug_max_tgts_luns(void)
3103{
3104 struct sdebug_host_info * sdbg_host;
3105 struct Scsi_Host *hpnt;
3106
3107 spin_lock(&sdebug_host_list_lock);
3108 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3109 hpnt = sdbg_host->shost;
3110 if ((hpnt->this_id >= 0) &&
3111 (scsi_debug_num_tgts > hpnt->this_id))
3112 hpnt->max_id = scsi_debug_num_tgts + 1;
3113 else
3114 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003115 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 }
3117 spin_unlock(&sdebug_host_list_lock);
3118}