blob: 4f4c5b7bdef5ce386bd1a4eefbd10cce0a4d2705 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3 * Copyright (C) 1992 Eric Youngdale
4 * Simulate a host adapter with 2 disks attached. Do a lot of checking
5 * to make sure that we are not getting blocks mixed up, and PANIC if
6 * anything out of the ordinary is seen.
7 * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8 *
9 * This version is more generic, simulating a variable number of disk
Douglas Gilbert23183912006-09-16 20:30:47 -040010 * (or disk like devices) sharing a common amount of RAM. To be more
11 * realistic, the simulated devices have the transport attributes of
12 * SAS disks.
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 *
14 *
15 * For documentation see http://www.torque.net/sg/sdebug26.html
16 *
17 * D. Gilbert (dpg) work for Magneto-Optical device test [20010421]
18 * dpg: work for devfs large number of disks [20010809]
19 * forked for lk 2.5 series [20011216, 20020101]
20 * use vmalloc() more inquiry+mode_sense [20020302]
21 * add timers for delayed responses [20020721]
22 * Patrick Mansfield <patmans@us.ibm.com> max_luns+scsi_level [20021031]
23 * Mike Anderson <andmike@us.ibm.com> sysfs work [20021118]
24 * dpg: change style of boot options to "scsi_debug.num_tgts=2" and
25 * module options to "modprobe scsi_debug num_tgts=2" [20021221]
26 */
27
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/module.h>
29
30#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/errno.h>
32#include <linux/timer.h>
33#include <linux/types.h>
34#include <linux/string.h>
35#include <linux/genhd.h>
36#include <linux/fs.h>
37#include <linux/init.h>
38#include <linux/proc_fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <linux/vmalloc.h>
40#include <linux/moduleparam.h>
Jens Axboe852e0342007-07-16 10:19:24 +020041#include <linux/scatterlist.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <linux/blkdev.h>
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090043
44#include <scsi/scsi.h>
45#include <scsi/scsi_cmnd.h>
46#include <scsi/scsi_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <scsi/scsi_host.h>
48#include <scsi/scsicam.h>
49
50#include <linux/stat.h>
51
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include "scsi_logging.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050054#define SCSI_DEBUG_VERSION "1.81"
55static const char * scsi_debug_version_date = "20070104";
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050057/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040058#define NO_ADDITIONAL_SENSE 0x0
59#define LOGICAL_UNIT_NOT_READY 0x4
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040061#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#define INVALID_OPCODE 0x20
63#define ADDR_OUT_OF_RANGE 0x21
64#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040065#define INVALID_FIELD_IN_PARAM_LIST 0x26
Linus Torvalds1da177e2005-04-16 15:20:36 -070066#define POWERON_RESET 0x29
67#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050068#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040069#define THRESHOLD_EXCEEDED 0x5d
70#define LOW_POWER_COND_ON 0x5e
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050072/* Additional Sense Code Qualifier (ASCQ) */
73#define ACK_NAK_TO 0x3
74
Linus Torvalds1da177e2005-04-16 15:20:36 -070075#define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
76
77/* Default values for driver parameters */
78#define DEF_NUM_HOST 1
79#define DEF_NUM_TGTS 1
80#define DEF_MAX_LUNS 1
81/* With these defaults, this driver will make 1 host with 1 target
82 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
83 */
84#define DEF_DELAY 1
85#define DEF_DEV_SIZE_MB 8
86#define DEF_EVERY_NTH 0
87#define DEF_NUM_PARTS 0
88#define DEF_OPTS 0
89#define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */
90#define DEF_PTYPE 0
91#define DEF_D_SENSE 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -040092#define DEF_NO_LUN_0 0
93#define DEF_VIRTUAL_GB 0
Douglas Gilbert23183912006-09-16 20:30:47 -040094#define DEF_FAKE_RW 0
95#define DEF_VPD_USE_HOSTNO 1
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
97/* bit mask values for scsi_debug_opts */
98#define SCSI_DEBUG_OPT_NOISE 1
99#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
100#define SCSI_DEBUG_OPT_TIMEOUT 4
101#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500102#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103/* When "every_nth" > 0 then modulo "every_nth" commands:
104 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
105 * - a RECOVERED_ERROR is simulated on successful read and write
106 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500107 * - a TRANSPORT_ERROR is simulated on successful read and write
108 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 *
110 * When "every_nth" < 0 then after "- every_nth" commands:
111 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
112 * - a RECOVERED_ERROR is simulated on successful read and write
113 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500114 * - a TRANSPORT_ERROR is simulated on successful read and write
115 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 * This will continue until some other action occurs (e.g. the user
117 * writing a new value (other than -1 or 1) to every_nth via sysfs).
118 */
119
120/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
121 * sector on read commands: */
122#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
123
124/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
125 * or "peripheral device" addressing (value 0) */
126#define SAM2_LUN_ADDRESS_METHOD 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400127#define SAM2_WLUN_REPORT_LUNS 0xc101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128
129static int scsi_debug_add_host = DEF_NUM_HOST;
130static int scsi_debug_delay = DEF_DELAY;
131static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
132static int scsi_debug_every_nth = DEF_EVERY_NTH;
133static int scsi_debug_max_luns = DEF_MAX_LUNS;
134static int scsi_debug_num_parts = DEF_NUM_PARTS;
135static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
136static int scsi_debug_opts = DEF_OPTS;
137static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
138static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
139static int scsi_debug_dsense = DEF_D_SENSE;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400140static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
141static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
Douglas Gilbert23183912006-09-16 20:30:47 -0400142static int scsi_debug_fake_rw = DEF_FAKE_RW;
143static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
145static int scsi_debug_cmnd_count = 0;
146
147#define DEV_READONLY(TGT) (0)
148#define DEV_REMOVEABLE(TGT) (0)
149
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400150static unsigned int sdebug_store_size; /* in bytes */
151static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152static sector_t sdebug_capacity; /* in sectors */
153
154/* old BIOS stuff, kernel may get rid of them but some mode sense pages
155 may still need them */
156static int sdebug_heads; /* heads per disk */
157static int sdebug_cylinders_per; /* cylinders per surface */
158static int sdebug_sectors_per; /* sectors per cylinder */
159
160/* default sector size is 512 bytes, 2**9 bytes */
161#define POW2_SECT_SIZE 9
162#define SECT_SIZE (1 << POW2_SECT_SIZE)
163#define SECT_SIZE_PER(TGT) SECT_SIZE
164
165#define SDEBUG_MAX_PARTS 4
166
167#define SDEBUG_SENSE_LEN 32
168
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +0900169#define SCSI_DEBUG_CANQUEUE 255
170#define SCSI_DEBUG_MAX_CMD_LEN 16
171
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172struct sdebug_dev_info {
173 struct list_head dev_list;
174 unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */
175 unsigned int channel;
176 unsigned int target;
177 unsigned int lun;
178 struct sdebug_host_info *sdbg_host;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400179 unsigned int wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 char reset;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400181 char stopped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 char used;
183};
184
185struct sdebug_host_info {
186 struct list_head host_list;
187 struct Scsi_Host *shost;
188 struct device dev;
189 struct list_head dev_info_list;
190};
191
192#define to_sdebug_host(d) \
193 container_of(d, struct sdebug_host_info, dev)
194
195static LIST_HEAD(sdebug_host_list);
196static DEFINE_SPINLOCK(sdebug_host_list_lock);
197
198typedef void (* done_funct_t) (struct scsi_cmnd *);
199
200struct sdebug_queued_cmd {
201 int in_use;
202 struct timer_list cmnd_timer;
203 done_funct_t done_funct;
204 struct scsi_cmnd * a_cmnd;
205 int scsi_result;
206};
207static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
208
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209static unsigned char * fake_storep; /* ramdisk storage */
210
211static int num_aborts = 0;
212static int num_dev_resets = 0;
213static int num_bus_resets = 0;
214static int num_host_resets = 0;
215
216static DEFINE_SPINLOCK(queued_arr_lock);
217static DEFINE_RWLOCK(atomic_rw);
218
219static char sdebug_proc_name[] = "scsi_debug";
220
221static int sdebug_driver_probe(struct device *);
222static int sdebug_driver_remove(struct device *);
223static struct bus_type pseudo_lld_bus;
224
225static struct device_driver sdebug_driverfs_driver = {
226 .name = sdebug_proc_name,
227 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228};
229
230static const int check_condition_result =
231 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
232
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400233static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
234 0, 0, 0x2, 0x4b};
235static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
236 0, 0, 0x0, 0x0};
237
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev);
239static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
240 int asc, int asq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241static void stop_all_queued(void);
242static int stop_queued_cmnd(struct scsi_cmnd * cmnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
244static int sdebug_add_adapter(void);
245static void sdebug_remove_adapter(void);
246static void sdebug_max_tgts_luns(void);
247
248static struct device pseudo_primary;
249static struct bus_type pseudo_lld_bus;
250
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900251static void get_data_transfer_info(unsigned char *cmd,
252 unsigned long long *lba, unsigned int *num)
253{
254 int i;
255
256 switch (*cmd) {
257 case WRITE_16:
258 case READ_16:
259 for (*lba = 0, i = 0; i < 8; ++i) {
260 if (i > 0)
261 *lba <<= 8;
262 *lba += cmd[2 + i];
263 }
264 *num = cmd[13] + (cmd[12] << 8) +
265 (cmd[11] << 16) + (cmd[10] << 24);
266 break;
267 case WRITE_12:
268 case READ_12:
269 *lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
270 *num = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
271 break;
272 case WRITE_10:
273 case READ_10:
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900274 case XDWRITEREAD_10:
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900275 *lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
276 *num = cmd[8] + (cmd[7] << 8);
277 break;
278 case WRITE_6:
279 case READ_6:
280 *lba = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
281 *num = (0 == cmd[4]) ? 256 : cmd[4];
282 break;
283 default:
284 break;
285 }
286}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
289{
290 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
291 printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
292 }
293 return -EINVAL;
294 /* return -ENOTTY; // correct return but upsets fdisk */
295}
296
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400297static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
298 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299{
300 if (devip->reset) {
301 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
302 printk(KERN_INFO "scsi_debug: Reporting Unit "
303 "attention: power on reset\n");
304 devip->reset = 0;
305 mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
306 return check_condition_result;
307 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400308 if ((0 == reset_only) && devip->stopped) {
309 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
310 printk(KERN_INFO "scsi_debug: Reporting Not "
311 "ready: initializing command required\n");
312 mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
313 0x2);
314 return check_condition_result;
315 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 return 0;
317}
318
319/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900320static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 int arr_len)
322{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900323 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900324 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900326 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900328 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 return (DID_ERROR << 16);
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900330
331 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
332 arr, arr_len);
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900333 if (sdb->resid)
334 sdb->resid -= act_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400335 else
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900336 sdb->resid = scsi_bufflen(scp) - act_len;
337
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 return 0;
339}
340
341/* Returns number of bytes fetched into 'arr' or -1 if error. */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900342static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
343 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900345 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900347 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900349
350 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351}
352
353
354static const char * inq_vendor_id = "Linux ";
355static const char * inq_product_id = "scsi_debug ";
356static const char * inq_product_rev = "0004";
357
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200358static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
359 int target_dev_id, int dev_id_num,
360 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400361 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400363 int num, port_a;
364 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400366 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 /* T10 vendor identifier field format (faked) */
368 arr[0] = 0x2; /* ASCII */
369 arr[1] = 0x1;
370 arr[2] = 0x0;
371 memcpy(&arr[4], inq_vendor_id, 8);
372 memcpy(&arr[12], inq_product_id, 16);
373 memcpy(&arr[28], dev_id_str, dev_id_str_len);
374 num = 8 + 16 + dev_id_str_len;
375 arr[3] = num;
376 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400377 if (dev_id_num >= 0) {
378 /* NAA-5, Logical unit identifier (binary) */
379 arr[num++] = 0x1; /* binary (not necessarily sas) */
380 arr[num++] = 0x3; /* PIV=0, lu, naa */
381 arr[num++] = 0x0;
382 arr[num++] = 0x8;
383 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
384 arr[num++] = 0x33;
385 arr[num++] = 0x33;
386 arr[num++] = 0x30;
387 arr[num++] = (dev_id_num >> 24);
388 arr[num++] = (dev_id_num >> 16) & 0xff;
389 arr[num++] = (dev_id_num >> 8) & 0xff;
390 arr[num++] = dev_id_num & 0xff;
391 /* Target relative port number */
392 arr[num++] = 0x61; /* proto=sas, binary */
393 arr[num++] = 0x94; /* PIV=1, target port, rel port */
394 arr[num++] = 0x0; /* reserved */
395 arr[num++] = 0x4; /* length */
396 arr[num++] = 0x0; /* reserved */
397 arr[num++] = 0x0; /* reserved */
398 arr[num++] = 0x0;
399 arr[num++] = 0x1; /* relative port A */
400 }
401 /* NAA-5, Target port identifier */
402 arr[num++] = 0x61; /* proto=sas, binary */
403 arr[num++] = 0x93; /* piv=1, target port, naa */
404 arr[num++] = 0x0;
405 arr[num++] = 0x8;
406 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
407 arr[num++] = 0x22;
408 arr[num++] = 0x22;
409 arr[num++] = 0x20;
410 arr[num++] = (port_a >> 24);
411 arr[num++] = (port_a >> 16) & 0xff;
412 arr[num++] = (port_a >> 8) & 0xff;
413 arr[num++] = port_a & 0xff;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200414 /* NAA-5, Target port group identifier */
415 arr[num++] = 0x61; /* proto=sas, binary */
416 arr[num++] = 0x95; /* piv=1, target port group id */
417 arr[num++] = 0x0;
418 arr[num++] = 0x4;
419 arr[num++] = 0;
420 arr[num++] = 0;
421 arr[num++] = (port_group_id >> 8) & 0xff;
422 arr[num++] = port_group_id & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400423 /* NAA-5, Target device identifier */
424 arr[num++] = 0x61; /* proto=sas, binary */
425 arr[num++] = 0xa3; /* piv=1, target device, naa */
426 arr[num++] = 0x0;
427 arr[num++] = 0x8;
428 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
429 arr[num++] = 0x22;
430 arr[num++] = 0x22;
431 arr[num++] = 0x20;
432 arr[num++] = (target_dev_id >> 24);
433 arr[num++] = (target_dev_id >> 16) & 0xff;
434 arr[num++] = (target_dev_id >> 8) & 0xff;
435 arr[num++] = target_dev_id & 0xff;
436 /* SCSI name string: Target device identifier */
437 arr[num++] = 0x63; /* proto=sas, UTF-8 */
438 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
439 arr[num++] = 0x0;
440 arr[num++] = 24;
441 memcpy(arr + num, "naa.52222220", 12);
442 num += 12;
443 snprintf(b, sizeof(b), "%08X", target_dev_id);
444 memcpy(arr + num, b, 8);
445 num += 8;
446 memset(arr + num, 0, 4);
447 num += 4;
448 return num;
449}
450
451
452static unsigned char vpd84_data[] = {
453/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
454 0x22,0x22,0x22,0x0,0xbb,0x1,
455 0x22,0x22,0x22,0x0,0xbb,0x2,
456};
457
458static int inquiry_evpd_84(unsigned char * arr)
459{
460 memcpy(arr, vpd84_data, sizeof(vpd84_data));
461 return sizeof(vpd84_data);
462}
463
464static int inquiry_evpd_85(unsigned char * arr)
465{
466 int num = 0;
467 const char * na1 = "https://www.kernel.org/config";
468 const char * na2 = "http://www.kernel.org/log";
469 int plen, olen;
470
471 arr[num++] = 0x1; /* lu, storage config */
472 arr[num++] = 0x0; /* reserved */
473 arr[num++] = 0x0;
474 olen = strlen(na1);
475 plen = olen + 1;
476 if (plen % 4)
477 plen = ((plen / 4) + 1) * 4;
478 arr[num++] = plen; /* length, null termianted, padded */
479 memcpy(arr + num, na1, olen);
480 memset(arr + num + olen, 0, plen - olen);
481 num += plen;
482
483 arr[num++] = 0x4; /* lu, logging */
484 arr[num++] = 0x0; /* reserved */
485 arr[num++] = 0x0;
486 olen = strlen(na2);
487 plen = olen + 1;
488 if (plen % 4)
489 plen = ((plen / 4) + 1) * 4;
490 arr[num++] = plen; /* length, null terminated, padded */
491 memcpy(arr + num, na2, olen);
492 memset(arr + num + olen, 0, plen - olen);
493 num += plen;
494
495 return num;
496}
497
498/* SCSI ports VPD page */
499static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
500{
501 int num = 0;
502 int port_a, port_b;
503
504 port_a = target_dev_id + 1;
505 port_b = port_a + 1;
506 arr[num++] = 0x0; /* reserved */
507 arr[num++] = 0x0; /* reserved */
508 arr[num++] = 0x0;
509 arr[num++] = 0x1; /* relative port 1 (primary) */
510 memset(arr + num, 0, 6);
511 num += 6;
512 arr[num++] = 0x0;
513 arr[num++] = 12; /* length tp descriptor */
514 /* naa-5 target port identifier (A) */
515 arr[num++] = 0x61; /* proto=sas, binary */
516 arr[num++] = 0x93; /* PIV=1, target port, NAA */
517 arr[num++] = 0x0; /* reserved */
518 arr[num++] = 0x8; /* length */
519 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
520 arr[num++] = 0x22;
521 arr[num++] = 0x22;
522 arr[num++] = 0x20;
523 arr[num++] = (port_a >> 24);
524 arr[num++] = (port_a >> 16) & 0xff;
525 arr[num++] = (port_a >> 8) & 0xff;
526 arr[num++] = port_a & 0xff;
527
528 arr[num++] = 0x0; /* reserved */
529 arr[num++] = 0x0; /* reserved */
530 arr[num++] = 0x0;
531 arr[num++] = 0x2; /* relative port 2 (secondary) */
532 memset(arr + num, 0, 6);
533 num += 6;
534 arr[num++] = 0x0;
535 arr[num++] = 12; /* length tp descriptor */
536 /* naa-5 target port identifier (B) */
537 arr[num++] = 0x61; /* proto=sas, binary */
538 arr[num++] = 0x93; /* PIV=1, target port, NAA */
539 arr[num++] = 0x0; /* reserved */
540 arr[num++] = 0x8; /* length */
541 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
542 arr[num++] = 0x22;
543 arr[num++] = 0x22;
544 arr[num++] = 0x20;
545 arr[num++] = (port_b >> 24);
546 arr[num++] = (port_b >> 16) & 0xff;
547 arr[num++] = (port_b >> 8) & 0xff;
548 arr[num++] = port_b & 0xff;
549
550 return num;
551}
552
553
554static unsigned char vpd89_data[] = {
555/* from 4th byte */ 0,0,0,0,
556'l','i','n','u','x',' ',' ',' ',
557'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
558'1','2','3','4',
5590x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
5600xec,0,0,0,
5610x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
5620,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
5630x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
5640x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
5650x53,0x41,
5660x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
5670x20,0x20,
5680x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
5690x10,0x80,
5700,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
5710x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
5720x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
5730,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
5740x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
5750x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
5760,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
5770,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5780,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5790,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5800x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
5810,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
5820xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
5830,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
5840,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5850,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5860,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5870,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5880,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5890,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5900,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5910,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5920,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5930,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5940,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5950,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
596};
597
598static int inquiry_evpd_89(unsigned char * arr)
599{
600 memcpy(arr, vpd89_data, sizeof(vpd89_data));
601 return sizeof(vpd89_data);
602}
603
604
605static unsigned char vpdb0_data[] = {
606 /* from 4th byte */ 0,0,0,4,
607 0,0,0x4,0,
608 0,0,0,64,
609};
610
611static int inquiry_evpd_b0(unsigned char * arr)
612{
613 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
614 if (sdebug_store_sectors > 0x400) {
615 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
616 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
617 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
618 arr[7] = sdebug_store_sectors & 0xff;
619 }
620 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621}
622
623
624#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400625#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626
627static int resp_inquiry(struct scsi_cmnd * scp, int target,
628 struct sdebug_dev_info * devip)
629{
630 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200631 unsigned char * arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 unsigned char *cmd = (unsigned char *)scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200633 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634
635 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500636 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
637 if (! arr)
638 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400639 if (devip->wlun)
640 pq_pdt = 0x1e; /* present, wlun */
641 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
642 pq_pdt = 0x7f; /* not present, no device type */
643 else
644 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 arr[0] = pq_pdt;
646 if (0x2 & cmd[1]) { /* CMDDT bit set */
647 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
648 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200649 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 return check_condition_result;
651 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200652 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400653 char lu_id_str[6];
654 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200656 port_group_id = (((host_no + 1) & 0x7f) << 8) +
657 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -0400658 if (0 == scsi_debug_vpd_use_hostno)
659 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400660 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
661 (devip->target * 1000) + devip->lun);
662 target_dev_id = ((host_no + 1) * 2000) +
663 (devip->target * 1000) - 3;
664 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400666 arr[1] = cmd[2]; /*sanity */
667 n = 4;
668 arr[n++] = 0x0; /* this page */
669 arr[n++] = 0x80; /* unit serial number */
670 arr[n++] = 0x83; /* device identification */
671 arr[n++] = 0x84; /* software interface ident. */
672 arr[n++] = 0x85; /* management network addresses */
673 arr[n++] = 0x86; /* extended inquiry */
674 arr[n++] = 0x87; /* mode page policy */
675 arr[n++] = 0x88; /* SCSI ports */
676 arr[n++] = 0x89; /* ATA information */
677 arr[n++] = 0xb0; /* Block limits (SBC) */
678 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400680 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400682 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400684 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200685 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
686 target_dev_id, lu_id_num,
687 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400688 } else if (0x84 == cmd[2]) { /* Software interface ident. */
689 arr[1] = cmd[2]; /*sanity */
690 arr[3] = inquiry_evpd_84(&arr[4]);
691 } else if (0x85 == cmd[2]) { /* Management network addresses */
692 arr[1] = cmd[2]; /*sanity */
693 arr[3] = inquiry_evpd_85(&arr[4]);
694 } else if (0x86 == cmd[2]) { /* extended inquiry */
695 arr[1] = cmd[2]; /*sanity */
696 arr[3] = 0x3c; /* number of following entries */
697 arr[4] = 0x0; /* no protection stuff */
698 arr[5] = 0x7; /* head of q, ordered + simple q's */
699 } else if (0x87 == cmd[2]) { /* mode page policy */
700 arr[1] = cmd[2]; /*sanity */
701 arr[3] = 0x8; /* number of following entries */
702 arr[4] = 0x2; /* disconnect-reconnect mp */
703 arr[6] = 0x80; /* mlus, shared */
704 arr[8] = 0x18; /* protocol specific lu */
705 arr[10] = 0x82; /* mlus, per initiator port */
706 } else if (0x88 == cmd[2]) { /* SCSI Ports */
707 arr[1] = cmd[2]; /*sanity */
708 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
709 } else if (0x89 == cmd[2]) { /* ATA information */
710 arr[1] = cmd[2]; /*sanity */
711 n = inquiry_evpd_89(&arr[4]);
712 arr[2] = (n >> 8);
713 arr[3] = (n & 0xff);
714 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
715 arr[1] = cmd[2]; /*sanity */
716 arr[3] = inquiry_evpd_b0(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 } else {
718 /* Illegal request, invalid field in cdb */
719 mk_sense_buffer(devip, ILLEGAL_REQUEST,
720 INVALID_FIELD_IN_CDB, 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200721 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 return check_condition_result;
723 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400724 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200725 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400726 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200727 kfree(arr);
728 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 }
730 /* drops through here for a standard inquiry */
731 arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
732 arr[2] = scsi_debug_scsi_level;
733 arr[3] = 2; /* response_data_format==2 */
734 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200735 if (0 == scsi_debug_vpd_use_hostno)
736 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400737 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400739 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 memcpy(&arr[8], inq_vendor_id, 8);
741 memcpy(&arr[16], inq_product_id, 16);
742 memcpy(&arr[32], inq_product_rev, 4);
743 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400744 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
745 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
746 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400748 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400750 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400752 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200753 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200755 kfree(arr);
756 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757}
758
759static int resp_requests(struct scsi_cmnd * scp,
760 struct sdebug_dev_info * devip)
761{
762 unsigned char * sbuff;
763 unsigned char *cmd = (unsigned char *)scp->cmnd;
764 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400765 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 int len = 18;
767
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400768 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400770 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
771 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400773 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
774 if (want_dsense) {
775 arr[0] = 0x72;
776 arr[1] = 0x0; /* NO_SENSE in sense_key */
777 arr[2] = THRESHOLD_EXCEEDED;
778 arr[3] = 0xff; /* TEST set and MRIE==6 */
779 } else {
780 arr[0] = 0x70;
781 arr[2] = 0x0; /* NO_SENSE in sense_key */
782 arr[7] = 0xa; /* 18 byte sense buffer */
783 arr[12] = THRESHOLD_EXCEEDED;
784 arr[13] = 0xff; /* TEST set and MRIE==6 */
785 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400786 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400788 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
789 /* DESC bit set and sense_buff in fixed format */
790 memset(arr, 0, sizeof(arr));
791 arr[0] = 0x72;
792 arr[1] = sbuff[2]; /* sense key */
793 arr[2] = sbuff[12]; /* asc */
794 arr[3] = sbuff[13]; /* ascq */
795 len = 8;
796 }
797 }
798 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 return fill_from_dev_buffer(scp, arr, len);
800}
801
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400802static int resp_start_stop(struct scsi_cmnd * scp,
803 struct sdebug_dev_info * devip)
804{
805 unsigned char *cmd = (unsigned char *)scp->cmnd;
806 int power_cond, errsts, start;
807
808 if ((errsts = check_readiness(scp, 1, devip)))
809 return errsts;
810 power_cond = (cmd[4] & 0xf0) >> 4;
811 if (power_cond) {
812 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
813 0);
814 return check_condition_result;
815 }
816 start = cmd[4] & 1;
817 if (start == devip->stopped)
818 devip->stopped = !start;
819 return 0;
820}
821
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822#define SDEBUG_READCAP_ARR_SZ 8
823static int resp_readcap(struct scsi_cmnd * scp,
824 struct sdebug_dev_info * devip)
825{
826 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400827 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 int errsts;
829
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400830 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400832 /* following just in case virtual_gb changed */
833 if (scsi_debug_virtual_gb > 0) {
834 sdebug_capacity = 2048 * 1024;
835 sdebug_capacity *= scsi_debug_virtual_gb;
836 } else
837 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400839 if (sdebug_capacity < 0xffffffff) {
840 capac = (unsigned int)sdebug_capacity - 1;
841 arr[0] = (capac >> 24);
842 arr[1] = (capac >> 16) & 0xff;
843 arr[2] = (capac >> 8) & 0xff;
844 arr[3] = capac & 0xff;
845 } else {
846 arr[0] = 0xff;
847 arr[1] = 0xff;
848 arr[2] = 0xff;
849 arr[3] = 0xff;
850 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
852 arr[7] = SECT_SIZE_PER(target) & 0xff;
853 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
854}
855
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400856#define SDEBUG_READCAP16_ARR_SZ 32
857static int resp_readcap16(struct scsi_cmnd * scp,
858 struct sdebug_dev_info * devip)
859{
860 unsigned char *cmd = (unsigned char *)scp->cmnd;
861 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
862 unsigned long long capac;
863 int errsts, k, alloc_len;
864
865 if ((errsts = check_readiness(scp, 1, devip)))
866 return errsts;
867 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
868 + cmd[13]);
869 /* following just in case virtual_gb changed */
870 if (scsi_debug_virtual_gb > 0) {
871 sdebug_capacity = 2048 * 1024;
872 sdebug_capacity *= scsi_debug_virtual_gb;
873 } else
874 sdebug_capacity = sdebug_store_sectors;
875 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
876 capac = sdebug_capacity - 1;
877 for (k = 0; k < 8; ++k, capac >>= 8)
878 arr[7 - k] = capac & 0xff;
879 arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff;
880 arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff;
881 arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff;
882 arr[11] = SECT_SIZE_PER(target) & 0xff;
883 return fill_from_dev_buffer(scp, arr,
884 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
885}
886
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200887#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
888
889static int resp_report_tgtpgs(struct scsi_cmnd * scp,
890 struct sdebug_dev_info * devip)
891{
892 unsigned char *cmd = (unsigned char *)scp->cmnd;
893 unsigned char * arr;
894 int host_no = devip->sdbg_host->shost->host_no;
895 int n, ret, alen, rlen;
896 int port_group_a, port_group_b, port_a, port_b;
897
898 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
899 + cmd[9]);
900
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500901 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
902 if (! arr)
903 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200904 /*
905 * EVPD page 0x88 states we have two ports, one
906 * real and a fake port with no device connected.
907 * So we create two port groups with one port each
908 * and set the group with port B to unavailable.
909 */
910 port_a = 0x1; /* relative port A */
911 port_b = 0x2; /* relative port B */
912 port_group_a = (((host_no + 1) & 0x7f) << 8) +
913 (devip->channel & 0x7f);
914 port_group_b = (((host_no + 1) & 0x7f) << 8) +
915 (devip->channel & 0x7f) + 0x80;
916
917 /*
918 * The asymmetric access state is cycled according to the host_id.
919 */
920 n = 4;
921 if (0 == scsi_debug_vpd_use_hostno) {
922 arr[n++] = host_no % 3; /* Asymm access state */
923 arr[n++] = 0x0F; /* claim: all states are supported */
924 } else {
925 arr[n++] = 0x0; /* Active/Optimized path */
926 arr[n++] = 0x01; /* claim: only support active/optimized paths */
927 }
928 arr[n++] = (port_group_a >> 8) & 0xff;
929 arr[n++] = port_group_a & 0xff;
930 arr[n++] = 0; /* Reserved */
931 arr[n++] = 0; /* Status code */
932 arr[n++] = 0; /* Vendor unique */
933 arr[n++] = 0x1; /* One port per group */
934 arr[n++] = 0; /* Reserved */
935 arr[n++] = 0; /* Reserved */
936 arr[n++] = (port_a >> 8) & 0xff;
937 arr[n++] = port_a & 0xff;
938 arr[n++] = 3; /* Port unavailable */
939 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
940 arr[n++] = (port_group_b >> 8) & 0xff;
941 arr[n++] = port_group_b & 0xff;
942 arr[n++] = 0; /* Reserved */
943 arr[n++] = 0; /* Status code */
944 arr[n++] = 0; /* Vendor unique */
945 arr[n++] = 0x1; /* One port per group */
946 arr[n++] = 0; /* Reserved */
947 arr[n++] = 0; /* Reserved */
948 arr[n++] = (port_b >> 8) & 0xff;
949 arr[n++] = port_b & 0xff;
950
951 rlen = n - 4;
952 arr[0] = (rlen >> 24) & 0xff;
953 arr[1] = (rlen >> 16) & 0xff;
954 arr[2] = (rlen >> 8) & 0xff;
955 arr[3] = rlen & 0xff;
956
957 /*
958 * Return the smallest value of either
959 * - The allocated length
960 * - The constructed command length
961 * - The maximum array size
962 */
963 rlen = min(alen,n);
964 ret = fill_from_dev_buffer(scp, arr,
965 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
966 kfree(arr);
967 return ret;
968}
969
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970/* <<Following mode page info copied from ST318451LW>> */
971
972static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
973{ /* Read-Write Error Recovery page for mode_sense */
974 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
975 5, 0, 0xff, 0xff};
976
977 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
978 if (1 == pcontrol)
979 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
980 return sizeof(err_recov_pg);
981}
982
983static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
984{ /* Disconnect-Reconnect page for mode_sense */
985 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
986 0, 0, 0, 0, 0, 0, 0, 0};
987
988 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
989 if (1 == pcontrol)
990 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
991 return sizeof(disconnect_pg);
992}
993
994static int resp_format_pg(unsigned char * p, int pcontrol, int target)
995{ /* Format device page for mode_sense */
996 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
997 0, 0, 0, 0, 0, 0, 0, 0,
998 0, 0, 0, 0, 0x40, 0, 0, 0};
999
1000 memcpy(p, format_pg, sizeof(format_pg));
1001 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1002 p[11] = sdebug_sectors_per & 0xff;
1003 p[12] = (SECT_SIZE >> 8) & 0xff;
1004 p[13] = SECT_SIZE & 0xff;
1005 if (DEV_REMOVEABLE(target))
1006 p[20] |= 0x20; /* should agree with INQUIRY */
1007 if (1 == pcontrol)
1008 memset(p + 2, 0, sizeof(format_pg) - 2);
1009 return sizeof(format_pg);
1010}
1011
1012static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1013{ /* Caching page for mode_sense */
1014 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1015 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1016
1017 memcpy(p, caching_pg, sizeof(caching_pg));
1018 if (1 == pcontrol)
1019 memset(p + 2, 0, sizeof(caching_pg) - 2);
1020 return sizeof(caching_pg);
1021}
1022
1023static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1024{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001025 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1026 0, 0, 0, 0};
1027 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 0, 0, 0x2, 0x4b};
1029
1030 if (scsi_debug_dsense)
1031 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001032 else
1033 ctrl_m_pg[2] &= ~0x4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1035 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001036 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1037 else if (2 == pcontrol)
1038 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 return sizeof(ctrl_m_pg);
1040}
1041
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001042
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1044{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001045 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1046 0, 0, 0x0, 0x0};
1047 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1048 0, 0, 0x0, 0x0};
1049
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1051 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001052 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1053 else if (2 == pcontrol)
1054 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 return sizeof(iec_m_pg);
1056}
1057
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001058static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1059{ /* SAS SSP mode page - short format for mode_sense */
1060 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1061 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1062
1063 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1064 if (1 == pcontrol)
1065 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1066 return sizeof(sas_sf_m_pg);
1067}
1068
1069
1070static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1071 int target_dev_id)
1072{ /* SAS phy control and discover mode page for mode_sense */
1073 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1074 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1075 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1076 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1077 0x2, 0, 0, 0, 0, 0, 0, 0,
1078 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1079 0, 0, 0, 0, 0, 0, 0, 0,
1080 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1081 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1082 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1083 0x3, 0, 0, 0, 0, 0, 0, 0,
1084 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1085 0, 0, 0, 0, 0, 0, 0, 0,
1086 };
1087 int port_a, port_b;
1088
1089 port_a = target_dev_id + 1;
1090 port_b = port_a + 1;
1091 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1092 p[20] = (port_a >> 24);
1093 p[21] = (port_a >> 16) & 0xff;
1094 p[22] = (port_a >> 8) & 0xff;
1095 p[23] = port_a & 0xff;
1096 p[48 + 20] = (port_b >> 24);
1097 p[48 + 21] = (port_b >> 16) & 0xff;
1098 p[48 + 22] = (port_b >> 8) & 0xff;
1099 p[48 + 23] = port_b & 0xff;
1100 if (1 == pcontrol)
1101 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1102 return sizeof(sas_pcd_m_pg);
1103}
1104
1105static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1106{ /* SAS SSP shared protocol specific port mode subpage */
1107 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1108 0, 0, 0, 0, 0, 0, 0, 0,
1109 };
1110
1111 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1112 if (1 == pcontrol)
1113 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1114 return sizeof(sas_sha_m_pg);
1115}
1116
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117#define SDEBUG_MAX_MSENSE_SZ 256
1118
1119static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1120 struct sdebug_dev_info * devip)
1121{
Douglas Gilbert23183912006-09-16 20:30:47 -04001122 unsigned char dbd, llbaa;
1123 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001125 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 unsigned char * ap;
1127 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1128 unsigned char *cmd = (unsigned char *)scp->cmnd;
1129
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001130 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001132 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 pcontrol = (cmd[2] & 0xc0) >> 6;
1134 pcode = cmd[2] & 0x3f;
1135 subpcode = cmd[3];
1136 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001137 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1138 if ((0 == scsi_debug_ptype) && (0 == dbd))
1139 bd_len = llbaa ? 16 : 8;
1140 else
1141 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1143 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1144 if (0x3 == pcontrol) { /* Saving values not supported */
1145 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1146 0);
1147 return check_condition_result;
1148 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001149 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1150 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001151 /* set DPOFUA bit for disks */
1152 if (0 == scsi_debug_ptype)
1153 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1154 else
1155 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 if (msense_6) {
1157 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001158 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 offset = 4;
1160 } else {
1161 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001162 if (16 == bd_len)
1163 arr[4] = 0x1; /* set LONGLBA bit */
1164 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 offset = 8;
1166 }
1167 ap = arr + offset;
Douglas Gilbert23183912006-09-16 20:30:47 -04001168 if ((bd_len > 0) && (0 == sdebug_capacity)) {
1169 if (scsi_debug_virtual_gb > 0) {
1170 sdebug_capacity = 2048 * 1024;
1171 sdebug_capacity *= scsi_debug_virtual_gb;
1172 } else
1173 sdebug_capacity = sdebug_store_sectors;
1174 }
1175 if (8 == bd_len) {
1176 if (sdebug_capacity > 0xfffffffe) {
1177 ap[0] = 0xff;
1178 ap[1] = 0xff;
1179 ap[2] = 0xff;
1180 ap[3] = 0xff;
1181 } else {
1182 ap[0] = (sdebug_capacity >> 24) & 0xff;
1183 ap[1] = (sdebug_capacity >> 16) & 0xff;
1184 ap[2] = (sdebug_capacity >> 8) & 0xff;
1185 ap[3] = sdebug_capacity & 0xff;
1186 }
1187 ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1188 ap[7] = SECT_SIZE_PER(target) & 0xff;
1189 offset += bd_len;
1190 ap = arr + offset;
1191 } else if (16 == bd_len) {
1192 unsigned long long capac = sdebug_capacity;
1193
1194 for (k = 0; k < 8; ++k, capac >>= 8)
1195 ap[7 - k] = capac & 0xff;
1196 ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff;
1197 ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff;
1198 ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1199 ap[15] = SECT_SIZE_PER(target) & 0xff;
1200 offset += bd_len;
1201 ap = arr + offset;
1202 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001204 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1205 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1207 0);
1208 return check_condition_result;
1209 }
1210 switch (pcode) {
1211 case 0x1: /* Read-Write error recovery page, direct access */
1212 len = resp_err_recov_pg(ap, pcontrol, target);
1213 offset += len;
1214 break;
1215 case 0x2: /* Disconnect-Reconnect page, all devices */
1216 len = resp_disconnect_pg(ap, pcontrol, target);
1217 offset += len;
1218 break;
1219 case 0x3: /* Format device page, direct access */
1220 len = resp_format_pg(ap, pcontrol, target);
1221 offset += len;
1222 break;
1223 case 0x8: /* Caching page, direct access */
1224 len = resp_caching_pg(ap, pcontrol, target);
1225 offset += len;
1226 break;
1227 case 0xa: /* Control Mode page, all devices */
1228 len = resp_ctrl_m_pg(ap, pcontrol, target);
1229 offset += len;
1230 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001231 case 0x19: /* if spc==1 then sas phy, control+discover */
1232 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1233 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1234 INVALID_FIELD_IN_CDB, 0);
1235 return check_condition_result;
1236 }
1237 len = 0;
1238 if ((0x0 == subpcode) || (0xff == subpcode))
1239 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1240 if ((0x1 == subpcode) || (0xff == subpcode))
1241 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1242 target_dev_id);
1243 if ((0x2 == subpcode) || (0xff == subpcode))
1244 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1245 offset += len;
1246 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 case 0x1c: /* Informational Exceptions Mode page, all devices */
1248 len = resp_iec_m_pg(ap, pcontrol, target);
1249 offset += len;
1250 break;
1251 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001252 if ((0 == subpcode) || (0xff == subpcode)) {
1253 len = resp_err_recov_pg(ap, pcontrol, target);
1254 len += resp_disconnect_pg(ap + len, pcontrol, target);
1255 len += resp_format_pg(ap + len, pcontrol, target);
1256 len += resp_caching_pg(ap + len, pcontrol, target);
1257 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1258 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1259 if (0xff == subpcode) {
1260 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1261 target, target_dev_id);
1262 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1263 }
1264 len += resp_iec_m_pg(ap + len, pcontrol, target);
1265 } else {
1266 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1267 INVALID_FIELD_IN_CDB, 0);
1268 return check_condition_result;
1269 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 offset += len;
1271 break;
1272 default:
1273 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1274 0);
1275 return check_condition_result;
1276 }
1277 if (msense_6)
1278 arr[0] = offset - 1;
1279 else {
1280 arr[0] = ((offset - 2) >> 8) & 0xff;
1281 arr[1] = (offset - 2) & 0xff;
1282 }
1283 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1284}
1285
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001286#define SDEBUG_MAX_MSELECT_SZ 512
1287
1288static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1289 struct sdebug_dev_info * devip)
1290{
1291 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1292 int param_len, res, errsts, mpage;
1293 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1294 unsigned char *cmd = (unsigned char *)scp->cmnd;
1295
1296 if ((errsts = check_readiness(scp, 1, devip)))
1297 return errsts;
1298 memset(arr, 0, sizeof(arr));
1299 pf = cmd[1] & 0x10;
1300 sp = cmd[1] & 0x1;
1301 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1302 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1303 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1304 INVALID_FIELD_IN_CDB, 0);
1305 return check_condition_result;
1306 }
1307 res = fetch_to_dev_buffer(scp, arr, param_len);
1308 if (-1 == res)
1309 return (DID_ERROR << 16);
1310 else if ((res < param_len) &&
1311 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1312 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1313 " IO sent=%d bytes\n", param_len, res);
1314 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1315 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001316 if (md_len > 2) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001317 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1318 INVALID_FIELD_IN_PARAM_LIST, 0);
1319 return check_condition_result;
1320 }
1321 off = bd_len + (mselect6 ? 4 : 8);
1322 mpage = arr[off] & 0x3f;
1323 ps = !!(arr[off] & 0x80);
1324 if (ps) {
1325 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1326 INVALID_FIELD_IN_PARAM_LIST, 0);
1327 return check_condition_result;
1328 }
1329 spf = !!(arr[off] & 0x40);
1330 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1331 (arr[off + 1] + 2);
1332 if ((pg_len + off) > param_len) {
1333 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1334 PARAMETER_LIST_LENGTH_ERR, 0);
1335 return check_condition_result;
1336 }
1337 switch (mpage) {
1338 case 0xa: /* Control Mode page */
1339 if (ctrl_m_pg[1] == arr[off + 1]) {
1340 memcpy(ctrl_m_pg + 2, arr + off + 2,
1341 sizeof(ctrl_m_pg) - 2);
1342 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1343 return 0;
1344 }
1345 break;
1346 case 0x1c: /* Informational Exceptions Mode page */
1347 if (iec_m_pg[1] == arr[off + 1]) {
1348 memcpy(iec_m_pg + 2, arr + off + 2,
1349 sizeof(iec_m_pg) - 2);
1350 return 0;
1351 }
1352 break;
1353 default:
1354 break;
1355 }
1356 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1357 INVALID_FIELD_IN_PARAM_LIST, 0);
1358 return check_condition_result;
1359}
1360
1361static int resp_temp_l_pg(unsigned char * arr)
1362{
1363 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1364 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1365 };
1366
1367 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1368 return sizeof(temp_l_pg);
1369}
1370
1371static int resp_ie_l_pg(unsigned char * arr)
1372{
1373 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1374 };
1375
1376 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1377 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1378 arr[4] = THRESHOLD_EXCEEDED;
1379 arr[5] = 0xff;
1380 }
1381 return sizeof(ie_l_pg);
1382}
1383
1384#define SDEBUG_MAX_LSENSE_SZ 512
1385
1386static int resp_log_sense(struct scsi_cmnd * scp,
1387 struct sdebug_dev_info * devip)
1388{
Douglas Gilbert23183912006-09-16 20:30:47 -04001389 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001390 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1391 unsigned char *cmd = (unsigned char *)scp->cmnd;
1392
1393 if ((errsts = check_readiness(scp, 1, devip)))
1394 return errsts;
1395 memset(arr, 0, sizeof(arr));
1396 ppc = cmd[1] & 0x2;
1397 sp = cmd[1] & 0x1;
1398 if (ppc || sp) {
1399 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1400 INVALID_FIELD_IN_CDB, 0);
1401 return check_condition_result;
1402 }
1403 pcontrol = (cmd[2] & 0xc0) >> 6;
1404 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001405 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001406 alloc_len = (cmd[7] << 8) + cmd[8];
1407 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001408 if (0 == subpcode) {
1409 switch (pcode) {
1410 case 0x0: /* Supported log pages log page */
1411 n = 4;
1412 arr[n++] = 0x0; /* this page */
1413 arr[n++] = 0xd; /* Temperature */
1414 arr[n++] = 0x2f; /* Informational exceptions */
1415 arr[3] = n - 4;
1416 break;
1417 case 0xd: /* Temperature log page */
1418 arr[3] = resp_temp_l_pg(arr + 4);
1419 break;
1420 case 0x2f: /* Informational exceptions log page */
1421 arr[3] = resp_ie_l_pg(arr + 4);
1422 break;
1423 default:
1424 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1425 INVALID_FIELD_IN_CDB, 0);
1426 return check_condition_result;
1427 }
1428 } else if (0xff == subpcode) {
1429 arr[0] |= 0x40;
1430 arr[1] = subpcode;
1431 switch (pcode) {
1432 case 0x0: /* Supported log pages and subpages log page */
1433 n = 4;
1434 arr[n++] = 0x0;
1435 arr[n++] = 0x0; /* 0,0 page */
1436 arr[n++] = 0x0;
1437 arr[n++] = 0xff; /* this page */
1438 arr[n++] = 0xd;
1439 arr[n++] = 0x0; /* Temperature */
1440 arr[n++] = 0x2f;
1441 arr[n++] = 0x0; /* Informational exceptions */
1442 arr[3] = n - 4;
1443 break;
1444 case 0xd: /* Temperature subpages */
1445 n = 4;
1446 arr[n++] = 0xd;
1447 arr[n++] = 0x0; /* Temperature */
1448 arr[3] = n - 4;
1449 break;
1450 case 0x2f: /* Informational exceptions subpages */
1451 n = 4;
1452 arr[n++] = 0x2f;
1453 arr[n++] = 0x0; /* Informational exceptions */
1454 arr[3] = n - 4;
1455 break;
1456 default:
1457 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1458 INVALID_FIELD_IN_CDB, 0);
1459 return check_condition_result;
1460 }
1461 } else {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001462 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1463 INVALID_FIELD_IN_CDB, 0);
1464 return check_condition_result;
1465 }
1466 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1467 return fill_from_dev_buffer(scp, arr,
1468 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1469}
1470
1471static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
1472 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473{
1474 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001475 unsigned int block, from_bottom;
1476 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 int ret;
1478
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001479 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1481 0);
1482 return check_condition_result;
1483 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001484 /* transfer length excessive (tie in to block limits VPD page) */
1485 if (num > sdebug_store_sectors) {
1486 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1487 0);
1488 return check_condition_result;
1489 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001491 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1492 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1493 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1495 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001496 /* set info field and valid bit for fixed descriptor */
1497 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1498 devip->sense_buff[0] |= 0x80; /* Valid bit */
1499 ret = OPT_MEDIUM_ERR_ADDR;
1500 devip->sense_buff[3] = (ret >> 24) & 0xff;
1501 devip->sense_buff[4] = (ret >> 16) & 0xff;
1502 devip->sense_buff[5] = (ret >> 8) & 0xff;
1503 devip->sense_buff[6] = ret & 0xff;
1504 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 return check_condition_result;
1506 }
1507 read_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001508 if ((lba + num) <= sdebug_store_sectors)
1509 ret = fill_from_dev_buffer(SCpnt,
1510 fake_storep + (lba * SECT_SIZE),
1511 num * SECT_SIZE);
1512 else {
1513 /* modulo when one arg is 64 bits needs do_div() */
1514 u = lba;
1515 block = do_div(u, sdebug_store_sectors);
1516 from_bottom = 0;
1517 if ((block + num) > sdebug_store_sectors)
1518 from_bottom = (block + num) - sdebug_store_sectors;
1519 ret = fill_from_dev_buffer(SCpnt,
1520 fake_storep + (block * SECT_SIZE),
1521 (num - from_bottom) * SECT_SIZE);
1522 if ((0 == ret) && (from_bottom > 0))
1523 ret = fill_from_dev_buffer(SCpnt, fake_storep,
1524 from_bottom * SECT_SIZE);
1525 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 read_unlock_irqrestore(&atomic_rw, iflags);
1527 return ret;
1528}
1529
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001530static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
1531 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532{
1533 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001534 unsigned int block, to_bottom;
1535 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 int res;
1537
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001538 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1540 0);
1541 return check_condition_result;
1542 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001543 /* transfer length excessive (tie in to block limits VPD page) */
1544 if (num > sdebug_store_sectors) {
1545 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1546 0);
1547 return check_condition_result;
1548 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549
1550 write_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001551 if ((lba + num) <= sdebug_store_sectors)
1552 res = fetch_to_dev_buffer(SCpnt,
1553 fake_storep + (lba * SECT_SIZE),
1554 num * SECT_SIZE);
1555 else {
1556 /* modulo when one arg is 64 bits needs do_div() */
1557 u = lba;
1558 block = do_div(u, sdebug_store_sectors);
1559 to_bottom = 0;
1560 if ((block + num) > sdebug_store_sectors)
1561 to_bottom = (block + num) - sdebug_store_sectors;
1562 res = fetch_to_dev_buffer(SCpnt,
1563 fake_storep + (block * SECT_SIZE),
1564 (num - to_bottom) * SECT_SIZE);
1565 if ((0 == res) && (to_bottom > 0))
1566 res = fetch_to_dev_buffer(SCpnt, fake_storep,
1567 to_bottom * SECT_SIZE);
1568 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 write_unlock_irqrestore(&atomic_rw, iflags);
1570 if (-1 == res)
1571 return (DID_ERROR << 16);
1572 else if ((res < (num * SECT_SIZE)) &&
1573 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001574 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 " IO sent=%d bytes\n", num * SECT_SIZE, res);
1576 return 0;
1577}
1578
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001579#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580
1581static int resp_report_luns(struct scsi_cmnd * scp,
1582 struct sdebug_dev_info * devip)
1583{
1584 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001585 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 unsigned char *cmd = (unsigned char *)scp->cmnd;
1587 int select_report = (int)cmd[2];
1588 struct scsi_lun *one_lun;
1589 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001590 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591
1592 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001593 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1595 0);
1596 return check_condition_result;
1597 }
1598 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
1599 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
1600 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001601 if (1 == select_report)
1602 lun_cnt = 0;
1603 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
1604 --lun_cnt;
1605 wlun = (select_report > 0) ? 1 : 0;
1606 num = lun_cnt + wlun;
1607 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
1608 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
1609 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
1610 sizeof(struct scsi_lun)), num);
1611 if (n < num) {
1612 wlun = 0;
1613 lun_cnt = n;
1614 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001616 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
1617 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
1618 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
1619 i++, lun++) {
1620 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 if (upper)
1622 one_lun[i].scsi_lun[0] =
1623 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001624 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001626 if (wlun) {
1627 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
1628 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
1629 i++;
1630 }
1631 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 return fill_from_dev_buffer(scp, arr,
1633 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
1634}
1635
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001636static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
1637 unsigned int num, struct sdebug_dev_info *devip)
1638{
1639 int i, j, ret = -1;
1640 unsigned char *kaddr, *buf;
1641 unsigned int offset;
1642 struct scatterlist *sg;
1643 struct scsi_data_buffer *sdb = scsi_in(scp);
1644
1645 /* better not to use temporary buffer. */
1646 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
1647 if (!buf)
1648 return ret;
1649
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001650 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001651
1652 offset = 0;
1653 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
1654 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
1655 if (!kaddr)
1656 goto out;
1657
1658 for (j = 0; j < sg->length; j++)
1659 *(kaddr + sg->offset + j) ^= *(buf + offset + j);
1660
1661 offset += sg->length;
1662 kunmap_atomic(kaddr, KM_USER0);
1663 }
1664 ret = 0;
1665out:
1666 kfree(buf);
1667
1668 return ret;
1669}
1670
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671/* When timer goes off this function is called. */
1672static void timer_intr_handler(unsigned long indx)
1673{
1674 struct sdebug_queued_cmd * sqcp;
1675 unsigned long iflags;
1676
1677 if (indx >= SCSI_DEBUG_CANQUEUE) {
1678 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
1679 "large\n");
1680 return;
1681 }
1682 spin_lock_irqsave(&queued_arr_lock, iflags);
1683 sqcp = &queued_arr[(int)indx];
1684 if (! sqcp->in_use) {
1685 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
1686 "interrupt\n");
1687 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1688 return;
1689 }
1690 sqcp->in_use = 0;
1691 if (sqcp->done_funct) {
1692 sqcp->a_cmnd->result = sqcp->scsi_result;
1693 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
1694 }
1695 sqcp->done_funct = NULL;
1696 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1697}
1698
1699static int scsi_debug_slave_alloc(struct scsi_device * sdp)
1700{
1701 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001702 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
1703 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001704 set_bit(QUEUE_FLAG_BIDI, &sdp->request_queue->queue_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 return 0;
1706}
1707
1708static int scsi_debug_slave_configure(struct scsi_device * sdp)
1709{
1710 struct sdebug_dev_info * devip;
1711
1712 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001713 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
1714 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
1716 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
1717 devip = devInfoReg(sdp);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001718 if (NULL == devip)
1719 return 1; /* no resources, will be marked offline */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 sdp->hostdata = devip;
1721 if (sdp->host->cmd_per_lun)
1722 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
1723 sdp->host->cmd_per_lun);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001724 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 return 0;
1726}
1727
1728static void scsi_debug_slave_destroy(struct scsi_device * sdp)
1729{
1730 struct sdebug_dev_info * devip =
1731 (struct sdebug_dev_info *)sdp->hostdata;
1732
1733 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001734 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
1735 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 if (devip) {
1737 /* make this slot avaliable for re-use */
1738 devip->used = 0;
1739 sdp->hostdata = NULL;
1740 }
1741}
1742
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09001743struct sdebug_dev_info *sdebug_device_create(struct sdebug_host_info *sdbg_host,
1744 gfp_t flags)
1745{
1746 struct sdebug_dev_info *devip;
1747
1748 devip = kzalloc(sizeof(*devip), flags);
1749 if (devip) {
1750 devip->sdbg_host = sdbg_host;
1751 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
1752 }
1753 return devip;
1754}
1755
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
1757{
1758 struct sdebug_host_info * sdbg_host;
1759 struct sdebug_dev_info * open_devip = NULL;
1760 struct sdebug_dev_info * devip =
1761 (struct sdebug_dev_info *)sdev->hostdata;
1762
1763 if (devip)
1764 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09001765 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
1766 if (!sdbg_host) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 printk(KERN_ERR "Host info NULL\n");
1768 return NULL;
1769 }
1770 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
1771 if ((devip->used) && (devip->channel == sdev->channel) &&
1772 (devip->target == sdev->id) &&
1773 (devip->lun == sdev->lun))
1774 return devip;
1775 else {
1776 if ((!devip->used) && (!open_devip))
1777 open_devip = devip;
1778 }
1779 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09001780 if (!open_devip) { /* try and make a new one */
1781 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
1782 if (!open_devip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 printk(KERN_ERR "%s: out of memory at line %d\n",
1784 __FUNCTION__, __LINE__);
1785 return NULL;
1786 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09001788
1789 open_devip->channel = sdev->channel;
1790 open_devip->target = sdev->id;
1791 open_devip->lun = sdev->lun;
1792 open_devip->sdbg_host = sdbg_host;
1793 open_devip->reset = 1;
1794 open_devip->used = 1;
1795 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
1796 if (scsi_debug_dsense)
1797 open_devip->sense_buff[0] = 0x72;
1798 else {
1799 open_devip->sense_buff[0] = 0x70;
1800 open_devip->sense_buff[7] = 0xa;
1801 }
1802 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
1803 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
1804
1805 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806}
1807
1808static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
1809 int asc, int asq)
1810{
1811 unsigned char * sbuff;
1812
1813 sbuff = devip->sense_buff;
1814 memset(sbuff, 0, SDEBUG_SENSE_LEN);
1815 if (scsi_debug_dsense) {
1816 sbuff[0] = 0x72; /* descriptor, current */
1817 sbuff[1] = key;
1818 sbuff[2] = asc;
1819 sbuff[3] = asq;
1820 } else {
1821 sbuff[0] = 0x70; /* fixed, current */
1822 sbuff[2] = key;
1823 sbuff[7] = 0xa; /* implies 18 byte sense buffer */
1824 sbuff[12] = asc;
1825 sbuff[13] = asq;
1826 }
1827 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1828 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
1829 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
1830}
1831
1832static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
1833{
1834 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1835 printk(KERN_INFO "scsi_debug: abort\n");
1836 ++num_aborts;
1837 stop_queued_cmnd(SCpnt);
1838 return SUCCESS;
1839}
1840
1841static int scsi_debug_biosparam(struct scsi_device *sdev,
1842 struct block_device * bdev, sector_t capacity, int *info)
1843{
1844 int res;
1845 unsigned char *buf;
1846
1847 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1848 printk(KERN_INFO "scsi_debug: biosparam\n");
1849 buf = scsi_bios_ptable(bdev);
1850 if (buf) {
1851 res = scsi_partsize(buf, capacity,
1852 &info[2], &info[0], &info[1]);
1853 kfree(buf);
1854 if (! res)
1855 return res;
1856 }
1857 info[0] = sdebug_heads;
1858 info[1] = sdebug_sectors_per;
1859 info[2] = sdebug_cylinders_per;
1860 return 0;
1861}
1862
1863static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
1864{
1865 struct sdebug_dev_info * devip;
1866
1867 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1868 printk(KERN_INFO "scsi_debug: device_reset\n");
1869 ++num_dev_resets;
1870 if (SCpnt) {
1871 devip = devInfoReg(SCpnt->device);
1872 if (devip)
1873 devip->reset = 1;
1874 }
1875 return SUCCESS;
1876}
1877
1878static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
1879{
1880 struct sdebug_host_info *sdbg_host;
1881 struct sdebug_dev_info * dev_info;
1882 struct scsi_device * sdp;
1883 struct Scsi_Host * hp;
1884
1885 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1886 printk(KERN_INFO "scsi_debug: bus_reset\n");
1887 ++num_bus_resets;
1888 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09001889 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 if (sdbg_host) {
1891 list_for_each_entry(dev_info,
1892 &sdbg_host->dev_info_list,
1893 dev_list)
1894 dev_info->reset = 1;
1895 }
1896 }
1897 return SUCCESS;
1898}
1899
1900static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
1901{
1902 struct sdebug_host_info * sdbg_host;
1903 struct sdebug_dev_info * dev_info;
1904
1905 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1906 printk(KERN_INFO "scsi_debug: host_reset\n");
1907 ++num_host_resets;
1908 spin_lock(&sdebug_host_list_lock);
1909 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
1910 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
1911 dev_list)
1912 dev_info->reset = 1;
1913 }
1914 spin_unlock(&sdebug_host_list_lock);
1915 stop_all_queued();
1916 return SUCCESS;
1917}
1918
1919/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
1920static int stop_queued_cmnd(struct scsi_cmnd * cmnd)
1921{
1922 unsigned long iflags;
1923 int k;
1924 struct sdebug_queued_cmd * sqcp;
1925
1926 spin_lock_irqsave(&queued_arr_lock, iflags);
1927 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1928 sqcp = &queued_arr[k];
1929 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
1930 del_timer_sync(&sqcp->cmnd_timer);
1931 sqcp->in_use = 0;
1932 sqcp->a_cmnd = NULL;
1933 break;
1934 }
1935 }
1936 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1937 return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
1938}
1939
1940/* Deletes (stops) timers of all queued commands */
1941static void stop_all_queued(void)
1942{
1943 unsigned long iflags;
1944 int k;
1945 struct sdebug_queued_cmd * sqcp;
1946
1947 spin_lock_irqsave(&queued_arr_lock, iflags);
1948 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1949 sqcp = &queued_arr[k];
1950 if (sqcp->in_use && sqcp->a_cmnd) {
1951 del_timer_sync(&sqcp->cmnd_timer);
1952 sqcp->in_use = 0;
1953 sqcp->a_cmnd = NULL;
1954 }
1955 }
1956 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1957}
1958
1959/* Initializes timers in queued array */
1960static void __init init_all_queued(void)
1961{
1962 unsigned long iflags;
1963 int k;
1964 struct sdebug_queued_cmd * sqcp;
1965
1966 spin_lock_irqsave(&queued_arr_lock, iflags);
1967 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1968 sqcp = &queued_arr[k];
1969 init_timer(&sqcp->cmnd_timer);
1970 sqcp->in_use = 0;
1971 sqcp->a_cmnd = NULL;
1972 }
1973 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1974}
1975
1976static void __init sdebug_build_parts(unsigned char * ramp)
1977{
1978 struct partition * pp;
1979 int starts[SDEBUG_MAX_PARTS + 2];
1980 int sectors_per_part, num_sectors, k;
1981 int heads_by_sects, start_sec, end_sec;
1982
1983 /* assume partition table already zeroed */
1984 if ((scsi_debug_num_parts < 1) || (sdebug_store_size < 1048576))
1985 return;
1986 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
1987 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
1988 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
1989 "partitions to %d\n", SDEBUG_MAX_PARTS);
1990 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001991 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 sectors_per_part = (num_sectors - sdebug_sectors_per)
1993 / scsi_debug_num_parts;
1994 heads_by_sects = sdebug_heads * sdebug_sectors_per;
1995 starts[0] = sdebug_sectors_per;
1996 for (k = 1; k < scsi_debug_num_parts; ++k)
1997 starts[k] = ((k * sectors_per_part) / heads_by_sects)
1998 * heads_by_sects;
1999 starts[scsi_debug_num_parts] = num_sectors;
2000 starts[scsi_debug_num_parts + 1] = 0;
2001
2002 ramp[510] = 0x55; /* magic partition markings */
2003 ramp[511] = 0xAA;
2004 pp = (struct partition *)(ramp + 0x1be);
2005 for (k = 0; starts[k + 1]; ++k, ++pp) {
2006 start_sec = starts[k];
2007 end_sec = starts[k + 1] - 1;
2008 pp->boot_ind = 0;
2009
2010 pp->cyl = start_sec / heads_by_sects;
2011 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2012 / sdebug_sectors_per;
2013 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2014
2015 pp->end_cyl = end_sec / heads_by_sects;
2016 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2017 / sdebug_sectors_per;
2018 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2019
2020 pp->start_sect = start_sec;
2021 pp->nr_sects = end_sec - start_sec + 1;
2022 pp->sys_ind = 0x83; /* plain Linux partition */
2023 }
2024}
2025
2026static int schedule_resp(struct scsi_cmnd * cmnd,
2027 struct sdebug_dev_info * devip,
2028 done_funct_t done, int scsi_result, int delta_jiff)
2029{
2030 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2031 if (scsi_result) {
2032 struct scsi_device * sdp = cmnd->device;
2033
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002034 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2035 "non-zero result=0x%x\n", sdp->host->host_no,
2036 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 }
2038 }
2039 if (cmnd && devip) {
2040 /* simulate autosense by this driver */
2041 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2042 memcpy(cmnd->sense_buffer, devip->sense_buff,
2043 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2044 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2045 }
2046 if (delta_jiff <= 0) {
2047 if (cmnd)
2048 cmnd->result = scsi_result;
2049 if (done)
2050 done(cmnd);
2051 return 0;
2052 } else {
2053 unsigned long iflags;
2054 int k;
2055 struct sdebug_queued_cmd * sqcp = NULL;
2056
2057 spin_lock_irqsave(&queued_arr_lock, iflags);
2058 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2059 sqcp = &queued_arr[k];
2060 if (! sqcp->in_use)
2061 break;
2062 }
2063 if (k >= SCSI_DEBUG_CANQUEUE) {
2064 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2065 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2066 return 1; /* report busy to mid level */
2067 }
2068 sqcp->in_use = 1;
2069 sqcp->a_cmnd = cmnd;
2070 sqcp->scsi_result = scsi_result;
2071 sqcp->done_funct = done;
2072 sqcp->cmnd_timer.function = timer_intr_handler;
2073 sqcp->cmnd_timer.data = k;
2074 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2075 add_timer(&sqcp->cmnd_timer);
2076 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2077 if (cmnd)
2078 cmnd->result = 0;
2079 return 0;
2080 }
2081}
2082
Douglas Gilbert23183912006-09-16 20:30:47 -04002083/* Note: The following macros create attribute files in the
2084 /sys/module/scsi_debug/parameters directory. Unfortunately this
2085 driver is unaware of a change and cannot trigger auxiliary actions
2086 as it can when the corresponding attribute in the
2087 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2088 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002089module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2090module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2091module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2092module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2093module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002094module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002095module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2096module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2097module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2098module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2099module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2100module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2101module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2102module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002103module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2104 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105
2106MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2107MODULE_DESCRIPTION("SCSI debug adapter driver");
2108MODULE_LICENSE("GPL");
2109MODULE_VERSION(SCSI_DEBUG_VERSION);
2110
2111MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2112MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002113MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2114MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07002115MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002116MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002117MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2118MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002120MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002121MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2123MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002124MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002125MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126
2127
2128static char sdebug_info[256];
2129
2130static const char * scsi_debug_info(struct Scsi_Host * shp)
2131{
2132 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2133 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2134 scsi_debug_version_date, scsi_debug_dev_size_mb,
2135 scsi_debug_opts);
2136 return sdebug_info;
2137}
2138
2139/* scsi_debug_proc_info
2140 * Used if the driver currently has no own support for /proc/scsi
2141 */
2142static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2143 int length, int inout)
2144{
2145 int len, pos, begin;
2146 int orig_length;
2147
2148 orig_length = length;
2149
2150 if (inout == 1) {
2151 char arr[16];
2152 int minLen = length > 15 ? 15 : length;
2153
2154 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2155 return -EACCES;
2156 memcpy(arr, buffer, minLen);
2157 arr[minLen] = '\0';
2158 if (1 != sscanf(arr, "%d", &pos))
2159 return -EINVAL;
2160 scsi_debug_opts = pos;
2161 if (scsi_debug_every_nth != 0)
2162 scsi_debug_cmnd_count = 0;
2163 return length;
2164 }
2165 begin = 0;
2166 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2167 "%s [%s]\n"
2168 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2169 "every_nth=%d(curr:%d)\n"
2170 "delay=%d, max_luns=%d, scsi_level=%d\n"
2171 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2172 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
2173 "host_resets=%d\n",
2174 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2175 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2176 scsi_debug_cmnd_count, scsi_debug_delay,
2177 scsi_debug_max_luns, scsi_debug_scsi_level,
2178 SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
2179 num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
2180 if (pos < offset) {
2181 len = 0;
2182 begin = pos;
2183 }
2184 *start = buffer + (offset - begin); /* Start of wanted data */
2185 len -= (offset - begin);
2186 if (len > length)
2187 len = length;
2188 return len;
2189}
2190
2191static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2192{
2193 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2194}
2195
2196static ssize_t sdebug_delay_store(struct device_driver * ddp,
2197 const char * buf, size_t count)
2198{
2199 int delay;
2200 char work[20];
2201
2202 if (1 == sscanf(buf, "%10s", work)) {
2203 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2204 scsi_debug_delay = delay;
2205 return count;
2206 }
2207 }
2208 return -EINVAL;
2209}
2210DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2211 sdebug_delay_store);
2212
2213static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2214{
2215 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2216}
2217
2218static ssize_t sdebug_opts_store(struct device_driver * ddp,
2219 const char * buf, size_t count)
2220{
2221 int opts;
2222 char work[20];
2223
2224 if (1 == sscanf(buf, "%10s", work)) {
2225 if (0 == strnicmp(work,"0x", 2)) {
2226 if (1 == sscanf(&work[2], "%x", &opts))
2227 goto opts_done;
2228 } else {
2229 if (1 == sscanf(work, "%d", &opts))
2230 goto opts_done;
2231 }
2232 }
2233 return -EINVAL;
2234opts_done:
2235 scsi_debug_opts = opts;
2236 scsi_debug_cmnd_count = 0;
2237 return count;
2238}
2239DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2240 sdebug_opts_store);
2241
2242static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2243{
2244 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2245}
2246static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2247 const char * buf, size_t count)
2248{
2249 int n;
2250
2251 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2252 scsi_debug_ptype = n;
2253 return count;
2254 }
2255 return -EINVAL;
2256}
2257DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2258
2259static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2260{
2261 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2262}
2263static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2264 const char * buf, size_t count)
2265{
2266 int n;
2267
2268 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2269 scsi_debug_dsense = n;
2270 return count;
2271 }
2272 return -EINVAL;
2273}
2274DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2275 sdebug_dsense_store);
2276
Douglas Gilbert23183912006-09-16 20:30:47 -04002277static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2278{
2279 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2280}
2281static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2282 const char * buf, size_t count)
2283{
2284 int n;
2285
2286 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2287 scsi_debug_fake_rw = n;
2288 return count;
2289 }
2290 return -EINVAL;
2291}
2292DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2293 sdebug_fake_rw_store);
2294
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002295static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2296{
2297 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2298}
2299static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2300 const char * buf, size_t count)
2301{
2302 int n;
2303
2304 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2305 scsi_debug_no_lun_0 = n;
2306 return count;
2307 }
2308 return -EINVAL;
2309}
2310DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2311 sdebug_no_lun_0_store);
2312
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2314{
2315 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2316}
2317static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2318 const char * buf, size_t count)
2319{
2320 int n;
2321
2322 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2323 scsi_debug_num_tgts = n;
2324 sdebug_max_tgts_luns();
2325 return count;
2326 }
2327 return -EINVAL;
2328}
2329DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2330 sdebug_num_tgts_store);
2331
2332static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2333{
2334 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2335}
2336DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2337
2338static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2339{
2340 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2341}
2342DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2343
2344static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2345{
2346 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2347}
2348static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2349 const char * buf, size_t count)
2350{
2351 int nth;
2352
2353 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2354 scsi_debug_every_nth = nth;
2355 scsi_debug_cmnd_count = 0;
2356 return count;
2357 }
2358 return -EINVAL;
2359}
2360DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2361 sdebug_every_nth_store);
2362
2363static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2364{
2365 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2366}
2367static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2368 const char * buf, size_t count)
2369{
2370 int n;
2371
2372 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2373 scsi_debug_max_luns = n;
2374 sdebug_max_tgts_luns();
2375 return count;
2376 }
2377 return -EINVAL;
2378}
2379DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2380 sdebug_max_luns_store);
2381
2382static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
2383{
2384 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
2385}
2386DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
2387
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002388static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2389{
2390 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2391}
2392static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2393 const char * buf, size_t count)
2394{
2395 int n;
2396
2397 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2398 scsi_debug_virtual_gb = n;
2399 if (scsi_debug_virtual_gb > 0) {
2400 sdebug_capacity = 2048 * 1024;
2401 sdebug_capacity *= scsi_debug_virtual_gb;
2402 } else
2403 sdebug_capacity = sdebug_store_sectors;
2404 return count;
2405 }
2406 return -EINVAL;
2407}
2408DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2409 sdebug_virtual_gb_store);
2410
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
2412{
2413 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
2414}
2415
2416static ssize_t sdebug_add_host_store(struct device_driver * ddp,
2417 const char * buf, size_t count)
2418{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002419 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002421 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 if (delta_hosts > 0) {
2424 do {
2425 sdebug_add_adapter();
2426 } while (--delta_hosts);
2427 } else if (delta_hosts < 0) {
2428 do {
2429 sdebug_remove_adapter();
2430 } while (++delta_hosts);
2431 }
2432 return count;
2433}
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002434DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 sdebug_add_host_store);
2436
Douglas Gilbert23183912006-09-16 20:30:47 -04002437static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
2438 char * buf)
2439{
2440 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
2441}
2442static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
2443 const char * buf, size_t count)
2444{
2445 int n;
2446
2447 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2448 scsi_debug_vpd_use_hostno = n;
2449 return count;
2450 }
2451 return -EINVAL;
2452}
2453DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
2454 sdebug_vpd_use_hostno_store);
2455
2456/* Note: The following function creates attribute files in the
2457 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
2458 files (over those found in the /sys/module/scsi_debug/parameters
2459 directory) is that auxiliary actions can be triggered when an attribute
2460 is changed. For example see: sdebug_add_host_store() above.
2461 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002462static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002464 int ret;
2465
2466 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2467 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
2468 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2469 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2470 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04002471 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002472 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002473 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002474 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002475 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002476 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
2477 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
2478 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04002479 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
2480 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002481 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482}
2483
2484static void do_remove_driverfs_files(void)
2485{
Douglas Gilbert23183912006-09-16 20:30:47 -04002486 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
2487 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
2489 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
2490 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002492 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
2493 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002495 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
2497 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2498 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2499 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
2500 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2501}
2502
2503static int __init scsi_debug_init(void)
2504{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002505 unsigned int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 int host_to_add;
2507 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002508 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509
2510 if (scsi_debug_dev_size_mb < 1)
2511 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002512 sdebug_store_size = (unsigned int)scsi_debug_dev_size_mb * 1048576;
2513 sdebug_store_sectors = sdebug_store_size / SECT_SIZE;
2514 if (scsi_debug_virtual_gb > 0) {
2515 sdebug_capacity = 2048 * 1024;
2516 sdebug_capacity *= scsi_debug_virtual_gb;
2517 } else
2518 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519
2520 /* play around with geometry, don't waste too much on track 0 */
2521 sdebug_heads = 8;
2522 sdebug_sectors_per = 32;
2523 if (scsi_debug_dev_size_mb >= 16)
2524 sdebug_heads = 32;
2525 else if (scsi_debug_dev_size_mb >= 256)
2526 sdebug_heads = 64;
2527 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2528 (sdebug_sectors_per * sdebug_heads);
2529 if (sdebug_cylinders_per >= 1024) {
2530 /* other LLDs do this; implies >= 1GB ram disk ... */
2531 sdebug_heads = 255;
2532 sdebug_sectors_per = 63;
2533 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2534 (sdebug_sectors_per * sdebug_heads);
2535 }
2536
2537 sz = sdebug_store_size;
2538 fake_storep = vmalloc(sz);
2539 if (NULL == fake_storep) {
2540 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
2541 return -ENOMEM;
2542 }
2543 memset(fake_storep, 0, sz);
2544 if (scsi_debug_num_parts > 0)
2545 sdebug_build_parts(fake_storep);
2546
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002547 ret = device_register(&pseudo_primary);
2548 if (ret < 0) {
2549 printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
2550 ret);
2551 goto free_vm;
2552 }
2553 ret = bus_register(&pseudo_lld_bus);
2554 if (ret < 0) {
2555 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
2556 ret);
2557 goto dev_unreg;
2558 }
2559 ret = driver_register(&sdebug_driverfs_driver);
2560 if (ret < 0) {
2561 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
2562 ret);
2563 goto bus_unreg;
2564 }
2565 ret = do_create_driverfs_files();
2566 if (ret < 0) {
2567 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
2568 ret);
2569 goto del_files;
2570 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002572 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 host_to_add = scsi_debug_add_host;
2575 scsi_debug_add_host = 0;
2576
2577 for (k = 0; k < host_to_add; k++) {
2578 if (sdebug_add_adapter()) {
2579 printk(KERN_ERR "scsi_debug_init: "
2580 "sdebug_add_adapter failed k=%d\n", k);
2581 break;
2582 }
2583 }
2584
2585 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
2586 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
2587 scsi_debug_add_host);
2588 }
2589 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002590
2591del_files:
2592 do_remove_driverfs_files();
2593 driver_unregister(&sdebug_driverfs_driver);
2594bus_unreg:
2595 bus_unregister(&pseudo_lld_bus);
2596dev_unreg:
2597 device_unregister(&pseudo_primary);
2598free_vm:
2599 vfree(fake_storep);
2600
2601 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602}
2603
2604static void __exit scsi_debug_exit(void)
2605{
2606 int k = scsi_debug_add_host;
2607
2608 stop_all_queued();
2609 for (; k; k--)
2610 sdebug_remove_adapter();
2611 do_remove_driverfs_files();
2612 driver_unregister(&sdebug_driverfs_driver);
2613 bus_unregister(&pseudo_lld_bus);
2614 device_unregister(&pseudo_primary);
2615
2616 vfree(fake_storep);
2617}
2618
2619device_initcall(scsi_debug_init);
2620module_exit(scsi_debug_exit);
2621
Adrian Bunk52c1da32005-06-23 22:05:33 -07002622static void pseudo_0_release(struct device * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623{
2624 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2625 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
2626}
2627
2628static struct device pseudo_primary = {
2629 .bus_id = "pseudo_0",
2630 .release = pseudo_0_release,
2631};
2632
2633static int pseudo_lld_bus_match(struct device *dev,
2634 struct device_driver *dev_driver)
2635{
2636 return 1;
2637}
2638
2639static struct bus_type pseudo_lld_bus = {
2640 .name = "pseudo",
2641 .match = pseudo_lld_bus_match,
Russell Kingbbbe3a42006-01-05 14:44:46 +00002642 .probe = sdebug_driver_probe,
2643 .remove = sdebug_driver_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644};
2645
2646static void sdebug_release_adapter(struct device * dev)
2647{
2648 struct sdebug_host_info *sdbg_host;
2649
2650 sdbg_host = to_sdebug_host(dev);
2651 kfree(sdbg_host);
2652}
2653
2654static int sdebug_add_adapter(void)
2655{
2656 int k, devs_per_host;
2657 int error = 0;
2658 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09002659 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002661 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 if (NULL == sdbg_host) {
2663 printk(KERN_ERR "%s: out of memory at line %d\n",
2664 __FUNCTION__, __LINE__);
2665 return -ENOMEM;
2666 }
2667
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
2669
2670 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
2671 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002672 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
2673 if (!sdbg_devinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 printk(KERN_ERR "%s: out of memory at line %d\n",
2675 __FUNCTION__, __LINE__);
2676 error = -ENOMEM;
2677 goto clean;
2678 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 }
2680
2681 spin_lock(&sdebug_host_list_lock);
2682 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
2683 spin_unlock(&sdebug_host_list_lock);
2684
2685 sdbg_host->dev.bus = &pseudo_lld_bus;
2686 sdbg_host->dev.parent = &pseudo_primary;
2687 sdbg_host->dev.release = &sdebug_release_adapter;
2688 sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host);
2689
2690 error = device_register(&sdbg_host->dev);
2691
2692 if (error)
2693 goto clean;
2694
2695 ++scsi_debug_add_host;
2696 return error;
2697
2698clean:
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09002699 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
2700 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 list_del(&sdbg_devinfo->dev_list);
2702 kfree(sdbg_devinfo);
2703 }
2704
2705 kfree(sdbg_host);
2706 return error;
2707}
2708
2709static void sdebug_remove_adapter(void)
2710{
2711 struct sdebug_host_info * sdbg_host = NULL;
2712
2713 spin_lock(&sdebug_host_list_lock);
2714 if (!list_empty(&sdebug_host_list)) {
2715 sdbg_host = list_entry(sdebug_host_list.prev,
2716 struct sdebug_host_info, host_list);
2717 list_del(&sdbg_host->host_list);
2718 }
2719 spin_unlock(&sdebug_host_list_lock);
2720
2721 if (!sdbg_host)
2722 return;
2723
2724 device_unregister(&sdbg_host->dev);
2725 --scsi_debug_add_host;
2726}
2727
FUJITA Tomonori639db472008-03-20 11:09:19 +09002728static
2729int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
2730{
2731 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
2732 int len, k;
2733 unsigned int num;
2734 unsigned long long lba;
2735 int errsts = 0;
2736 int target = SCpnt->device->id;
2737 struct sdebug_dev_info *devip = NULL;
2738 int inj_recovered = 0;
2739 int inj_transport = 0;
2740 int delay_override = 0;
2741
2742 scsi_set_resid(SCpnt, 0);
2743 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
2744 printk(KERN_INFO "scsi_debug: cmd ");
2745 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
2746 printk("%02x ", (int)cmd[k]);
2747 printk("\n");
2748 }
2749
2750 if (target == SCpnt->device->host->hostt->this_id) {
2751 printk(KERN_INFO "scsi_debug: initiator's id used as "
2752 "target!\n");
2753 return schedule_resp(SCpnt, NULL, done,
2754 DID_NO_CONNECT << 16, 0);
2755 }
2756
2757 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
2758 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
2759 return schedule_resp(SCpnt, NULL, done,
2760 DID_NO_CONNECT << 16, 0);
2761 devip = devInfoReg(SCpnt->device);
2762 if (NULL == devip)
2763 return schedule_resp(SCpnt, NULL, done,
2764 DID_NO_CONNECT << 16, 0);
2765
2766 if ((scsi_debug_every_nth != 0) &&
2767 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
2768 scsi_debug_cmnd_count = 0;
2769 if (scsi_debug_every_nth < -1)
2770 scsi_debug_every_nth = -1;
2771 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
2772 return 0; /* ignore command causing timeout */
2773 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
2774 inj_recovered = 1; /* to reads and writes below */
2775 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
2776 inj_transport = 1; /* to reads and writes below */
2777 }
2778
2779 if (devip->wlun) {
2780 switch (*cmd) {
2781 case INQUIRY:
2782 case REQUEST_SENSE:
2783 case TEST_UNIT_READY:
2784 case REPORT_LUNS:
2785 break; /* only allowable wlun commands */
2786 default:
2787 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2788 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
2789 "not supported for wlun\n", *cmd);
2790 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2791 INVALID_OPCODE, 0);
2792 errsts = check_condition_result;
2793 return schedule_resp(SCpnt, devip, done, errsts,
2794 0);
2795 }
2796 }
2797
2798 switch (*cmd) {
2799 case INQUIRY: /* mandatory, ignore unit attention */
2800 delay_override = 1;
2801 errsts = resp_inquiry(SCpnt, target, devip);
2802 break;
2803 case REQUEST_SENSE: /* mandatory, ignore unit attention */
2804 delay_override = 1;
2805 errsts = resp_requests(SCpnt, devip);
2806 break;
2807 case REZERO_UNIT: /* actually this is REWIND for SSC */
2808 case START_STOP:
2809 errsts = resp_start_stop(SCpnt, devip);
2810 break;
2811 case ALLOW_MEDIUM_REMOVAL:
2812 errsts = check_readiness(SCpnt, 1, devip);
2813 if (errsts)
2814 break;
2815 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2816 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
2817 cmd[4] ? "inhibited" : "enabled");
2818 break;
2819 case SEND_DIAGNOSTIC: /* mandatory */
2820 errsts = check_readiness(SCpnt, 1, devip);
2821 break;
2822 case TEST_UNIT_READY: /* mandatory */
2823 delay_override = 1;
2824 errsts = check_readiness(SCpnt, 0, devip);
2825 break;
2826 case RESERVE:
2827 errsts = check_readiness(SCpnt, 1, devip);
2828 break;
2829 case RESERVE_10:
2830 errsts = check_readiness(SCpnt, 1, devip);
2831 break;
2832 case RELEASE:
2833 errsts = check_readiness(SCpnt, 1, devip);
2834 break;
2835 case RELEASE_10:
2836 errsts = check_readiness(SCpnt, 1, devip);
2837 break;
2838 case READ_CAPACITY:
2839 errsts = resp_readcap(SCpnt, devip);
2840 break;
2841 case SERVICE_ACTION_IN:
2842 if (SAI_READ_CAPACITY_16 != cmd[1]) {
2843 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2844 INVALID_OPCODE, 0);
2845 errsts = check_condition_result;
2846 break;
2847 }
2848 errsts = resp_readcap16(SCpnt, devip);
2849 break;
2850 case MAINTENANCE_IN:
2851 if (MI_REPORT_TARGET_PGS != cmd[1]) {
2852 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2853 INVALID_OPCODE, 0);
2854 errsts = check_condition_result;
2855 break;
2856 }
2857 errsts = resp_report_tgtpgs(SCpnt, devip);
2858 break;
2859 case READ_16:
2860 case READ_12:
2861 case READ_10:
2862 case READ_6:
2863 errsts = check_readiness(SCpnt, 0, devip);
2864 if (errsts)
2865 break;
2866 if (scsi_debug_fake_rw)
2867 break;
2868 get_data_transfer_info(cmd, &lba, &num);
2869 errsts = resp_read(SCpnt, lba, num, devip);
2870 if (inj_recovered && (0 == errsts)) {
2871 mk_sense_buffer(devip, RECOVERED_ERROR,
2872 THRESHOLD_EXCEEDED, 0);
2873 errsts = check_condition_result;
2874 } else if (inj_transport && (0 == errsts)) {
2875 mk_sense_buffer(devip, ABORTED_COMMAND,
2876 TRANSPORT_PROBLEM, ACK_NAK_TO);
2877 errsts = check_condition_result;
2878 }
2879 break;
2880 case REPORT_LUNS: /* mandatory, ignore unit attention */
2881 delay_override = 1;
2882 errsts = resp_report_luns(SCpnt, devip);
2883 break;
2884 case VERIFY: /* 10 byte SBC-2 command */
2885 errsts = check_readiness(SCpnt, 0, devip);
2886 break;
2887 case WRITE_16:
2888 case WRITE_12:
2889 case WRITE_10:
2890 case WRITE_6:
2891 errsts = check_readiness(SCpnt, 0, devip);
2892 if (errsts)
2893 break;
2894 if (scsi_debug_fake_rw)
2895 break;
2896 get_data_transfer_info(cmd, &lba, &num);
2897 errsts = resp_write(SCpnt, lba, num, devip);
2898 if (inj_recovered && (0 == errsts)) {
2899 mk_sense_buffer(devip, RECOVERED_ERROR,
2900 THRESHOLD_EXCEEDED, 0);
2901 errsts = check_condition_result;
2902 }
2903 break;
2904 case MODE_SENSE:
2905 case MODE_SENSE_10:
2906 errsts = resp_mode_sense(SCpnt, target, devip);
2907 break;
2908 case MODE_SELECT:
2909 errsts = resp_mode_select(SCpnt, 1, devip);
2910 break;
2911 case MODE_SELECT_10:
2912 errsts = resp_mode_select(SCpnt, 0, devip);
2913 break;
2914 case LOG_SENSE:
2915 errsts = resp_log_sense(SCpnt, devip);
2916 break;
2917 case SYNCHRONIZE_CACHE:
2918 delay_override = 1;
2919 errsts = check_readiness(SCpnt, 0, devip);
2920 break;
2921 case WRITE_BUFFER:
2922 errsts = check_readiness(SCpnt, 1, devip);
2923 break;
2924 case XDWRITEREAD_10:
2925 if (!scsi_bidi_cmnd(SCpnt)) {
2926 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2927 INVALID_FIELD_IN_CDB, 0);
2928 errsts = check_condition_result;
2929 break;
2930 }
2931
2932 errsts = check_readiness(SCpnt, 0, devip);
2933 if (errsts)
2934 break;
2935 if (scsi_debug_fake_rw)
2936 break;
2937 get_data_transfer_info(cmd, &lba, &num);
2938 errsts = resp_read(SCpnt, lba, num, devip);
2939 if (errsts)
2940 break;
2941 errsts = resp_write(SCpnt, lba, num, devip);
2942 if (errsts)
2943 break;
2944 errsts = resp_xdwriteread(SCpnt, lba, num, devip);
2945 break;
2946 default:
2947 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2948 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
2949 "supported\n", *cmd);
2950 errsts = check_readiness(SCpnt, 1, devip);
2951 if (errsts)
2952 break; /* Unit attention takes precedence */
2953 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
2954 errsts = check_condition_result;
2955 break;
2956 }
2957 return schedule_resp(SCpnt, devip, done, errsts,
2958 (delay_override ? 0 : scsi_debug_delay));
2959}
2960
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09002961static struct scsi_host_template sdebug_driver_template = {
2962 .proc_info = scsi_debug_proc_info,
2963 .proc_name = sdebug_proc_name,
2964 .name = "SCSI DEBUG",
2965 .info = scsi_debug_info,
2966 .slave_alloc = scsi_debug_slave_alloc,
2967 .slave_configure = scsi_debug_slave_configure,
2968 .slave_destroy = scsi_debug_slave_destroy,
2969 .ioctl = scsi_debug_ioctl,
2970 .queuecommand = scsi_debug_queuecommand,
2971 .eh_abort_handler = scsi_debug_abort,
2972 .eh_bus_reset_handler = scsi_debug_bus_reset,
2973 .eh_device_reset_handler = scsi_debug_device_reset,
2974 .eh_host_reset_handler = scsi_debug_host_reset,
2975 .bios_param = scsi_debug_biosparam,
2976 .can_queue = SCSI_DEBUG_CANQUEUE,
2977 .this_id = 7,
2978 .sg_tablesize = 256,
2979 .cmd_per_lun = 16,
2980 .max_sectors = 0xffff,
2981 .use_clustering = DISABLE_CLUSTERING,
2982 .module = THIS_MODULE,
2983};
2984
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985static int sdebug_driver_probe(struct device * dev)
2986{
2987 int error = 0;
2988 struct sdebug_host_info *sdbg_host;
2989 struct Scsi_Host *hpnt;
2990
2991 sdbg_host = to_sdebug_host(dev);
2992
2993 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
2994 if (NULL == hpnt) {
2995 printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__);
2996 error = -ENODEV;
2997 return error;
2998 }
2999
3000 sdbg_host->shost = hpnt;
3001 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
3002 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
3003 hpnt->max_id = scsi_debug_num_tgts + 1;
3004 else
3005 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003006 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007
3008 error = scsi_add_host(hpnt, &sdbg_host->dev);
3009 if (error) {
3010 printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
3011 error = -ENODEV;
3012 scsi_host_put(hpnt);
3013 } else
3014 scsi_scan_host(hpnt);
3015
3016
3017 return error;
3018}
3019
3020static int sdebug_driver_remove(struct device * dev)
3021{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003023 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024
3025 sdbg_host = to_sdebug_host(dev);
3026
3027 if (!sdbg_host) {
3028 printk(KERN_ERR "%s: Unable to locate host info\n",
3029 __FUNCTION__);
3030 return -ENODEV;
3031 }
3032
3033 scsi_remove_host(sdbg_host->shost);
3034
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003035 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
3036 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 list_del(&sdbg_devinfo->dev_list);
3038 kfree(sdbg_devinfo);
3039 }
3040
3041 scsi_host_put(sdbg_host->shost);
3042 return 0;
3043}
3044
3045static void sdebug_max_tgts_luns(void)
3046{
3047 struct sdebug_host_info * sdbg_host;
3048 struct Scsi_Host *hpnt;
3049
3050 spin_lock(&sdebug_host_list_lock);
3051 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3052 hpnt = sdbg_host->shost;
3053 if ((hpnt->this_id >= 0) &&
3054 (scsi_debug_num_tgts > hpnt->this_id))
3055 hpnt->max_id = scsi_debug_num_tgts + 1;
3056 else
3057 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003058 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 }
3060 spin_unlock(&sdebug_host_list_lock);
3061}