blob: 4cd9c58efef12007f208dd0bf07710cd87313cce [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3 * Copyright (C) 1992 Eric Youngdale
4 * Simulate a host adapter with 2 disks attached. Do a lot of checking
5 * to make sure that we are not getting blocks mixed up, and PANIC if
6 * anything out of the ordinary is seen.
7 * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8 *
9 * This version is more generic, simulating a variable number of disk
Douglas Gilbert23183912006-09-16 20:30:47 -040010 * (or disk like devices) sharing a common amount of RAM. To be more
11 * realistic, the simulated devices have the transport attributes of
12 * SAS disks.
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 *
14 *
15 * For documentation see http://www.torque.net/sg/sdebug26.html
16 *
17 * D. Gilbert (dpg) work for Magneto-Optical device test [20010421]
18 * dpg: work for devfs large number of disks [20010809]
19 * forked for lk 2.5 series [20011216, 20020101]
20 * use vmalloc() more inquiry+mode_sense [20020302]
21 * add timers for delayed responses [20020721]
22 * Patrick Mansfield <patmans@us.ibm.com> max_luns+scsi_level [20021031]
23 * Mike Anderson <andmike@us.ibm.com> sysfs work [20021118]
24 * dpg: change style of boot options to "scsi_debug.num_tgts=2" and
25 * module options to "modprobe scsi_debug num_tgts=2" [20021221]
26 */
27
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/module.h>
29
30#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/errno.h>
32#include <linux/timer.h>
33#include <linux/types.h>
34#include <linux/string.h>
35#include <linux/genhd.h>
36#include <linux/fs.h>
37#include <linux/init.h>
38#include <linux/proc_fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <linux/vmalloc.h>
40#include <linux/moduleparam.h>
41
42#include <linux/blkdev.h>
43#include "scsi.h"
44#include <scsi/scsi_host.h>
45#include <scsi/scsicam.h>
46
47#include <linux/stat.h>
48
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include "scsi_logging.h"
50#include "scsi_debug.h"
51
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050052#define SCSI_DEBUG_VERSION "1.81"
53static const char * scsi_debug_version_date = "20070104";
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050055/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040056#define NO_ADDITIONAL_SENSE 0x0
57#define LOGICAL_UNIT_NOT_READY 0x4
Linus Torvalds1da177e2005-04-16 15:20:36 -070058#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040059#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#define INVALID_OPCODE 0x20
61#define ADDR_OUT_OF_RANGE 0x21
62#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040063#define INVALID_FIELD_IN_PARAM_LIST 0x26
Linus Torvalds1da177e2005-04-16 15:20:36 -070064#define POWERON_RESET 0x29
65#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050066#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040067#define THRESHOLD_EXCEEDED 0x5d
68#define LOW_POWER_COND_ON 0x5e
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050070/* Additional Sense Code Qualifier (ASCQ) */
71#define ACK_NAK_TO 0x3
72
Linus Torvalds1da177e2005-04-16 15:20:36 -070073#define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
74
75/* Default values for driver parameters */
76#define DEF_NUM_HOST 1
77#define DEF_NUM_TGTS 1
78#define DEF_MAX_LUNS 1
79/* With these defaults, this driver will make 1 host with 1 target
80 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
81 */
82#define DEF_DELAY 1
83#define DEF_DEV_SIZE_MB 8
84#define DEF_EVERY_NTH 0
85#define DEF_NUM_PARTS 0
86#define DEF_OPTS 0
87#define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */
88#define DEF_PTYPE 0
89#define DEF_D_SENSE 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -040090#define DEF_NO_LUN_0 0
91#define DEF_VIRTUAL_GB 0
Douglas Gilbert23183912006-09-16 20:30:47 -040092#define DEF_FAKE_RW 0
93#define DEF_VPD_USE_HOSTNO 1
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
95/* bit mask values for scsi_debug_opts */
96#define SCSI_DEBUG_OPT_NOISE 1
97#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
98#define SCSI_DEBUG_OPT_TIMEOUT 4
99#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500100#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101/* When "every_nth" > 0 then modulo "every_nth" commands:
102 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
103 * - a RECOVERED_ERROR is simulated on successful read and write
104 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500105 * - a TRANSPORT_ERROR is simulated on successful read and write
106 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 *
108 * When "every_nth" < 0 then after "- every_nth" commands:
109 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
110 * - a RECOVERED_ERROR is simulated on successful read and write
111 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500112 * - a TRANSPORT_ERROR is simulated on successful read and write
113 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 * This will continue until some other action occurs (e.g. the user
115 * writing a new value (other than -1 or 1) to every_nth via sysfs).
116 */
117
118/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
119 * sector on read commands: */
120#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
121
122/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
123 * or "peripheral device" addressing (value 0) */
124#define SAM2_LUN_ADDRESS_METHOD 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400125#define SAM2_WLUN_REPORT_LUNS 0xc101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
127static int scsi_debug_add_host = DEF_NUM_HOST;
128static int scsi_debug_delay = DEF_DELAY;
129static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
130static int scsi_debug_every_nth = DEF_EVERY_NTH;
131static int scsi_debug_max_luns = DEF_MAX_LUNS;
132static int scsi_debug_num_parts = DEF_NUM_PARTS;
133static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
134static int scsi_debug_opts = DEF_OPTS;
135static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
136static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
137static int scsi_debug_dsense = DEF_D_SENSE;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400138static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
139static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
Douglas Gilbert23183912006-09-16 20:30:47 -0400140static int scsi_debug_fake_rw = DEF_FAKE_RW;
141static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
143static int scsi_debug_cmnd_count = 0;
144
145#define DEV_READONLY(TGT) (0)
146#define DEV_REMOVEABLE(TGT) (0)
147
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400148static unsigned int sdebug_store_size; /* in bytes */
149static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150static sector_t sdebug_capacity; /* in sectors */
151
152/* old BIOS stuff, kernel may get rid of them but some mode sense pages
153 may still need them */
154static int sdebug_heads; /* heads per disk */
155static int sdebug_cylinders_per; /* cylinders per surface */
156static int sdebug_sectors_per; /* sectors per cylinder */
157
158/* default sector size is 512 bytes, 2**9 bytes */
159#define POW2_SECT_SIZE 9
160#define SECT_SIZE (1 << POW2_SECT_SIZE)
161#define SECT_SIZE_PER(TGT) SECT_SIZE
162
163#define SDEBUG_MAX_PARTS 4
164
165#define SDEBUG_SENSE_LEN 32
166
167struct sdebug_dev_info {
168 struct list_head dev_list;
169 unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */
170 unsigned int channel;
171 unsigned int target;
172 unsigned int lun;
173 struct sdebug_host_info *sdbg_host;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400174 unsigned int wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 char reset;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400176 char stopped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 char used;
178};
179
180struct sdebug_host_info {
181 struct list_head host_list;
182 struct Scsi_Host *shost;
183 struct device dev;
184 struct list_head dev_info_list;
185};
186
187#define to_sdebug_host(d) \
188 container_of(d, struct sdebug_host_info, dev)
189
190static LIST_HEAD(sdebug_host_list);
191static DEFINE_SPINLOCK(sdebug_host_list_lock);
192
193typedef void (* done_funct_t) (struct scsi_cmnd *);
194
195struct sdebug_queued_cmd {
196 int in_use;
197 struct timer_list cmnd_timer;
198 done_funct_t done_funct;
199 struct scsi_cmnd * a_cmnd;
200 int scsi_result;
201};
202static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
203
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +0100204static struct scsi_host_template sdebug_driver_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 .proc_info = scsi_debug_proc_info,
206 .name = "SCSI DEBUG",
207 .info = scsi_debug_info,
208 .slave_alloc = scsi_debug_slave_alloc,
209 .slave_configure = scsi_debug_slave_configure,
210 .slave_destroy = scsi_debug_slave_destroy,
211 .ioctl = scsi_debug_ioctl,
212 .queuecommand = scsi_debug_queuecommand,
213 .eh_abort_handler = scsi_debug_abort,
214 .eh_bus_reset_handler = scsi_debug_bus_reset,
215 .eh_device_reset_handler = scsi_debug_device_reset,
216 .eh_host_reset_handler = scsi_debug_host_reset,
217 .bios_param = scsi_debug_biosparam,
218 .can_queue = SCSI_DEBUG_CANQUEUE,
219 .this_id = 7,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400220 .sg_tablesize = 256,
221 .cmd_per_lun = 16,
222 .max_sectors = 0xffff,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 .unchecked_isa_dma = 0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400224 .use_clustering = ENABLE_CLUSTERING,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 .module = THIS_MODULE,
226};
227
228static unsigned char * fake_storep; /* ramdisk storage */
229
230static int num_aborts = 0;
231static int num_dev_resets = 0;
232static int num_bus_resets = 0;
233static int num_host_resets = 0;
234
235static DEFINE_SPINLOCK(queued_arr_lock);
236static DEFINE_RWLOCK(atomic_rw);
237
238static char sdebug_proc_name[] = "scsi_debug";
239
240static int sdebug_driver_probe(struct device *);
241static int sdebug_driver_remove(struct device *);
242static struct bus_type pseudo_lld_bus;
243
244static struct device_driver sdebug_driverfs_driver = {
245 .name = sdebug_proc_name,
246 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247};
248
249static const int check_condition_result =
250 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
251
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400252static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
253 0, 0, 0x2, 0x4b};
254static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
255 0, 0, 0x0, 0x0};
256
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257/* function declarations */
258static int resp_inquiry(struct scsi_cmnd * SCpnt, int target,
259 struct sdebug_dev_info * devip);
260static int resp_requests(struct scsi_cmnd * SCpnt,
261 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400262static int resp_start_stop(struct scsi_cmnd * scp,
263 struct sdebug_dev_info * devip);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200264static int resp_report_tgtpgs(struct scsi_cmnd * scp,
265 struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266static int resp_readcap(struct scsi_cmnd * SCpnt,
267 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400268static int resp_readcap16(struct scsi_cmnd * SCpnt,
269 struct sdebug_dev_info * devip);
270static int resp_mode_sense(struct scsi_cmnd * scp, int target,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400272static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
273 struct sdebug_dev_info * devip);
274static int resp_log_sense(struct scsi_cmnd * scp,
275 struct sdebug_dev_info * devip);
276static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
277 unsigned int num, struct sdebug_dev_info * devip);
278static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
279 unsigned int num, struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280static int resp_report_luns(struct scsi_cmnd * SCpnt,
281 struct sdebug_dev_info * devip);
282static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
283 int arr_len);
284static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
285 int max_arr_len);
286static void timer_intr_handler(unsigned long);
287static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev);
288static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
289 int asc, int asq);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400290static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
291 struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292static int schedule_resp(struct scsi_cmnd * cmnd,
293 struct sdebug_dev_info * devip,
294 done_funct_t done, int scsi_result, int delta_jiff);
295static void __init sdebug_build_parts(unsigned char * ramp);
296static void __init init_all_queued(void);
297static void stop_all_queued(void);
298static int stop_queued_cmnd(struct scsi_cmnd * cmnd);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200299static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
300 int target_dev_id, int dev_id_num,
301 const char * dev_id_str, int dev_id_str_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400302static int inquiry_evpd_88(unsigned char * arr, int target_dev_id);
Randy Dunlap6ecaff72006-07-11 20:53:22 -0700303static int do_create_driverfs_files(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304static void do_remove_driverfs_files(void);
305
306static int sdebug_add_adapter(void);
307static void sdebug_remove_adapter(void);
308static void sdebug_max_tgts_luns(void);
309
310static struct device pseudo_primary;
311static struct bus_type pseudo_lld_bus;
312
313
314static
315int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
316{
317 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400318 int len, k, j;
319 unsigned int num;
320 unsigned long long lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 int errsts = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400322 int target = SCpnt->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 struct sdebug_dev_info * devip = NULL;
324 int inj_recovered = 0;
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500325 int inj_transport = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400326 int delay_override = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
328 if (done == NULL)
329 return 0; /* assume mid level reprocessing command */
330
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400331 SCpnt->resid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
333 printk(KERN_INFO "scsi_debug: cmd ");
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400334 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 printk("%02x ", (int)cmd[k]);
336 printk("\n");
337 }
338 if(target == sdebug_driver_template.this_id) {
339 printk(KERN_INFO "scsi_debug: initiator's id used as "
340 "target!\n");
341 return schedule_resp(SCpnt, NULL, done,
342 DID_NO_CONNECT << 16, 0);
343 }
344
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400345 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
346 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 return schedule_resp(SCpnt, NULL, done,
348 DID_NO_CONNECT << 16, 0);
349 devip = devInfoReg(SCpnt->device);
350 if (NULL == devip)
351 return schedule_resp(SCpnt, NULL, done,
352 DID_NO_CONNECT << 16, 0);
353
354 if ((scsi_debug_every_nth != 0) &&
355 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
356 scsi_debug_cmnd_count = 0;
357 if (scsi_debug_every_nth < -1)
358 scsi_debug_every_nth = -1;
359 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
360 return 0; /* ignore command causing timeout */
361 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
362 inj_recovered = 1; /* to reads and writes below */
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500363 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
364 inj_transport = 1; /* to reads and writes below */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 }
366
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400367 if (devip->wlun) {
368 switch (*cmd) {
369 case INQUIRY:
370 case REQUEST_SENSE:
371 case TEST_UNIT_READY:
372 case REPORT_LUNS:
373 break; /* only allowable wlun commands */
374 default:
375 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
376 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
377 "not supported for wlun\n", *cmd);
378 mk_sense_buffer(devip, ILLEGAL_REQUEST,
379 INVALID_OPCODE, 0);
380 errsts = check_condition_result;
381 return schedule_resp(SCpnt, devip, done, errsts,
382 0);
383 }
384 }
385
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 switch (*cmd) {
387 case INQUIRY: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400388 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 errsts = resp_inquiry(SCpnt, target, devip);
390 break;
391 case REQUEST_SENSE: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400392 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 errsts = resp_requests(SCpnt, devip);
394 break;
395 case REZERO_UNIT: /* actually this is REWIND for SSC */
396 case START_STOP:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400397 errsts = resp_start_stop(SCpnt, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 break;
399 case ALLOW_MEDIUM_REMOVAL:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400400 if ((errsts = check_readiness(SCpnt, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 break;
402 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
403 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
404 cmd[4] ? "inhibited" : "enabled");
405 break;
406 case SEND_DIAGNOSTIC: /* mandatory */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400407 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 break;
409 case TEST_UNIT_READY: /* mandatory */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400410 delay_override = 1;
411 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 break;
413 case RESERVE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400414 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 break;
416 case RESERVE_10:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400417 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 break;
419 case RELEASE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400420 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 break;
422 case RELEASE_10:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400423 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 break;
425 case READ_CAPACITY:
426 errsts = resp_readcap(SCpnt, devip);
427 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400428 case SERVICE_ACTION_IN:
429 if (SAI_READ_CAPACITY_16 != cmd[1]) {
430 mk_sense_buffer(devip, ILLEGAL_REQUEST,
431 INVALID_OPCODE, 0);
432 errsts = check_condition_result;
433 break;
434 }
435 errsts = resp_readcap16(SCpnt, devip);
436 break;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200437 case MAINTENANCE_IN:
438 if (MI_REPORT_TARGET_PGS != cmd[1]) {
439 mk_sense_buffer(devip, ILLEGAL_REQUEST,
440 INVALID_OPCODE, 0);
441 errsts = check_condition_result;
442 break;
443 }
444 errsts = resp_report_tgtpgs(SCpnt, devip);
445 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 case READ_16:
447 case READ_12:
448 case READ_10:
449 case READ_6:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400450 if ((errsts = check_readiness(SCpnt, 0, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 break;
Douglas Gilbert23183912006-09-16 20:30:47 -0400452 if (scsi_debug_fake_rw)
453 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 if ((*cmd) == READ_16) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400455 for (lba = 0, j = 0; j < 8; ++j) {
456 if (j > 0)
457 lba <<= 8;
458 lba += cmd[2 + j];
459 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 num = cmd[13] + (cmd[12] << 8) +
461 (cmd[11] << 16) + (cmd[10] << 24);
462 } else if ((*cmd) == READ_12) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400463 lba = cmd[5] + (cmd[4] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 (cmd[3] << 16) + (cmd[2] << 24);
465 num = cmd[9] + (cmd[8] << 8) +
466 (cmd[7] << 16) + (cmd[6] << 24);
467 } else if ((*cmd) == READ_10) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400468 lba = cmd[5] + (cmd[4] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 (cmd[3] << 16) + (cmd[2] << 24);
470 num = cmd[8] + (cmd[7] << 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400471 } else { /* READ (6) */
472 lba = cmd[3] + (cmd[2] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 ((cmd[1] & 0x1f) << 16);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400474 num = (0 == cmd[4]) ? 256 : cmd[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400476 errsts = resp_read(SCpnt, lba, num, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 if (inj_recovered && (0 == errsts)) {
478 mk_sense_buffer(devip, RECOVERED_ERROR,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400479 THRESHOLD_EXCEEDED, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 errsts = check_condition_result;
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500481 } else if (inj_transport && (0 == errsts)) {
482 mk_sense_buffer(devip, ABORTED_COMMAND,
483 TRANSPORT_PROBLEM, ACK_NAK_TO);
484 errsts = check_condition_result;
485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 break;
487 case REPORT_LUNS: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400488 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 errsts = resp_report_luns(SCpnt, devip);
490 break;
491 case VERIFY: /* 10 byte SBC-2 command */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400492 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 break;
494 case WRITE_16:
495 case WRITE_12:
496 case WRITE_10:
497 case WRITE_6:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400498 if ((errsts = check_readiness(SCpnt, 0, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 break;
Douglas Gilbert23183912006-09-16 20:30:47 -0400500 if (scsi_debug_fake_rw)
501 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 if ((*cmd) == WRITE_16) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400503 for (lba = 0, j = 0; j < 8; ++j) {
504 if (j > 0)
505 lba <<= 8;
506 lba += cmd[2 + j];
507 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 num = cmd[13] + (cmd[12] << 8) +
509 (cmd[11] << 16) + (cmd[10] << 24);
510 } else if ((*cmd) == WRITE_12) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400511 lba = cmd[5] + (cmd[4] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 (cmd[3] << 16) + (cmd[2] << 24);
513 num = cmd[9] + (cmd[8] << 8) +
514 (cmd[7] << 16) + (cmd[6] << 24);
515 } else if ((*cmd) == WRITE_10) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400516 lba = cmd[5] + (cmd[4] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 (cmd[3] << 16) + (cmd[2] << 24);
518 num = cmd[8] + (cmd[7] << 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400519 } else { /* WRITE (6) */
520 lba = cmd[3] + (cmd[2] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 ((cmd[1] & 0x1f) << 16);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400522 num = (0 == cmd[4]) ? 256 : cmd[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400524 errsts = resp_write(SCpnt, lba, num, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 if (inj_recovered && (0 == errsts)) {
526 mk_sense_buffer(devip, RECOVERED_ERROR,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400527 THRESHOLD_EXCEEDED, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 errsts = check_condition_result;
529 }
530 break;
531 case MODE_SENSE:
532 case MODE_SENSE_10:
533 errsts = resp_mode_sense(SCpnt, target, devip);
534 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400535 case MODE_SELECT:
536 errsts = resp_mode_select(SCpnt, 1, devip);
537 break;
538 case MODE_SELECT_10:
539 errsts = resp_mode_select(SCpnt, 0, devip);
540 break;
541 case LOG_SENSE:
542 errsts = resp_log_sense(SCpnt, devip);
543 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 case SYNCHRONIZE_CACHE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400545 delay_override = 1;
546 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 break;
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500548 case WRITE_BUFFER:
549 errsts = check_readiness(SCpnt, 1, devip);
550 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 default:
552 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
553 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
554 "supported\n", *cmd);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400555 if ((errsts = check_readiness(SCpnt, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 break; /* Unit attention takes precedence */
557 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
558 errsts = check_condition_result;
559 break;
560 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400561 return schedule_resp(SCpnt, devip, done, errsts,
562 (delay_override ? 0 : scsi_debug_delay));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563}
564
565static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
566{
567 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
568 printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
569 }
570 return -EINVAL;
571 /* return -ENOTTY; // correct return but upsets fdisk */
572}
573
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400574static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
575 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576{
577 if (devip->reset) {
578 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
579 printk(KERN_INFO "scsi_debug: Reporting Unit "
580 "attention: power on reset\n");
581 devip->reset = 0;
582 mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
583 return check_condition_result;
584 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400585 if ((0 == reset_only) && devip->stopped) {
586 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
587 printk(KERN_INFO "scsi_debug: Reporting Not "
588 "ready: initializing command required\n");
589 mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
590 0x2);
591 return check_condition_result;
592 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 return 0;
594}
595
596/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
597static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
598 int arr_len)
599{
600 int k, req_len, act_len, len, active;
601 void * kaddr;
602 void * kaddr_off;
603 struct scatterlist * sgpnt;
604
605 if (0 == scp->request_bufflen)
606 return 0;
607 if (NULL == scp->request_buffer)
608 return (DID_ERROR << 16);
609 if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
610 (scp->sc_data_direction == DMA_FROM_DEVICE)))
611 return (DID_ERROR << 16);
612 if (0 == scp->use_sg) {
613 req_len = scp->request_bufflen;
614 act_len = (req_len < arr_len) ? req_len : arr_len;
615 memcpy(scp->request_buffer, arr, act_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400616 if (scp->resid)
617 scp->resid -= act_len;
618 else
619 scp->resid = req_len - act_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 return 0;
621 }
622 sgpnt = (struct scatterlist *)scp->request_buffer;
623 active = 1;
624 for (k = 0, req_len = 0, act_len = 0; k < scp->use_sg; ++k, ++sgpnt) {
625 if (active) {
626 kaddr = (unsigned char *)
627 kmap_atomic(sgpnt->page, KM_USER0);
628 if (NULL == kaddr)
629 return (DID_ERROR << 16);
630 kaddr_off = (unsigned char *)kaddr + sgpnt->offset;
631 len = sgpnt->length;
632 if ((req_len + len) > arr_len) {
633 active = 0;
634 len = arr_len - req_len;
635 }
636 memcpy(kaddr_off, arr + req_len, len);
637 kunmap_atomic(kaddr, KM_USER0);
638 act_len += len;
639 }
640 req_len += sgpnt->length;
641 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400642 if (scp->resid)
643 scp->resid -= act_len;
644 else
645 scp->resid = req_len - act_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 return 0;
647}
648
649/* Returns number of bytes fetched into 'arr' or -1 if error. */
650static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
651 int max_arr_len)
652{
653 int k, req_len, len, fin;
654 void * kaddr;
655 void * kaddr_off;
656 struct scatterlist * sgpnt;
657
658 if (0 == scp->request_bufflen)
659 return 0;
660 if (NULL == scp->request_buffer)
661 return -1;
662 if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
663 (scp->sc_data_direction == DMA_TO_DEVICE)))
664 return -1;
665 if (0 == scp->use_sg) {
666 req_len = scp->request_bufflen;
667 len = (req_len < max_arr_len) ? req_len : max_arr_len;
668 memcpy(arr, scp->request_buffer, len);
669 return len;
670 }
671 sgpnt = (struct scatterlist *)scp->request_buffer;
672 for (k = 0, req_len = 0, fin = 0; k < scp->use_sg; ++k, ++sgpnt) {
673 kaddr = (unsigned char *)kmap_atomic(sgpnt->page, KM_USER0);
674 if (NULL == kaddr)
675 return -1;
676 kaddr_off = (unsigned char *)kaddr + sgpnt->offset;
677 len = sgpnt->length;
678 if ((req_len + len) > max_arr_len) {
679 len = max_arr_len - req_len;
680 fin = 1;
681 }
682 memcpy(arr + req_len, kaddr_off, len);
683 kunmap_atomic(kaddr, KM_USER0);
684 if (fin)
685 return req_len + len;
686 req_len += sgpnt->length;
687 }
688 return req_len;
689}
690
691
692static const char * inq_vendor_id = "Linux ";
693static const char * inq_product_id = "scsi_debug ";
694static const char * inq_product_rev = "0004";
695
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200696static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
697 int target_dev_id, int dev_id_num,
698 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400699 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400701 int num, port_a;
702 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400704 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 /* T10 vendor identifier field format (faked) */
706 arr[0] = 0x2; /* ASCII */
707 arr[1] = 0x1;
708 arr[2] = 0x0;
709 memcpy(&arr[4], inq_vendor_id, 8);
710 memcpy(&arr[12], inq_product_id, 16);
711 memcpy(&arr[28], dev_id_str, dev_id_str_len);
712 num = 8 + 16 + dev_id_str_len;
713 arr[3] = num;
714 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400715 if (dev_id_num >= 0) {
716 /* NAA-5, Logical unit identifier (binary) */
717 arr[num++] = 0x1; /* binary (not necessarily sas) */
718 arr[num++] = 0x3; /* PIV=0, lu, naa */
719 arr[num++] = 0x0;
720 arr[num++] = 0x8;
721 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
722 arr[num++] = 0x33;
723 arr[num++] = 0x33;
724 arr[num++] = 0x30;
725 arr[num++] = (dev_id_num >> 24);
726 arr[num++] = (dev_id_num >> 16) & 0xff;
727 arr[num++] = (dev_id_num >> 8) & 0xff;
728 arr[num++] = dev_id_num & 0xff;
729 /* Target relative port number */
730 arr[num++] = 0x61; /* proto=sas, binary */
731 arr[num++] = 0x94; /* PIV=1, target port, rel port */
732 arr[num++] = 0x0; /* reserved */
733 arr[num++] = 0x4; /* length */
734 arr[num++] = 0x0; /* reserved */
735 arr[num++] = 0x0; /* reserved */
736 arr[num++] = 0x0;
737 arr[num++] = 0x1; /* relative port A */
738 }
739 /* NAA-5, Target port identifier */
740 arr[num++] = 0x61; /* proto=sas, binary */
741 arr[num++] = 0x93; /* piv=1, target port, naa */
742 arr[num++] = 0x0;
743 arr[num++] = 0x8;
744 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
745 arr[num++] = 0x22;
746 arr[num++] = 0x22;
747 arr[num++] = 0x20;
748 arr[num++] = (port_a >> 24);
749 arr[num++] = (port_a >> 16) & 0xff;
750 arr[num++] = (port_a >> 8) & 0xff;
751 arr[num++] = port_a & 0xff;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200752 /* NAA-5, Target port group identifier */
753 arr[num++] = 0x61; /* proto=sas, binary */
754 arr[num++] = 0x95; /* piv=1, target port group id */
755 arr[num++] = 0x0;
756 arr[num++] = 0x4;
757 arr[num++] = 0;
758 arr[num++] = 0;
759 arr[num++] = (port_group_id >> 8) & 0xff;
760 arr[num++] = port_group_id & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400761 /* NAA-5, Target device identifier */
762 arr[num++] = 0x61; /* proto=sas, binary */
763 arr[num++] = 0xa3; /* piv=1, target device, naa */
764 arr[num++] = 0x0;
765 arr[num++] = 0x8;
766 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
767 arr[num++] = 0x22;
768 arr[num++] = 0x22;
769 arr[num++] = 0x20;
770 arr[num++] = (target_dev_id >> 24);
771 arr[num++] = (target_dev_id >> 16) & 0xff;
772 arr[num++] = (target_dev_id >> 8) & 0xff;
773 arr[num++] = target_dev_id & 0xff;
774 /* SCSI name string: Target device identifier */
775 arr[num++] = 0x63; /* proto=sas, UTF-8 */
776 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
777 arr[num++] = 0x0;
778 arr[num++] = 24;
779 memcpy(arr + num, "naa.52222220", 12);
780 num += 12;
781 snprintf(b, sizeof(b), "%08X", target_dev_id);
782 memcpy(arr + num, b, 8);
783 num += 8;
784 memset(arr + num, 0, 4);
785 num += 4;
786 return num;
787}
788
789
790static unsigned char vpd84_data[] = {
791/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
792 0x22,0x22,0x22,0x0,0xbb,0x1,
793 0x22,0x22,0x22,0x0,0xbb,0x2,
794};
795
796static int inquiry_evpd_84(unsigned char * arr)
797{
798 memcpy(arr, vpd84_data, sizeof(vpd84_data));
799 return sizeof(vpd84_data);
800}
801
802static int inquiry_evpd_85(unsigned char * arr)
803{
804 int num = 0;
805 const char * na1 = "https://www.kernel.org/config";
806 const char * na2 = "http://www.kernel.org/log";
807 int plen, olen;
808
809 arr[num++] = 0x1; /* lu, storage config */
810 arr[num++] = 0x0; /* reserved */
811 arr[num++] = 0x0;
812 olen = strlen(na1);
813 plen = olen + 1;
814 if (plen % 4)
815 plen = ((plen / 4) + 1) * 4;
816 arr[num++] = plen; /* length, null termianted, padded */
817 memcpy(arr + num, na1, olen);
818 memset(arr + num + olen, 0, plen - olen);
819 num += plen;
820
821 arr[num++] = 0x4; /* lu, logging */
822 arr[num++] = 0x0; /* reserved */
823 arr[num++] = 0x0;
824 olen = strlen(na2);
825 plen = olen + 1;
826 if (plen % 4)
827 plen = ((plen / 4) + 1) * 4;
828 arr[num++] = plen; /* length, null terminated, padded */
829 memcpy(arr + num, na2, olen);
830 memset(arr + num + olen, 0, plen - olen);
831 num += plen;
832
833 return num;
834}
835
836/* SCSI ports VPD page */
837static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
838{
839 int num = 0;
840 int port_a, port_b;
841
842 port_a = target_dev_id + 1;
843 port_b = port_a + 1;
844 arr[num++] = 0x0; /* reserved */
845 arr[num++] = 0x0; /* reserved */
846 arr[num++] = 0x0;
847 arr[num++] = 0x1; /* relative port 1 (primary) */
848 memset(arr + num, 0, 6);
849 num += 6;
850 arr[num++] = 0x0;
851 arr[num++] = 12; /* length tp descriptor */
852 /* naa-5 target port identifier (A) */
853 arr[num++] = 0x61; /* proto=sas, binary */
854 arr[num++] = 0x93; /* PIV=1, target port, NAA */
855 arr[num++] = 0x0; /* reserved */
856 arr[num++] = 0x8; /* length */
857 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
858 arr[num++] = 0x22;
859 arr[num++] = 0x22;
860 arr[num++] = 0x20;
861 arr[num++] = (port_a >> 24);
862 arr[num++] = (port_a >> 16) & 0xff;
863 arr[num++] = (port_a >> 8) & 0xff;
864 arr[num++] = port_a & 0xff;
865
866 arr[num++] = 0x0; /* reserved */
867 arr[num++] = 0x0; /* reserved */
868 arr[num++] = 0x0;
869 arr[num++] = 0x2; /* relative port 2 (secondary) */
870 memset(arr + num, 0, 6);
871 num += 6;
872 arr[num++] = 0x0;
873 arr[num++] = 12; /* length tp descriptor */
874 /* naa-5 target port identifier (B) */
875 arr[num++] = 0x61; /* proto=sas, binary */
876 arr[num++] = 0x93; /* PIV=1, target port, NAA */
877 arr[num++] = 0x0; /* reserved */
878 arr[num++] = 0x8; /* length */
879 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
880 arr[num++] = 0x22;
881 arr[num++] = 0x22;
882 arr[num++] = 0x20;
883 arr[num++] = (port_b >> 24);
884 arr[num++] = (port_b >> 16) & 0xff;
885 arr[num++] = (port_b >> 8) & 0xff;
886 arr[num++] = port_b & 0xff;
887
888 return num;
889}
890
891
892static unsigned char vpd89_data[] = {
893/* from 4th byte */ 0,0,0,0,
894'l','i','n','u','x',' ',' ',' ',
895'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
896'1','2','3','4',
8970x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
8980xec,0,0,0,
8990x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
9000,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
9010x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
9020x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
9030x53,0x41,
9040x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
9050x20,0x20,
9060x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
9070x10,0x80,
9080,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
9090x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
9100x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
9110,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
9120x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
9130x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
9140,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
9150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9170,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9180x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
9190,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
9200xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
9210,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
9220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0xa5,0x51,
934};
935
936static int inquiry_evpd_89(unsigned char * arr)
937{
938 memcpy(arr, vpd89_data, sizeof(vpd89_data));
939 return sizeof(vpd89_data);
940}
941
942
943static unsigned char vpdb0_data[] = {
944 /* from 4th byte */ 0,0,0,4,
945 0,0,0x4,0,
946 0,0,0,64,
947};
948
949static int inquiry_evpd_b0(unsigned char * arr)
950{
951 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
952 if (sdebug_store_sectors > 0x400) {
953 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
954 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
955 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
956 arr[7] = sdebug_store_sectors & 0xff;
957 }
958 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959}
960
961
962#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400963#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
965static int resp_inquiry(struct scsi_cmnd * scp, int target,
966 struct sdebug_dev_info * devip)
967{
968 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200969 unsigned char * arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 unsigned char *cmd = (unsigned char *)scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200971 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972
973 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500974 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
975 if (! arr)
976 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400977 if (devip->wlun)
978 pq_pdt = 0x1e; /* present, wlun */
979 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
980 pq_pdt = 0x7f; /* not present, no device type */
981 else
982 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 arr[0] = pq_pdt;
984 if (0x2 & cmd[1]) { /* CMDDT bit set */
985 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
986 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200987 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 return check_condition_result;
989 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200990 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400991 char lu_id_str[6];
992 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200994 port_group_id = (((host_no + 1) & 0x7f) << 8) +
995 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -0400996 if (0 == scsi_debug_vpd_use_hostno)
997 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400998 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
999 (devip->target * 1000) + devip->lun);
1000 target_dev_id = ((host_no + 1) * 2000) +
1001 (devip->target * 1000) - 3;
1002 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001004 arr[1] = cmd[2]; /*sanity */
1005 n = 4;
1006 arr[n++] = 0x0; /* this page */
1007 arr[n++] = 0x80; /* unit serial number */
1008 arr[n++] = 0x83; /* device identification */
1009 arr[n++] = 0x84; /* software interface ident. */
1010 arr[n++] = 0x85; /* management network addresses */
1011 arr[n++] = 0x86; /* extended inquiry */
1012 arr[n++] = 0x87; /* mode page policy */
1013 arr[n++] = 0x88; /* SCSI ports */
1014 arr[n++] = 0x89; /* ATA information */
1015 arr[n++] = 0xb0; /* Block limits (SBC) */
1016 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001018 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001020 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001022 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001023 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
1024 target_dev_id, lu_id_num,
1025 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001026 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1027 arr[1] = cmd[2]; /*sanity */
1028 arr[3] = inquiry_evpd_84(&arr[4]);
1029 } else if (0x85 == cmd[2]) { /* Management network addresses */
1030 arr[1] = cmd[2]; /*sanity */
1031 arr[3] = inquiry_evpd_85(&arr[4]);
1032 } else if (0x86 == cmd[2]) { /* extended inquiry */
1033 arr[1] = cmd[2]; /*sanity */
1034 arr[3] = 0x3c; /* number of following entries */
1035 arr[4] = 0x0; /* no protection stuff */
1036 arr[5] = 0x7; /* head of q, ordered + simple q's */
1037 } else if (0x87 == cmd[2]) { /* mode page policy */
1038 arr[1] = cmd[2]; /*sanity */
1039 arr[3] = 0x8; /* number of following entries */
1040 arr[4] = 0x2; /* disconnect-reconnect mp */
1041 arr[6] = 0x80; /* mlus, shared */
1042 arr[8] = 0x18; /* protocol specific lu */
1043 arr[10] = 0x82; /* mlus, per initiator port */
1044 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1045 arr[1] = cmd[2]; /*sanity */
1046 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
1047 } else if (0x89 == cmd[2]) { /* ATA information */
1048 arr[1] = cmd[2]; /*sanity */
1049 n = inquiry_evpd_89(&arr[4]);
1050 arr[2] = (n >> 8);
1051 arr[3] = (n & 0xff);
1052 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
1053 arr[1] = cmd[2]; /*sanity */
1054 arr[3] = inquiry_evpd_b0(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 } else {
1056 /* Illegal request, invalid field in cdb */
1057 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1058 INVALID_FIELD_IN_CDB, 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001059 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 return check_condition_result;
1061 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001062 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001063 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001064 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001065 kfree(arr);
1066 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 }
1068 /* drops through here for a standard inquiry */
1069 arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
1070 arr[2] = scsi_debug_scsi_level;
1071 arr[3] = 2; /* response_data_format==2 */
1072 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001073 if (0 == scsi_debug_vpd_use_hostno)
1074 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001075 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001077 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 memcpy(&arr[8], inq_vendor_id, 8);
1079 memcpy(&arr[16], inq_product_id, 16);
1080 memcpy(&arr[32], inq_product_rev, 4);
1081 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001082 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
1083 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
1084 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001086 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001088 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001090 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001091 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001093 kfree(arr);
1094 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095}
1096
1097static int resp_requests(struct scsi_cmnd * scp,
1098 struct sdebug_dev_info * devip)
1099{
1100 unsigned char * sbuff;
1101 unsigned char *cmd = (unsigned char *)scp->cmnd;
1102 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001103 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 int len = 18;
1105
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001106 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001108 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
1109 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001111 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1112 if (want_dsense) {
1113 arr[0] = 0x72;
1114 arr[1] = 0x0; /* NO_SENSE in sense_key */
1115 arr[2] = THRESHOLD_EXCEEDED;
1116 arr[3] = 0xff; /* TEST set and MRIE==6 */
1117 } else {
1118 arr[0] = 0x70;
1119 arr[2] = 0x0; /* NO_SENSE in sense_key */
1120 arr[7] = 0xa; /* 18 byte sense buffer */
1121 arr[12] = THRESHOLD_EXCEEDED;
1122 arr[13] = 0xff; /* TEST set and MRIE==6 */
1123 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001124 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001126 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
1127 /* DESC bit set and sense_buff in fixed format */
1128 memset(arr, 0, sizeof(arr));
1129 arr[0] = 0x72;
1130 arr[1] = sbuff[2]; /* sense key */
1131 arr[2] = sbuff[12]; /* asc */
1132 arr[3] = sbuff[13]; /* ascq */
1133 len = 8;
1134 }
1135 }
1136 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 return fill_from_dev_buffer(scp, arr, len);
1138}
1139
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001140static int resp_start_stop(struct scsi_cmnd * scp,
1141 struct sdebug_dev_info * devip)
1142{
1143 unsigned char *cmd = (unsigned char *)scp->cmnd;
1144 int power_cond, errsts, start;
1145
1146 if ((errsts = check_readiness(scp, 1, devip)))
1147 return errsts;
1148 power_cond = (cmd[4] & 0xf0) >> 4;
1149 if (power_cond) {
1150 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1151 0);
1152 return check_condition_result;
1153 }
1154 start = cmd[4] & 1;
1155 if (start == devip->stopped)
1156 devip->stopped = !start;
1157 return 0;
1158}
1159
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160#define SDEBUG_READCAP_ARR_SZ 8
1161static int resp_readcap(struct scsi_cmnd * scp,
1162 struct sdebug_dev_info * devip)
1163{
1164 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001165 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 int errsts;
1167
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001168 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001170 /* following just in case virtual_gb changed */
1171 if (scsi_debug_virtual_gb > 0) {
1172 sdebug_capacity = 2048 * 1024;
1173 sdebug_capacity *= scsi_debug_virtual_gb;
1174 } else
1175 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001177 if (sdebug_capacity < 0xffffffff) {
1178 capac = (unsigned int)sdebug_capacity - 1;
1179 arr[0] = (capac >> 24);
1180 arr[1] = (capac >> 16) & 0xff;
1181 arr[2] = (capac >> 8) & 0xff;
1182 arr[3] = capac & 0xff;
1183 } else {
1184 arr[0] = 0xff;
1185 arr[1] = 0xff;
1186 arr[2] = 0xff;
1187 arr[3] = 0xff;
1188 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1190 arr[7] = SECT_SIZE_PER(target) & 0xff;
1191 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1192}
1193
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001194#define SDEBUG_READCAP16_ARR_SZ 32
1195static int resp_readcap16(struct scsi_cmnd * scp,
1196 struct sdebug_dev_info * devip)
1197{
1198 unsigned char *cmd = (unsigned char *)scp->cmnd;
1199 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1200 unsigned long long capac;
1201 int errsts, k, alloc_len;
1202
1203 if ((errsts = check_readiness(scp, 1, devip)))
1204 return errsts;
1205 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1206 + cmd[13]);
1207 /* following just in case virtual_gb changed */
1208 if (scsi_debug_virtual_gb > 0) {
1209 sdebug_capacity = 2048 * 1024;
1210 sdebug_capacity *= scsi_debug_virtual_gb;
1211 } else
1212 sdebug_capacity = sdebug_store_sectors;
1213 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1214 capac = sdebug_capacity - 1;
1215 for (k = 0; k < 8; ++k, capac >>= 8)
1216 arr[7 - k] = capac & 0xff;
1217 arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff;
1218 arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff;
1219 arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1220 arr[11] = SECT_SIZE_PER(target) & 0xff;
1221 return fill_from_dev_buffer(scp, arr,
1222 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1223}
1224
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001225#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1226
1227static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1228 struct sdebug_dev_info * devip)
1229{
1230 unsigned char *cmd = (unsigned char *)scp->cmnd;
1231 unsigned char * arr;
1232 int host_no = devip->sdbg_host->shost->host_no;
1233 int n, ret, alen, rlen;
1234 int port_group_a, port_group_b, port_a, port_b;
1235
1236 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
1237 + cmd[9]);
1238
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001239 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1240 if (! arr)
1241 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001242 /*
1243 * EVPD page 0x88 states we have two ports, one
1244 * real and a fake port with no device connected.
1245 * So we create two port groups with one port each
1246 * and set the group with port B to unavailable.
1247 */
1248 port_a = 0x1; /* relative port A */
1249 port_b = 0x2; /* relative port B */
1250 port_group_a = (((host_no + 1) & 0x7f) << 8) +
1251 (devip->channel & 0x7f);
1252 port_group_b = (((host_no + 1) & 0x7f) << 8) +
1253 (devip->channel & 0x7f) + 0x80;
1254
1255 /*
1256 * The asymmetric access state is cycled according to the host_id.
1257 */
1258 n = 4;
1259 if (0 == scsi_debug_vpd_use_hostno) {
1260 arr[n++] = host_no % 3; /* Asymm access state */
1261 arr[n++] = 0x0F; /* claim: all states are supported */
1262 } else {
1263 arr[n++] = 0x0; /* Active/Optimized path */
1264 arr[n++] = 0x01; /* claim: only support active/optimized paths */
1265 }
1266 arr[n++] = (port_group_a >> 8) & 0xff;
1267 arr[n++] = port_group_a & 0xff;
1268 arr[n++] = 0; /* Reserved */
1269 arr[n++] = 0; /* Status code */
1270 arr[n++] = 0; /* Vendor unique */
1271 arr[n++] = 0x1; /* One port per group */
1272 arr[n++] = 0; /* Reserved */
1273 arr[n++] = 0; /* Reserved */
1274 arr[n++] = (port_a >> 8) & 0xff;
1275 arr[n++] = port_a & 0xff;
1276 arr[n++] = 3; /* Port unavailable */
1277 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1278 arr[n++] = (port_group_b >> 8) & 0xff;
1279 arr[n++] = port_group_b & 0xff;
1280 arr[n++] = 0; /* Reserved */
1281 arr[n++] = 0; /* Status code */
1282 arr[n++] = 0; /* Vendor unique */
1283 arr[n++] = 0x1; /* One port per group */
1284 arr[n++] = 0; /* Reserved */
1285 arr[n++] = 0; /* Reserved */
1286 arr[n++] = (port_b >> 8) & 0xff;
1287 arr[n++] = port_b & 0xff;
1288
1289 rlen = n - 4;
1290 arr[0] = (rlen >> 24) & 0xff;
1291 arr[1] = (rlen >> 16) & 0xff;
1292 arr[2] = (rlen >> 8) & 0xff;
1293 arr[3] = rlen & 0xff;
1294
1295 /*
1296 * Return the smallest value of either
1297 * - The allocated length
1298 * - The constructed command length
1299 * - The maximum array size
1300 */
1301 rlen = min(alen,n);
1302 ret = fill_from_dev_buffer(scp, arr,
1303 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1304 kfree(arr);
1305 return ret;
1306}
1307
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308/* <<Following mode page info copied from ST318451LW>> */
1309
1310static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1311{ /* Read-Write Error Recovery page for mode_sense */
1312 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1313 5, 0, 0xff, 0xff};
1314
1315 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1316 if (1 == pcontrol)
1317 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1318 return sizeof(err_recov_pg);
1319}
1320
1321static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1322{ /* Disconnect-Reconnect page for mode_sense */
1323 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1324 0, 0, 0, 0, 0, 0, 0, 0};
1325
1326 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1327 if (1 == pcontrol)
1328 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1329 return sizeof(disconnect_pg);
1330}
1331
1332static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1333{ /* Format device page for mode_sense */
1334 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1335 0, 0, 0, 0, 0, 0, 0, 0,
1336 0, 0, 0, 0, 0x40, 0, 0, 0};
1337
1338 memcpy(p, format_pg, sizeof(format_pg));
1339 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1340 p[11] = sdebug_sectors_per & 0xff;
1341 p[12] = (SECT_SIZE >> 8) & 0xff;
1342 p[13] = SECT_SIZE & 0xff;
1343 if (DEV_REMOVEABLE(target))
1344 p[20] |= 0x20; /* should agree with INQUIRY */
1345 if (1 == pcontrol)
1346 memset(p + 2, 0, sizeof(format_pg) - 2);
1347 return sizeof(format_pg);
1348}
1349
1350static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1351{ /* Caching page for mode_sense */
1352 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1353 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1354
1355 memcpy(p, caching_pg, sizeof(caching_pg));
1356 if (1 == pcontrol)
1357 memset(p + 2, 0, sizeof(caching_pg) - 2);
1358 return sizeof(caching_pg);
1359}
1360
1361static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1362{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001363 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1364 0, 0, 0, 0};
1365 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 0, 0, 0x2, 0x4b};
1367
1368 if (scsi_debug_dsense)
1369 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001370 else
1371 ctrl_m_pg[2] &= ~0x4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1373 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001374 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1375 else if (2 == pcontrol)
1376 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 return sizeof(ctrl_m_pg);
1378}
1379
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001380
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1382{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001383 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1384 0, 0, 0x0, 0x0};
1385 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1386 0, 0, 0x0, 0x0};
1387
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1389 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001390 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1391 else if (2 == pcontrol)
1392 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 return sizeof(iec_m_pg);
1394}
1395
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001396static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1397{ /* SAS SSP mode page - short format for mode_sense */
1398 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1399 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1400
1401 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1402 if (1 == pcontrol)
1403 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1404 return sizeof(sas_sf_m_pg);
1405}
1406
1407
1408static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1409 int target_dev_id)
1410{ /* SAS phy control and discover mode page for mode_sense */
1411 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1412 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1413 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1414 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1415 0x2, 0, 0, 0, 0, 0, 0, 0,
1416 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1417 0, 0, 0, 0, 0, 0, 0, 0,
1418 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1419 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1420 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1421 0x3, 0, 0, 0, 0, 0, 0, 0,
1422 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1423 0, 0, 0, 0, 0, 0, 0, 0,
1424 };
1425 int port_a, port_b;
1426
1427 port_a = target_dev_id + 1;
1428 port_b = port_a + 1;
1429 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1430 p[20] = (port_a >> 24);
1431 p[21] = (port_a >> 16) & 0xff;
1432 p[22] = (port_a >> 8) & 0xff;
1433 p[23] = port_a & 0xff;
1434 p[48 + 20] = (port_b >> 24);
1435 p[48 + 21] = (port_b >> 16) & 0xff;
1436 p[48 + 22] = (port_b >> 8) & 0xff;
1437 p[48 + 23] = port_b & 0xff;
1438 if (1 == pcontrol)
1439 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1440 return sizeof(sas_pcd_m_pg);
1441}
1442
1443static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1444{ /* SAS SSP shared protocol specific port mode subpage */
1445 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1446 0, 0, 0, 0, 0, 0, 0, 0,
1447 };
1448
1449 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1450 if (1 == pcontrol)
1451 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1452 return sizeof(sas_sha_m_pg);
1453}
1454
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455#define SDEBUG_MAX_MSENSE_SZ 256
1456
1457static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1458 struct sdebug_dev_info * devip)
1459{
Douglas Gilbert23183912006-09-16 20:30:47 -04001460 unsigned char dbd, llbaa;
1461 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001463 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 unsigned char * ap;
1465 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1466 unsigned char *cmd = (unsigned char *)scp->cmnd;
1467
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001468 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001470 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 pcontrol = (cmd[2] & 0xc0) >> 6;
1472 pcode = cmd[2] & 0x3f;
1473 subpcode = cmd[3];
1474 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001475 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1476 if ((0 == scsi_debug_ptype) && (0 == dbd))
1477 bd_len = llbaa ? 16 : 8;
1478 else
1479 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1481 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1482 if (0x3 == pcontrol) { /* Saving values not supported */
1483 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1484 0);
1485 return check_condition_result;
1486 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001487 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1488 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001489 /* set DPOFUA bit for disks */
1490 if (0 == scsi_debug_ptype)
1491 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1492 else
1493 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 if (msense_6) {
1495 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001496 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 offset = 4;
1498 } else {
1499 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001500 if (16 == bd_len)
1501 arr[4] = 0x1; /* set LONGLBA bit */
1502 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 offset = 8;
1504 }
1505 ap = arr + offset;
Douglas Gilbert23183912006-09-16 20:30:47 -04001506 if ((bd_len > 0) && (0 == sdebug_capacity)) {
1507 if (scsi_debug_virtual_gb > 0) {
1508 sdebug_capacity = 2048 * 1024;
1509 sdebug_capacity *= scsi_debug_virtual_gb;
1510 } else
1511 sdebug_capacity = sdebug_store_sectors;
1512 }
1513 if (8 == bd_len) {
1514 if (sdebug_capacity > 0xfffffffe) {
1515 ap[0] = 0xff;
1516 ap[1] = 0xff;
1517 ap[2] = 0xff;
1518 ap[3] = 0xff;
1519 } else {
1520 ap[0] = (sdebug_capacity >> 24) & 0xff;
1521 ap[1] = (sdebug_capacity >> 16) & 0xff;
1522 ap[2] = (sdebug_capacity >> 8) & 0xff;
1523 ap[3] = sdebug_capacity & 0xff;
1524 }
1525 ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1526 ap[7] = SECT_SIZE_PER(target) & 0xff;
1527 offset += bd_len;
1528 ap = arr + offset;
1529 } else if (16 == bd_len) {
1530 unsigned long long capac = sdebug_capacity;
1531
1532 for (k = 0; k < 8; ++k, capac >>= 8)
1533 ap[7 - k] = capac & 0xff;
1534 ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff;
1535 ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff;
1536 ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1537 ap[15] = SECT_SIZE_PER(target) & 0xff;
1538 offset += bd_len;
1539 ap = arr + offset;
1540 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001542 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1543 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1545 0);
1546 return check_condition_result;
1547 }
1548 switch (pcode) {
1549 case 0x1: /* Read-Write error recovery page, direct access */
1550 len = resp_err_recov_pg(ap, pcontrol, target);
1551 offset += len;
1552 break;
1553 case 0x2: /* Disconnect-Reconnect page, all devices */
1554 len = resp_disconnect_pg(ap, pcontrol, target);
1555 offset += len;
1556 break;
1557 case 0x3: /* Format device page, direct access */
1558 len = resp_format_pg(ap, pcontrol, target);
1559 offset += len;
1560 break;
1561 case 0x8: /* Caching page, direct access */
1562 len = resp_caching_pg(ap, pcontrol, target);
1563 offset += len;
1564 break;
1565 case 0xa: /* Control Mode page, all devices */
1566 len = resp_ctrl_m_pg(ap, pcontrol, target);
1567 offset += len;
1568 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001569 case 0x19: /* if spc==1 then sas phy, control+discover */
1570 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1571 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1572 INVALID_FIELD_IN_CDB, 0);
1573 return check_condition_result;
1574 }
1575 len = 0;
1576 if ((0x0 == subpcode) || (0xff == subpcode))
1577 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1578 if ((0x1 == subpcode) || (0xff == subpcode))
1579 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1580 target_dev_id);
1581 if ((0x2 == subpcode) || (0xff == subpcode))
1582 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1583 offset += len;
1584 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 case 0x1c: /* Informational Exceptions Mode page, all devices */
1586 len = resp_iec_m_pg(ap, pcontrol, target);
1587 offset += len;
1588 break;
1589 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001590 if ((0 == subpcode) || (0xff == subpcode)) {
1591 len = resp_err_recov_pg(ap, pcontrol, target);
1592 len += resp_disconnect_pg(ap + len, pcontrol, target);
1593 len += resp_format_pg(ap + len, pcontrol, target);
1594 len += resp_caching_pg(ap + len, pcontrol, target);
1595 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1596 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1597 if (0xff == subpcode) {
1598 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1599 target, target_dev_id);
1600 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1601 }
1602 len += resp_iec_m_pg(ap + len, pcontrol, target);
1603 } else {
1604 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1605 INVALID_FIELD_IN_CDB, 0);
1606 return check_condition_result;
1607 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 offset += len;
1609 break;
1610 default:
1611 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1612 0);
1613 return check_condition_result;
1614 }
1615 if (msense_6)
1616 arr[0] = offset - 1;
1617 else {
1618 arr[0] = ((offset - 2) >> 8) & 0xff;
1619 arr[1] = (offset - 2) & 0xff;
1620 }
1621 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1622}
1623
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001624#define SDEBUG_MAX_MSELECT_SZ 512
1625
1626static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1627 struct sdebug_dev_info * devip)
1628{
1629 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1630 int param_len, res, errsts, mpage;
1631 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1632 unsigned char *cmd = (unsigned char *)scp->cmnd;
1633
1634 if ((errsts = check_readiness(scp, 1, devip)))
1635 return errsts;
1636 memset(arr, 0, sizeof(arr));
1637 pf = cmd[1] & 0x10;
1638 sp = cmd[1] & 0x1;
1639 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1640 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1641 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1642 INVALID_FIELD_IN_CDB, 0);
1643 return check_condition_result;
1644 }
1645 res = fetch_to_dev_buffer(scp, arr, param_len);
1646 if (-1 == res)
1647 return (DID_ERROR << 16);
1648 else if ((res < param_len) &&
1649 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1650 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1651 " IO sent=%d bytes\n", param_len, res);
1652 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1653 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001654 if (md_len > 2) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001655 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1656 INVALID_FIELD_IN_PARAM_LIST, 0);
1657 return check_condition_result;
1658 }
1659 off = bd_len + (mselect6 ? 4 : 8);
1660 mpage = arr[off] & 0x3f;
1661 ps = !!(arr[off] & 0x80);
1662 if (ps) {
1663 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1664 INVALID_FIELD_IN_PARAM_LIST, 0);
1665 return check_condition_result;
1666 }
1667 spf = !!(arr[off] & 0x40);
1668 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1669 (arr[off + 1] + 2);
1670 if ((pg_len + off) > param_len) {
1671 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1672 PARAMETER_LIST_LENGTH_ERR, 0);
1673 return check_condition_result;
1674 }
1675 switch (mpage) {
1676 case 0xa: /* Control Mode page */
1677 if (ctrl_m_pg[1] == arr[off + 1]) {
1678 memcpy(ctrl_m_pg + 2, arr + off + 2,
1679 sizeof(ctrl_m_pg) - 2);
1680 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1681 return 0;
1682 }
1683 break;
1684 case 0x1c: /* Informational Exceptions Mode page */
1685 if (iec_m_pg[1] == arr[off + 1]) {
1686 memcpy(iec_m_pg + 2, arr + off + 2,
1687 sizeof(iec_m_pg) - 2);
1688 return 0;
1689 }
1690 break;
1691 default:
1692 break;
1693 }
1694 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1695 INVALID_FIELD_IN_PARAM_LIST, 0);
1696 return check_condition_result;
1697}
1698
1699static int resp_temp_l_pg(unsigned char * arr)
1700{
1701 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1702 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1703 };
1704
1705 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1706 return sizeof(temp_l_pg);
1707}
1708
1709static int resp_ie_l_pg(unsigned char * arr)
1710{
1711 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1712 };
1713
1714 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1715 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1716 arr[4] = THRESHOLD_EXCEEDED;
1717 arr[5] = 0xff;
1718 }
1719 return sizeof(ie_l_pg);
1720}
1721
1722#define SDEBUG_MAX_LSENSE_SZ 512
1723
1724static int resp_log_sense(struct scsi_cmnd * scp,
1725 struct sdebug_dev_info * devip)
1726{
Douglas Gilbert23183912006-09-16 20:30:47 -04001727 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001728 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1729 unsigned char *cmd = (unsigned char *)scp->cmnd;
1730
1731 if ((errsts = check_readiness(scp, 1, devip)))
1732 return errsts;
1733 memset(arr, 0, sizeof(arr));
1734 ppc = cmd[1] & 0x2;
1735 sp = cmd[1] & 0x1;
1736 if (ppc || sp) {
1737 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1738 INVALID_FIELD_IN_CDB, 0);
1739 return check_condition_result;
1740 }
1741 pcontrol = (cmd[2] & 0xc0) >> 6;
1742 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001743 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001744 alloc_len = (cmd[7] << 8) + cmd[8];
1745 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001746 if (0 == subpcode) {
1747 switch (pcode) {
1748 case 0x0: /* Supported log pages log page */
1749 n = 4;
1750 arr[n++] = 0x0; /* this page */
1751 arr[n++] = 0xd; /* Temperature */
1752 arr[n++] = 0x2f; /* Informational exceptions */
1753 arr[3] = n - 4;
1754 break;
1755 case 0xd: /* Temperature log page */
1756 arr[3] = resp_temp_l_pg(arr + 4);
1757 break;
1758 case 0x2f: /* Informational exceptions log page */
1759 arr[3] = resp_ie_l_pg(arr + 4);
1760 break;
1761 default:
1762 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1763 INVALID_FIELD_IN_CDB, 0);
1764 return check_condition_result;
1765 }
1766 } else if (0xff == subpcode) {
1767 arr[0] |= 0x40;
1768 arr[1] = subpcode;
1769 switch (pcode) {
1770 case 0x0: /* Supported log pages and subpages log page */
1771 n = 4;
1772 arr[n++] = 0x0;
1773 arr[n++] = 0x0; /* 0,0 page */
1774 arr[n++] = 0x0;
1775 arr[n++] = 0xff; /* this page */
1776 arr[n++] = 0xd;
1777 arr[n++] = 0x0; /* Temperature */
1778 arr[n++] = 0x2f;
1779 arr[n++] = 0x0; /* Informational exceptions */
1780 arr[3] = n - 4;
1781 break;
1782 case 0xd: /* Temperature subpages */
1783 n = 4;
1784 arr[n++] = 0xd;
1785 arr[n++] = 0x0; /* Temperature */
1786 arr[3] = n - 4;
1787 break;
1788 case 0x2f: /* Informational exceptions subpages */
1789 n = 4;
1790 arr[n++] = 0x2f;
1791 arr[n++] = 0x0; /* Informational exceptions */
1792 arr[3] = n - 4;
1793 break;
1794 default:
1795 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1796 INVALID_FIELD_IN_CDB, 0);
1797 return check_condition_result;
1798 }
1799 } else {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001800 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1801 INVALID_FIELD_IN_CDB, 0);
1802 return check_condition_result;
1803 }
1804 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1805 return fill_from_dev_buffer(scp, arr,
1806 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1807}
1808
1809static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
1810 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811{
1812 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001813 unsigned int block, from_bottom;
1814 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 int ret;
1816
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001817 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1819 0);
1820 return check_condition_result;
1821 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001822 /* transfer length excessive (tie in to block limits VPD page) */
1823 if (num > sdebug_store_sectors) {
1824 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1825 0);
1826 return check_condition_result;
1827 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001829 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1830 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1831 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1833 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001834 /* set info field and valid bit for fixed descriptor */
1835 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1836 devip->sense_buff[0] |= 0x80; /* Valid bit */
1837 ret = OPT_MEDIUM_ERR_ADDR;
1838 devip->sense_buff[3] = (ret >> 24) & 0xff;
1839 devip->sense_buff[4] = (ret >> 16) & 0xff;
1840 devip->sense_buff[5] = (ret >> 8) & 0xff;
1841 devip->sense_buff[6] = ret & 0xff;
1842 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 return check_condition_result;
1844 }
1845 read_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001846 if ((lba + num) <= sdebug_store_sectors)
1847 ret = fill_from_dev_buffer(SCpnt,
1848 fake_storep + (lba * SECT_SIZE),
1849 num * SECT_SIZE);
1850 else {
1851 /* modulo when one arg is 64 bits needs do_div() */
1852 u = lba;
1853 block = do_div(u, sdebug_store_sectors);
1854 from_bottom = 0;
1855 if ((block + num) > sdebug_store_sectors)
1856 from_bottom = (block + num) - sdebug_store_sectors;
1857 ret = fill_from_dev_buffer(SCpnt,
1858 fake_storep + (block * SECT_SIZE),
1859 (num - from_bottom) * SECT_SIZE);
1860 if ((0 == ret) && (from_bottom > 0))
1861 ret = fill_from_dev_buffer(SCpnt, fake_storep,
1862 from_bottom * SECT_SIZE);
1863 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 read_unlock_irqrestore(&atomic_rw, iflags);
1865 return ret;
1866}
1867
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001868static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
1869 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870{
1871 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001872 unsigned int block, to_bottom;
1873 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 int res;
1875
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001876 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1878 0);
1879 return check_condition_result;
1880 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001881 /* transfer length excessive (tie in to block limits VPD page) */
1882 if (num > sdebug_store_sectors) {
1883 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1884 0);
1885 return check_condition_result;
1886 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887
1888 write_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001889 if ((lba + num) <= sdebug_store_sectors)
1890 res = fetch_to_dev_buffer(SCpnt,
1891 fake_storep + (lba * SECT_SIZE),
1892 num * SECT_SIZE);
1893 else {
1894 /* modulo when one arg is 64 bits needs do_div() */
1895 u = lba;
1896 block = do_div(u, sdebug_store_sectors);
1897 to_bottom = 0;
1898 if ((block + num) > sdebug_store_sectors)
1899 to_bottom = (block + num) - sdebug_store_sectors;
1900 res = fetch_to_dev_buffer(SCpnt,
1901 fake_storep + (block * SECT_SIZE),
1902 (num - to_bottom) * SECT_SIZE);
1903 if ((0 == res) && (to_bottom > 0))
1904 res = fetch_to_dev_buffer(SCpnt, fake_storep,
1905 to_bottom * SECT_SIZE);
1906 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 write_unlock_irqrestore(&atomic_rw, iflags);
1908 if (-1 == res)
1909 return (DID_ERROR << 16);
1910 else if ((res < (num * SECT_SIZE)) &&
1911 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001912 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 " IO sent=%d bytes\n", num * SECT_SIZE, res);
1914 return 0;
1915}
1916
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001917#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918
1919static int resp_report_luns(struct scsi_cmnd * scp,
1920 struct sdebug_dev_info * devip)
1921{
1922 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001923 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 unsigned char *cmd = (unsigned char *)scp->cmnd;
1925 int select_report = (int)cmd[2];
1926 struct scsi_lun *one_lun;
1927 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001928 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929
1930 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001931 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1933 0);
1934 return check_condition_result;
1935 }
1936 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
1937 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
1938 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001939 if (1 == select_report)
1940 lun_cnt = 0;
1941 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
1942 --lun_cnt;
1943 wlun = (select_report > 0) ? 1 : 0;
1944 num = lun_cnt + wlun;
1945 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
1946 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
1947 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
1948 sizeof(struct scsi_lun)), num);
1949 if (n < num) {
1950 wlun = 0;
1951 lun_cnt = n;
1952 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001954 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
1955 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
1956 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
1957 i++, lun++) {
1958 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 if (upper)
1960 one_lun[i].scsi_lun[0] =
1961 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001962 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001964 if (wlun) {
1965 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
1966 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
1967 i++;
1968 }
1969 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 return fill_from_dev_buffer(scp, arr,
1971 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
1972}
1973
1974/* When timer goes off this function is called. */
1975static void timer_intr_handler(unsigned long indx)
1976{
1977 struct sdebug_queued_cmd * sqcp;
1978 unsigned long iflags;
1979
1980 if (indx >= SCSI_DEBUG_CANQUEUE) {
1981 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
1982 "large\n");
1983 return;
1984 }
1985 spin_lock_irqsave(&queued_arr_lock, iflags);
1986 sqcp = &queued_arr[(int)indx];
1987 if (! sqcp->in_use) {
1988 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
1989 "interrupt\n");
1990 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1991 return;
1992 }
1993 sqcp->in_use = 0;
1994 if (sqcp->done_funct) {
1995 sqcp->a_cmnd->result = sqcp->scsi_result;
1996 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
1997 }
1998 sqcp->done_funct = NULL;
1999 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2000}
2001
2002static int scsi_debug_slave_alloc(struct scsi_device * sdp)
2003{
2004 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002005 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
2006 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 return 0;
2008}
2009
2010static int scsi_debug_slave_configure(struct scsi_device * sdp)
2011{
2012 struct sdebug_dev_info * devip;
2013
2014 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002015 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
2016 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
2018 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
2019 devip = devInfoReg(sdp);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002020 if (NULL == devip)
2021 return 1; /* no resources, will be marked offline */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 sdp->hostdata = devip;
2023 if (sdp->host->cmd_per_lun)
2024 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
2025 sdp->host->cmd_per_lun);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002026 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 return 0;
2028}
2029
2030static void scsi_debug_slave_destroy(struct scsi_device * sdp)
2031{
2032 struct sdebug_dev_info * devip =
2033 (struct sdebug_dev_info *)sdp->hostdata;
2034
2035 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002036 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
2037 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 if (devip) {
2039 /* make this slot avaliable for re-use */
2040 devip->used = 0;
2041 sdp->hostdata = NULL;
2042 }
2043}
2044
2045static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
2046{
2047 struct sdebug_host_info * sdbg_host;
2048 struct sdebug_dev_info * open_devip = NULL;
2049 struct sdebug_dev_info * devip =
2050 (struct sdebug_dev_info *)sdev->hostdata;
2051
2052 if (devip)
2053 return devip;
2054 sdbg_host = *(struct sdebug_host_info **) sdev->host->hostdata;
2055 if(! sdbg_host) {
2056 printk(KERN_ERR "Host info NULL\n");
2057 return NULL;
2058 }
2059 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
2060 if ((devip->used) && (devip->channel == sdev->channel) &&
2061 (devip->target == sdev->id) &&
2062 (devip->lun == sdev->lun))
2063 return devip;
2064 else {
2065 if ((!devip->used) && (!open_devip))
2066 open_devip = devip;
2067 }
2068 }
2069 if (NULL == open_devip) { /* try and make a new one */
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002070 open_devip = kzalloc(sizeof(*open_devip),GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 if (NULL == open_devip) {
2072 printk(KERN_ERR "%s: out of memory at line %d\n",
2073 __FUNCTION__, __LINE__);
2074 return NULL;
2075 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 open_devip->sdbg_host = sdbg_host;
2077 list_add_tail(&open_devip->dev_list,
2078 &sdbg_host->dev_info_list);
2079 }
2080 if (open_devip) {
2081 open_devip->channel = sdev->channel;
2082 open_devip->target = sdev->id;
2083 open_devip->lun = sdev->lun;
2084 open_devip->sdbg_host = sdbg_host;
2085 open_devip->reset = 1;
2086 open_devip->used = 1;
2087 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
2088 if (scsi_debug_dsense)
2089 open_devip->sense_buff[0] = 0x72;
2090 else {
2091 open_devip->sense_buff[0] = 0x70;
2092 open_devip->sense_buff[7] = 0xa;
2093 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002094 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2095 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 return open_devip;
2097 }
2098 return NULL;
2099}
2100
2101static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
2102 int asc, int asq)
2103{
2104 unsigned char * sbuff;
2105
2106 sbuff = devip->sense_buff;
2107 memset(sbuff, 0, SDEBUG_SENSE_LEN);
2108 if (scsi_debug_dsense) {
2109 sbuff[0] = 0x72; /* descriptor, current */
2110 sbuff[1] = key;
2111 sbuff[2] = asc;
2112 sbuff[3] = asq;
2113 } else {
2114 sbuff[0] = 0x70; /* fixed, current */
2115 sbuff[2] = key;
2116 sbuff[7] = 0xa; /* implies 18 byte sense buffer */
2117 sbuff[12] = asc;
2118 sbuff[13] = asq;
2119 }
2120 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2121 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
2122 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
2123}
2124
2125static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
2126{
2127 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2128 printk(KERN_INFO "scsi_debug: abort\n");
2129 ++num_aborts;
2130 stop_queued_cmnd(SCpnt);
2131 return SUCCESS;
2132}
2133
2134static int scsi_debug_biosparam(struct scsi_device *sdev,
2135 struct block_device * bdev, sector_t capacity, int *info)
2136{
2137 int res;
2138 unsigned char *buf;
2139
2140 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2141 printk(KERN_INFO "scsi_debug: biosparam\n");
2142 buf = scsi_bios_ptable(bdev);
2143 if (buf) {
2144 res = scsi_partsize(buf, capacity,
2145 &info[2], &info[0], &info[1]);
2146 kfree(buf);
2147 if (! res)
2148 return res;
2149 }
2150 info[0] = sdebug_heads;
2151 info[1] = sdebug_sectors_per;
2152 info[2] = sdebug_cylinders_per;
2153 return 0;
2154}
2155
2156static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
2157{
2158 struct sdebug_dev_info * devip;
2159
2160 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2161 printk(KERN_INFO "scsi_debug: device_reset\n");
2162 ++num_dev_resets;
2163 if (SCpnt) {
2164 devip = devInfoReg(SCpnt->device);
2165 if (devip)
2166 devip->reset = 1;
2167 }
2168 return SUCCESS;
2169}
2170
2171static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
2172{
2173 struct sdebug_host_info *sdbg_host;
2174 struct sdebug_dev_info * dev_info;
2175 struct scsi_device * sdp;
2176 struct Scsi_Host * hp;
2177
2178 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2179 printk(KERN_INFO "scsi_debug: bus_reset\n");
2180 ++num_bus_resets;
2181 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
2182 sdbg_host = *(struct sdebug_host_info **) hp->hostdata;
2183 if (sdbg_host) {
2184 list_for_each_entry(dev_info,
2185 &sdbg_host->dev_info_list,
2186 dev_list)
2187 dev_info->reset = 1;
2188 }
2189 }
2190 return SUCCESS;
2191}
2192
2193static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
2194{
2195 struct sdebug_host_info * sdbg_host;
2196 struct sdebug_dev_info * dev_info;
2197
2198 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2199 printk(KERN_INFO "scsi_debug: host_reset\n");
2200 ++num_host_resets;
2201 spin_lock(&sdebug_host_list_lock);
2202 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
2203 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
2204 dev_list)
2205 dev_info->reset = 1;
2206 }
2207 spin_unlock(&sdebug_host_list_lock);
2208 stop_all_queued();
2209 return SUCCESS;
2210}
2211
2212/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
2213static int stop_queued_cmnd(struct scsi_cmnd * cmnd)
2214{
2215 unsigned long iflags;
2216 int k;
2217 struct sdebug_queued_cmd * sqcp;
2218
2219 spin_lock_irqsave(&queued_arr_lock, iflags);
2220 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2221 sqcp = &queued_arr[k];
2222 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
2223 del_timer_sync(&sqcp->cmnd_timer);
2224 sqcp->in_use = 0;
2225 sqcp->a_cmnd = NULL;
2226 break;
2227 }
2228 }
2229 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2230 return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
2231}
2232
2233/* Deletes (stops) timers of all queued commands */
2234static void stop_all_queued(void)
2235{
2236 unsigned long iflags;
2237 int k;
2238 struct sdebug_queued_cmd * sqcp;
2239
2240 spin_lock_irqsave(&queued_arr_lock, iflags);
2241 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2242 sqcp = &queued_arr[k];
2243 if (sqcp->in_use && sqcp->a_cmnd) {
2244 del_timer_sync(&sqcp->cmnd_timer);
2245 sqcp->in_use = 0;
2246 sqcp->a_cmnd = NULL;
2247 }
2248 }
2249 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2250}
2251
2252/* Initializes timers in queued array */
2253static void __init init_all_queued(void)
2254{
2255 unsigned long iflags;
2256 int k;
2257 struct sdebug_queued_cmd * sqcp;
2258
2259 spin_lock_irqsave(&queued_arr_lock, iflags);
2260 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2261 sqcp = &queued_arr[k];
2262 init_timer(&sqcp->cmnd_timer);
2263 sqcp->in_use = 0;
2264 sqcp->a_cmnd = NULL;
2265 }
2266 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2267}
2268
2269static void __init sdebug_build_parts(unsigned char * ramp)
2270{
2271 struct partition * pp;
2272 int starts[SDEBUG_MAX_PARTS + 2];
2273 int sectors_per_part, num_sectors, k;
2274 int heads_by_sects, start_sec, end_sec;
2275
2276 /* assume partition table already zeroed */
2277 if ((scsi_debug_num_parts < 1) || (sdebug_store_size < 1048576))
2278 return;
2279 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
2280 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
2281 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
2282 "partitions to %d\n", SDEBUG_MAX_PARTS);
2283 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002284 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 sectors_per_part = (num_sectors - sdebug_sectors_per)
2286 / scsi_debug_num_parts;
2287 heads_by_sects = sdebug_heads * sdebug_sectors_per;
2288 starts[0] = sdebug_sectors_per;
2289 for (k = 1; k < scsi_debug_num_parts; ++k)
2290 starts[k] = ((k * sectors_per_part) / heads_by_sects)
2291 * heads_by_sects;
2292 starts[scsi_debug_num_parts] = num_sectors;
2293 starts[scsi_debug_num_parts + 1] = 0;
2294
2295 ramp[510] = 0x55; /* magic partition markings */
2296 ramp[511] = 0xAA;
2297 pp = (struct partition *)(ramp + 0x1be);
2298 for (k = 0; starts[k + 1]; ++k, ++pp) {
2299 start_sec = starts[k];
2300 end_sec = starts[k + 1] - 1;
2301 pp->boot_ind = 0;
2302
2303 pp->cyl = start_sec / heads_by_sects;
2304 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2305 / sdebug_sectors_per;
2306 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2307
2308 pp->end_cyl = end_sec / heads_by_sects;
2309 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2310 / sdebug_sectors_per;
2311 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2312
2313 pp->start_sect = start_sec;
2314 pp->nr_sects = end_sec - start_sec + 1;
2315 pp->sys_ind = 0x83; /* plain Linux partition */
2316 }
2317}
2318
2319static int schedule_resp(struct scsi_cmnd * cmnd,
2320 struct sdebug_dev_info * devip,
2321 done_funct_t done, int scsi_result, int delta_jiff)
2322{
2323 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2324 if (scsi_result) {
2325 struct scsi_device * sdp = cmnd->device;
2326
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002327 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2328 "non-zero result=0x%x\n", sdp->host->host_no,
2329 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330 }
2331 }
2332 if (cmnd && devip) {
2333 /* simulate autosense by this driver */
2334 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2335 memcpy(cmnd->sense_buffer, devip->sense_buff,
2336 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2337 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2338 }
2339 if (delta_jiff <= 0) {
2340 if (cmnd)
2341 cmnd->result = scsi_result;
2342 if (done)
2343 done(cmnd);
2344 return 0;
2345 } else {
2346 unsigned long iflags;
2347 int k;
2348 struct sdebug_queued_cmd * sqcp = NULL;
2349
2350 spin_lock_irqsave(&queued_arr_lock, iflags);
2351 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2352 sqcp = &queued_arr[k];
2353 if (! sqcp->in_use)
2354 break;
2355 }
2356 if (k >= SCSI_DEBUG_CANQUEUE) {
2357 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2358 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2359 return 1; /* report busy to mid level */
2360 }
2361 sqcp->in_use = 1;
2362 sqcp->a_cmnd = cmnd;
2363 sqcp->scsi_result = scsi_result;
2364 sqcp->done_funct = done;
2365 sqcp->cmnd_timer.function = timer_intr_handler;
2366 sqcp->cmnd_timer.data = k;
2367 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2368 add_timer(&sqcp->cmnd_timer);
2369 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2370 if (cmnd)
2371 cmnd->result = 0;
2372 return 0;
2373 }
2374}
2375
Douglas Gilbert23183912006-09-16 20:30:47 -04002376/* Note: The following macros create attribute files in the
2377 /sys/module/scsi_debug/parameters directory. Unfortunately this
2378 driver is unaware of a change and cannot trigger auxiliary actions
2379 as it can when the corresponding attribute in the
2380 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2381 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002382module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2383module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2384module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2385module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2386module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002387module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002388module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2389module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2390module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2391module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2392module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2393module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2394module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2395module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002396module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2397 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398
2399MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2400MODULE_DESCRIPTION("SCSI debug adapter driver");
2401MODULE_LICENSE("GPL");
2402MODULE_VERSION(SCSI_DEBUG_VERSION);
2403
2404MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2405MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002406MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2407MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07002408MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002409MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002410MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2411MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002413MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002414MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2416MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002417MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002418MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419
2420
2421static char sdebug_info[256];
2422
2423static const char * scsi_debug_info(struct Scsi_Host * shp)
2424{
2425 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2426 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2427 scsi_debug_version_date, scsi_debug_dev_size_mb,
2428 scsi_debug_opts);
2429 return sdebug_info;
2430}
2431
2432/* scsi_debug_proc_info
2433 * Used if the driver currently has no own support for /proc/scsi
2434 */
2435static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2436 int length, int inout)
2437{
2438 int len, pos, begin;
2439 int orig_length;
2440
2441 orig_length = length;
2442
2443 if (inout == 1) {
2444 char arr[16];
2445 int minLen = length > 15 ? 15 : length;
2446
2447 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2448 return -EACCES;
2449 memcpy(arr, buffer, minLen);
2450 arr[minLen] = '\0';
2451 if (1 != sscanf(arr, "%d", &pos))
2452 return -EINVAL;
2453 scsi_debug_opts = pos;
2454 if (scsi_debug_every_nth != 0)
2455 scsi_debug_cmnd_count = 0;
2456 return length;
2457 }
2458 begin = 0;
2459 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2460 "%s [%s]\n"
2461 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2462 "every_nth=%d(curr:%d)\n"
2463 "delay=%d, max_luns=%d, scsi_level=%d\n"
2464 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2465 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
2466 "host_resets=%d\n",
2467 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2468 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2469 scsi_debug_cmnd_count, scsi_debug_delay,
2470 scsi_debug_max_luns, scsi_debug_scsi_level,
2471 SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
2472 num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
2473 if (pos < offset) {
2474 len = 0;
2475 begin = pos;
2476 }
2477 *start = buffer + (offset - begin); /* Start of wanted data */
2478 len -= (offset - begin);
2479 if (len > length)
2480 len = length;
2481 return len;
2482}
2483
2484static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2485{
2486 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2487}
2488
2489static ssize_t sdebug_delay_store(struct device_driver * ddp,
2490 const char * buf, size_t count)
2491{
2492 int delay;
2493 char work[20];
2494
2495 if (1 == sscanf(buf, "%10s", work)) {
2496 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2497 scsi_debug_delay = delay;
2498 return count;
2499 }
2500 }
2501 return -EINVAL;
2502}
2503DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2504 sdebug_delay_store);
2505
2506static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2507{
2508 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2509}
2510
2511static ssize_t sdebug_opts_store(struct device_driver * ddp,
2512 const char * buf, size_t count)
2513{
2514 int opts;
2515 char work[20];
2516
2517 if (1 == sscanf(buf, "%10s", work)) {
2518 if (0 == strnicmp(work,"0x", 2)) {
2519 if (1 == sscanf(&work[2], "%x", &opts))
2520 goto opts_done;
2521 } else {
2522 if (1 == sscanf(work, "%d", &opts))
2523 goto opts_done;
2524 }
2525 }
2526 return -EINVAL;
2527opts_done:
2528 scsi_debug_opts = opts;
2529 scsi_debug_cmnd_count = 0;
2530 return count;
2531}
2532DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2533 sdebug_opts_store);
2534
2535static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2536{
2537 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2538}
2539static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2540 const char * buf, size_t count)
2541{
2542 int n;
2543
2544 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2545 scsi_debug_ptype = n;
2546 return count;
2547 }
2548 return -EINVAL;
2549}
2550DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2551
2552static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2553{
2554 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2555}
2556static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2557 const char * buf, size_t count)
2558{
2559 int n;
2560
2561 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2562 scsi_debug_dsense = n;
2563 return count;
2564 }
2565 return -EINVAL;
2566}
2567DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2568 sdebug_dsense_store);
2569
Douglas Gilbert23183912006-09-16 20:30:47 -04002570static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2571{
2572 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2573}
2574static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2575 const char * buf, size_t count)
2576{
2577 int n;
2578
2579 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2580 scsi_debug_fake_rw = n;
2581 return count;
2582 }
2583 return -EINVAL;
2584}
2585DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2586 sdebug_fake_rw_store);
2587
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002588static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2589{
2590 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2591}
2592static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2593 const char * buf, size_t count)
2594{
2595 int n;
2596
2597 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2598 scsi_debug_no_lun_0 = n;
2599 return count;
2600 }
2601 return -EINVAL;
2602}
2603DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2604 sdebug_no_lun_0_store);
2605
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2607{
2608 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2609}
2610static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2611 const char * buf, size_t count)
2612{
2613 int n;
2614
2615 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2616 scsi_debug_num_tgts = n;
2617 sdebug_max_tgts_luns();
2618 return count;
2619 }
2620 return -EINVAL;
2621}
2622DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2623 sdebug_num_tgts_store);
2624
2625static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2626{
2627 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2628}
2629DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2630
2631static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2632{
2633 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2634}
2635DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2636
2637static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2638{
2639 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2640}
2641static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2642 const char * buf, size_t count)
2643{
2644 int nth;
2645
2646 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2647 scsi_debug_every_nth = nth;
2648 scsi_debug_cmnd_count = 0;
2649 return count;
2650 }
2651 return -EINVAL;
2652}
2653DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2654 sdebug_every_nth_store);
2655
2656static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2657{
2658 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2659}
2660static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2661 const char * buf, size_t count)
2662{
2663 int n;
2664
2665 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2666 scsi_debug_max_luns = n;
2667 sdebug_max_tgts_luns();
2668 return count;
2669 }
2670 return -EINVAL;
2671}
2672DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2673 sdebug_max_luns_store);
2674
2675static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
2676{
2677 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
2678}
2679DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
2680
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002681static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2682{
2683 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2684}
2685static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2686 const char * buf, size_t count)
2687{
2688 int n;
2689
2690 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2691 scsi_debug_virtual_gb = n;
2692 if (scsi_debug_virtual_gb > 0) {
2693 sdebug_capacity = 2048 * 1024;
2694 sdebug_capacity *= scsi_debug_virtual_gb;
2695 } else
2696 sdebug_capacity = sdebug_store_sectors;
2697 return count;
2698 }
2699 return -EINVAL;
2700}
2701DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2702 sdebug_virtual_gb_store);
2703
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
2705{
2706 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
2707}
2708
2709static ssize_t sdebug_add_host_store(struct device_driver * ddp,
2710 const char * buf, size_t count)
2711{
2712 int delta_hosts;
2713 char work[20];
2714
2715 if (1 != sscanf(buf, "%10s", work))
2716 return -EINVAL;
2717 { /* temporary hack around sscanf() problem with -ve nums */
2718 int neg = 0;
2719
2720 if ('-' == *work)
2721 neg = 1;
2722 if (1 != sscanf(work + neg, "%d", &delta_hosts))
2723 return -EINVAL;
2724 if (neg)
2725 delta_hosts = -delta_hosts;
2726 }
2727 if (delta_hosts > 0) {
2728 do {
2729 sdebug_add_adapter();
2730 } while (--delta_hosts);
2731 } else if (delta_hosts < 0) {
2732 do {
2733 sdebug_remove_adapter();
2734 } while (++delta_hosts);
2735 }
2736 return count;
2737}
2738DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
2739 sdebug_add_host_store);
2740
Douglas Gilbert23183912006-09-16 20:30:47 -04002741static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
2742 char * buf)
2743{
2744 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
2745}
2746static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
2747 const char * buf, size_t count)
2748{
2749 int n;
2750
2751 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2752 scsi_debug_vpd_use_hostno = n;
2753 return count;
2754 }
2755 return -EINVAL;
2756}
2757DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
2758 sdebug_vpd_use_hostno_store);
2759
2760/* Note: The following function creates attribute files in the
2761 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
2762 files (over those found in the /sys/module/scsi_debug/parameters
2763 directory) is that auxiliary actions can be triggered when an attribute
2764 is changed. For example see: sdebug_add_host_store() above.
2765 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002766static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002768 int ret;
2769
2770 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2771 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
2772 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2773 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2774 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04002775 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002776 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002777 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002778 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002779 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002780 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
2781 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
2782 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04002783 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
2784 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002785 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786}
2787
2788static void do_remove_driverfs_files(void)
2789{
Douglas Gilbert23183912006-09-16 20:30:47 -04002790 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
2791 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
2793 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
2794 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002796 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
2797 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002799 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
2801 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2802 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2803 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
2804 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2805}
2806
2807static int __init scsi_debug_init(void)
2808{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002809 unsigned int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 int host_to_add;
2811 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002812 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813
2814 if (scsi_debug_dev_size_mb < 1)
2815 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002816 sdebug_store_size = (unsigned int)scsi_debug_dev_size_mb * 1048576;
2817 sdebug_store_sectors = sdebug_store_size / SECT_SIZE;
2818 if (scsi_debug_virtual_gb > 0) {
2819 sdebug_capacity = 2048 * 1024;
2820 sdebug_capacity *= scsi_debug_virtual_gb;
2821 } else
2822 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823
2824 /* play around with geometry, don't waste too much on track 0 */
2825 sdebug_heads = 8;
2826 sdebug_sectors_per = 32;
2827 if (scsi_debug_dev_size_mb >= 16)
2828 sdebug_heads = 32;
2829 else if (scsi_debug_dev_size_mb >= 256)
2830 sdebug_heads = 64;
2831 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2832 (sdebug_sectors_per * sdebug_heads);
2833 if (sdebug_cylinders_per >= 1024) {
2834 /* other LLDs do this; implies >= 1GB ram disk ... */
2835 sdebug_heads = 255;
2836 sdebug_sectors_per = 63;
2837 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2838 (sdebug_sectors_per * sdebug_heads);
2839 }
2840
2841 sz = sdebug_store_size;
2842 fake_storep = vmalloc(sz);
2843 if (NULL == fake_storep) {
2844 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
2845 return -ENOMEM;
2846 }
2847 memset(fake_storep, 0, sz);
2848 if (scsi_debug_num_parts > 0)
2849 sdebug_build_parts(fake_storep);
2850
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002851 ret = device_register(&pseudo_primary);
2852 if (ret < 0) {
2853 printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
2854 ret);
2855 goto free_vm;
2856 }
2857 ret = bus_register(&pseudo_lld_bus);
2858 if (ret < 0) {
2859 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
2860 ret);
2861 goto dev_unreg;
2862 }
2863 ret = driver_register(&sdebug_driverfs_driver);
2864 if (ret < 0) {
2865 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
2866 ret);
2867 goto bus_unreg;
2868 }
2869 ret = do_create_driverfs_files();
2870 if (ret < 0) {
2871 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
2872 ret);
2873 goto del_files;
2874 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002876 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877
2878 sdebug_driver_template.proc_name = (char *)sdebug_proc_name;
2879
2880 host_to_add = scsi_debug_add_host;
2881 scsi_debug_add_host = 0;
2882
2883 for (k = 0; k < host_to_add; k++) {
2884 if (sdebug_add_adapter()) {
2885 printk(KERN_ERR "scsi_debug_init: "
2886 "sdebug_add_adapter failed k=%d\n", k);
2887 break;
2888 }
2889 }
2890
2891 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
2892 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
2893 scsi_debug_add_host);
2894 }
2895 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002896
2897del_files:
2898 do_remove_driverfs_files();
2899 driver_unregister(&sdebug_driverfs_driver);
2900bus_unreg:
2901 bus_unregister(&pseudo_lld_bus);
2902dev_unreg:
2903 device_unregister(&pseudo_primary);
2904free_vm:
2905 vfree(fake_storep);
2906
2907 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908}
2909
2910static void __exit scsi_debug_exit(void)
2911{
2912 int k = scsi_debug_add_host;
2913
2914 stop_all_queued();
2915 for (; k; k--)
2916 sdebug_remove_adapter();
2917 do_remove_driverfs_files();
2918 driver_unregister(&sdebug_driverfs_driver);
2919 bus_unregister(&pseudo_lld_bus);
2920 device_unregister(&pseudo_primary);
2921
2922 vfree(fake_storep);
2923}
2924
2925device_initcall(scsi_debug_init);
2926module_exit(scsi_debug_exit);
2927
Adrian Bunk52c1da32005-06-23 22:05:33 -07002928static void pseudo_0_release(struct device * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929{
2930 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2931 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
2932}
2933
2934static struct device pseudo_primary = {
2935 .bus_id = "pseudo_0",
2936 .release = pseudo_0_release,
2937};
2938
2939static int pseudo_lld_bus_match(struct device *dev,
2940 struct device_driver *dev_driver)
2941{
2942 return 1;
2943}
2944
2945static struct bus_type pseudo_lld_bus = {
2946 .name = "pseudo",
2947 .match = pseudo_lld_bus_match,
Russell Kingbbbe3a42006-01-05 14:44:46 +00002948 .probe = sdebug_driver_probe,
2949 .remove = sdebug_driver_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950};
2951
2952static void sdebug_release_adapter(struct device * dev)
2953{
2954 struct sdebug_host_info *sdbg_host;
2955
2956 sdbg_host = to_sdebug_host(dev);
2957 kfree(sdbg_host);
2958}
2959
2960static int sdebug_add_adapter(void)
2961{
2962 int k, devs_per_host;
2963 int error = 0;
2964 struct sdebug_host_info *sdbg_host;
2965 struct sdebug_dev_info *sdbg_devinfo;
2966 struct list_head *lh, *lh_sf;
2967
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002968 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 if (NULL == sdbg_host) {
2970 printk(KERN_ERR "%s: out of memory at line %d\n",
2971 __FUNCTION__, __LINE__);
2972 return -ENOMEM;
2973 }
2974
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
2976
2977 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
2978 for (k = 0; k < devs_per_host; k++) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002979 sdbg_devinfo = kzalloc(sizeof(*sdbg_devinfo),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980 if (NULL == sdbg_devinfo) {
2981 printk(KERN_ERR "%s: out of memory at line %d\n",
2982 __FUNCTION__, __LINE__);
2983 error = -ENOMEM;
2984 goto clean;
2985 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 sdbg_devinfo->sdbg_host = sdbg_host;
2987 list_add_tail(&sdbg_devinfo->dev_list,
2988 &sdbg_host->dev_info_list);
2989 }
2990
2991 spin_lock(&sdebug_host_list_lock);
2992 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
2993 spin_unlock(&sdebug_host_list_lock);
2994
2995 sdbg_host->dev.bus = &pseudo_lld_bus;
2996 sdbg_host->dev.parent = &pseudo_primary;
2997 sdbg_host->dev.release = &sdebug_release_adapter;
2998 sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host);
2999
3000 error = device_register(&sdbg_host->dev);
3001
3002 if (error)
3003 goto clean;
3004
3005 ++scsi_debug_add_host;
3006 return error;
3007
3008clean:
3009 list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) {
3010 sdbg_devinfo = list_entry(lh, struct sdebug_dev_info,
3011 dev_list);
3012 list_del(&sdbg_devinfo->dev_list);
3013 kfree(sdbg_devinfo);
3014 }
3015
3016 kfree(sdbg_host);
3017 return error;
3018}
3019
3020static void sdebug_remove_adapter(void)
3021{
3022 struct sdebug_host_info * sdbg_host = NULL;
3023
3024 spin_lock(&sdebug_host_list_lock);
3025 if (!list_empty(&sdebug_host_list)) {
3026 sdbg_host = list_entry(sdebug_host_list.prev,
3027 struct sdebug_host_info, host_list);
3028 list_del(&sdbg_host->host_list);
3029 }
3030 spin_unlock(&sdebug_host_list_lock);
3031
3032 if (!sdbg_host)
3033 return;
3034
3035 device_unregister(&sdbg_host->dev);
3036 --scsi_debug_add_host;
3037}
3038
3039static int sdebug_driver_probe(struct device * dev)
3040{
3041 int error = 0;
3042 struct sdebug_host_info *sdbg_host;
3043 struct Scsi_Host *hpnt;
3044
3045 sdbg_host = to_sdebug_host(dev);
3046
3047 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
3048 if (NULL == hpnt) {
3049 printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__);
3050 error = -ENODEV;
3051 return error;
3052 }
3053
3054 sdbg_host->shost = hpnt;
3055 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
3056 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
3057 hpnt->max_id = scsi_debug_num_tgts + 1;
3058 else
3059 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003060 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061
3062 error = scsi_add_host(hpnt, &sdbg_host->dev);
3063 if (error) {
3064 printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
3065 error = -ENODEV;
3066 scsi_host_put(hpnt);
3067 } else
3068 scsi_scan_host(hpnt);
3069
3070
3071 return error;
3072}
3073
3074static int sdebug_driver_remove(struct device * dev)
3075{
3076 struct list_head *lh, *lh_sf;
3077 struct sdebug_host_info *sdbg_host;
3078 struct sdebug_dev_info *sdbg_devinfo;
3079
3080 sdbg_host = to_sdebug_host(dev);
3081
3082 if (!sdbg_host) {
3083 printk(KERN_ERR "%s: Unable to locate host info\n",
3084 __FUNCTION__);
3085 return -ENODEV;
3086 }
3087
3088 scsi_remove_host(sdbg_host->shost);
3089
3090 list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) {
3091 sdbg_devinfo = list_entry(lh, struct sdebug_dev_info,
3092 dev_list);
3093 list_del(&sdbg_devinfo->dev_list);
3094 kfree(sdbg_devinfo);
3095 }
3096
3097 scsi_host_put(sdbg_host->shost);
3098 return 0;
3099}
3100
3101static void sdebug_max_tgts_luns(void)
3102{
3103 struct sdebug_host_info * sdbg_host;
3104 struct Scsi_Host *hpnt;
3105
3106 spin_lock(&sdebug_host_list_lock);
3107 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3108 hpnt = sdbg_host->shost;
3109 if ((hpnt->this_id >= 0) &&
3110 (scsi_debug_num_tgts > hpnt->this_id))
3111 hpnt->max_id = scsi_debug_num_tgts + 1;
3112 else
3113 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003114 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115 }
3116 spin_unlock(&sdebug_host_list_lock);
3117}