blob: 27c633f557945f8cfb99ce433bcf53ca774f2df8 [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>
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +090049#include <scsi/scsi_eh.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
51#include <linux/stat.h>
52
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#include "scsi_logging.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050055#define SCSI_DEBUG_VERSION "1.81"
56static const char * scsi_debug_version_date = "20070104";
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050058/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040059#define NO_ADDITIONAL_SENSE 0x0
60#define LOGICAL_UNIT_NOT_READY 0x4
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040062#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070063#define INVALID_OPCODE 0x20
64#define ADDR_OUT_OF_RANGE 0x21
65#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040066#define INVALID_FIELD_IN_PARAM_LIST 0x26
Linus Torvalds1da177e2005-04-16 15:20:36 -070067#define POWERON_RESET 0x29
68#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050069#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040070#define THRESHOLD_EXCEEDED 0x5d
71#define LOW_POWER_COND_ON 0x5e
Linus Torvalds1da177e2005-04-16 15:20:36 -070072
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050073/* Additional Sense Code Qualifier (ASCQ) */
74#define ACK_NAK_TO 0x3
75
Linus Torvalds1da177e2005-04-16 15:20:36 -070076#define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
77
78/* Default values for driver parameters */
79#define DEF_NUM_HOST 1
80#define DEF_NUM_TGTS 1
81#define DEF_MAX_LUNS 1
82/* With these defaults, this driver will make 1 host with 1 target
83 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
84 */
85#define DEF_DELAY 1
86#define DEF_DEV_SIZE_MB 8
87#define DEF_EVERY_NTH 0
88#define DEF_NUM_PARTS 0
89#define DEF_OPTS 0
90#define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */
91#define DEF_PTYPE 0
92#define DEF_D_SENSE 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -040093#define DEF_NO_LUN_0 0
94#define DEF_VIRTUAL_GB 0
Douglas Gilbert23183912006-09-16 20:30:47 -040095#define DEF_FAKE_RW 0
96#define DEF_VPD_USE_HOSTNO 1
Martin K. Petersen597136a2008-06-05 00:12:59 -040097#define DEF_SECTOR_SIZE 512
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
99/* bit mask values for scsi_debug_opts */
100#define SCSI_DEBUG_OPT_NOISE 1
101#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
102#define SCSI_DEBUG_OPT_TIMEOUT 4
103#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500104#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105/* When "every_nth" > 0 then modulo "every_nth" commands:
106 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
107 * - a RECOVERED_ERROR is simulated on successful read and write
108 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500109 * - a TRANSPORT_ERROR is simulated on successful read and write
110 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 *
112 * When "every_nth" < 0 then after "- every_nth" commands:
113 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
114 * - a RECOVERED_ERROR is simulated on successful read and write
115 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500116 * - a TRANSPORT_ERROR is simulated on successful read and write
117 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 * This will continue until some other action occurs (e.g. the user
119 * writing a new value (other than -1 or 1) to every_nth via sysfs).
120 */
121
122/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
123 * sector on read commands: */
124#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
125
126/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
127 * or "peripheral device" addressing (value 0) */
128#define SAM2_LUN_ADDRESS_METHOD 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400129#define SAM2_WLUN_REPORT_LUNS 0xc101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130
131static int scsi_debug_add_host = DEF_NUM_HOST;
132static int scsi_debug_delay = DEF_DELAY;
133static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
134static int scsi_debug_every_nth = DEF_EVERY_NTH;
135static int scsi_debug_max_luns = DEF_MAX_LUNS;
136static int scsi_debug_num_parts = DEF_NUM_PARTS;
137static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
138static int scsi_debug_opts = DEF_OPTS;
139static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
140static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
141static int scsi_debug_dsense = DEF_D_SENSE;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400142static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
143static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
Douglas Gilbert23183912006-09-16 20:30:47 -0400144static int scsi_debug_fake_rw = DEF_FAKE_RW;
145static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
Martin K. Petersen597136a2008-06-05 00:12:59 -0400146static int scsi_debug_sector_size = DEF_SECTOR_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147
148static int scsi_debug_cmnd_count = 0;
149
150#define DEV_READONLY(TGT) (0)
151#define DEV_REMOVEABLE(TGT) (0)
152
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400153static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154static sector_t sdebug_capacity; /* in sectors */
155
156/* old BIOS stuff, kernel may get rid of them but some mode sense pages
157 may still need them */
158static int sdebug_heads; /* heads per disk */
159static int sdebug_cylinders_per; /* cylinders per surface */
160static int sdebug_sectors_per; /* sectors per cylinder */
161
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162#define SDEBUG_MAX_PARTS 4
163
164#define SDEBUG_SENSE_LEN 32
165
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +0900166#define SCSI_DEBUG_CANQUEUE 255
167#define SCSI_DEBUG_MAX_CMD_LEN 16
168
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169struct sdebug_dev_info {
170 struct list_head dev_list;
171 unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */
172 unsigned int channel;
173 unsigned int target;
174 unsigned int lun;
175 struct sdebug_host_info *sdbg_host;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400176 unsigned int wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 char reset;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400178 char stopped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 char used;
180};
181
182struct sdebug_host_info {
183 struct list_head host_list;
184 struct Scsi_Host *shost;
185 struct device dev;
186 struct list_head dev_info_list;
187};
188
189#define to_sdebug_host(d) \
190 container_of(d, struct sdebug_host_info, dev)
191
192static LIST_HEAD(sdebug_host_list);
193static DEFINE_SPINLOCK(sdebug_host_list_lock);
194
195typedef void (* done_funct_t) (struct scsi_cmnd *);
196
197struct sdebug_queued_cmd {
198 int in_use;
199 struct timer_list cmnd_timer;
200 done_funct_t done_funct;
201 struct scsi_cmnd * a_cmnd;
202 int scsi_result;
203};
204static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
205
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206static unsigned char * fake_storep; /* ramdisk storage */
207
208static int num_aborts = 0;
209static int num_dev_resets = 0;
210static int num_bus_resets = 0;
211static int num_host_resets = 0;
212
213static DEFINE_SPINLOCK(queued_arr_lock);
214static DEFINE_RWLOCK(atomic_rw);
215
216static char sdebug_proc_name[] = "scsi_debug";
217
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218static struct bus_type pseudo_lld_bus;
219
220static struct device_driver sdebug_driverfs_driver = {
221 .name = sdebug_proc_name,
222 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223};
224
225static const int check_condition_result =
226 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
227
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400228static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
229 0, 0, 0x2, 0x4b};
230static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
231 0, 0, 0x0, 0x0};
232
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233static int sdebug_add_adapter(void);
234static void sdebug_remove_adapter(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900236static void sdebug_max_tgts_luns(void)
237{
238 struct sdebug_host_info *sdbg_host;
239 struct Scsi_Host *hpnt;
240
241 spin_lock(&sdebug_host_list_lock);
242 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
243 hpnt = sdbg_host->shost;
244 if ((hpnt->this_id >= 0) &&
245 (scsi_debug_num_tgts > hpnt->this_id))
246 hpnt->max_id = scsi_debug_num_tgts + 1;
247 else
248 hpnt->max_id = scsi_debug_num_tgts;
249 /* scsi_debug_max_luns; */
250 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;
251 }
252 spin_unlock(&sdebug_host_list_lock);
253}
254
255static void mk_sense_buffer(struct sdebug_dev_info *devip, int key,
256 int asc, int asq)
257{
258 unsigned char *sbuff;
259
260 sbuff = devip->sense_buff;
261 memset(sbuff, 0, SDEBUG_SENSE_LEN);
262
263 scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
264
265 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
266 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
267 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
268}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900270static void get_data_transfer_info(unsigned char *cmd,
271 unsigned long long *lba, unsigned int *num)
272{
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900273 switch (*cmd) {
274 case WRITE_16:
275 case READ_16:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900276 *lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
277 (u64)cmd[7] << 16 | (u64)cmd[6] << 24 |
278 (u64)cmd[5] << 32 | (u64)cmd[4] << 40 |
279 (u64)cmd[3] << 48 | (u64)cmd[2] << 56;
280
281 *num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 |
282 (u32)cmd[10] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900283 break;
284 case WRITE_12:
285 case READ_12:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900286 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
287 (u32)cmd[2] << 24;
288
289 *num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |
290 (u32)cmd[6] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900291 break;
292 case WRITE_10:
293 case READ_10:
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900294 case XDWRITEREAD_10:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900295 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
296 (u32)cmd[2] << 24;
297
298 *num = (u32)cmd[8] | (u32)cmd[7] << 8;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900299 break;
300 case WRITE_6:
301 case READ_6:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900302 *lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
303 (u32)(cmd[1] & 0x1f) << 16;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900304 *num = (0 == cmd[4]) ? 256 : cmd[4];
305 break;
306 default:
307 break;
308 }
309}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
312{
313 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
314 printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
315 }
316 return -EINVAL;
317 /* return -ENOTTY; // correct return but upsets fdisk */
318}
319
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400320static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
321 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322{
323 if (devip->reset) {
324 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
325 printk(KERN_INFO "scsi_debug: Reporting Unit "
326 "attention: power on reset\n");
327 devip->reset = 0;
328 mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
329 return check_condition_result;
330 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400331 if ((0 == reset_only) && devip->stopped) {
332 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
333 printk(KERN_INFO "scsi_debug: Reporting Not "
334 "ready: initializing command required\n");
335 mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
336 0x2);
337 return check_condition_result;
338 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 return 0;
340}
341
342/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900343static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 int arr_len)
345{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900346 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900347 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900349 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900351 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 return (DID_ERROR << 16);
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900353
354 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
355 arr, arr_len);
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900356 if (sdb->resid)
357 sdb->resid -= act_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400358 else
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900359 sdb->resid = scsi_bufflen(scp) - act_len;
360
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 return 0;
362}
363
364/* Returns number of bytes fetched into 'arr' or -1 if error. */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900365static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
366 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900368 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900370 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900372
373 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374}
375
376
377static const char * inq_vendor_id = "Linux ";
378static const char * inq_product_id = "scsi_debug ";
379static const char * inq_product_rev = "0004";
380
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200381static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
382 int target_dev_id, int dev_id_num,
383 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400384 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400386 int num, port_a;
387 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400389 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 /* T10 vendor identifier field format (faked) */
391 arr[0] = 0x2; /* ASCII */
392 arr[1] = 0x1;
393 arr[2] = 0x0;
394 memcpy(&arr[4], inq_vendor_id, 8);
395 memcpy(&arr[12], inq_product_id, 16);
396 memcpy(&arr[28], dev_id_str, dev_id_str_len);
397 num = 8 + 16 + dev_id_str_len;
398 arr[3] = num;
399 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400400 if (dev_id_num >= 0) {
401 /* NAA-5, Logical unit identifier (binary) */
402 arr[num++] = 0x1; /* binary (not necessarily sas) */
403 arr[num++] = 0x3; /* PIV=0, lu, naa */
404 arr[num++] = 0x0;
405 arr[num++] = 0x8;
406 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
407 arr[num++] = 0x33;
408 arr[num++] = 0x33;
409 arr[num++] = 0x30;
410 arr[num++] = (dev_id_num >> 24);
411 arr[num++] = (dev_id_num >> 16) & 0xff;
412 arr[num++] = (dev_id_num >> 8) & 0xff;
413 arr[num++] = dev_id_num & 0xff;
414 /* Target relative port number */
415 arr[num++] = 0x61; /* proto=sas, binary */
416 arr[num++] = 0x94; /* PIV=1, target port, rel port */
417 arr[num++] = 0x0; /* reserved */
418 arr[num++] = 0x4; /* length */
419 arr[num++] = 0x0; /* reserved */
420 arr[num++] = 0x0; /* reserved */
421 arr[num++] = 0x0;
422 arr[num++] = 0x1; /* relative port A */
423 }
424 /* NAA-5, Target port identifier */
425 arr[num++] = 0x61; /* proto=sas, binary */
426 arr[num++] = 0x93; /* piv=1, target port, naa */
427 arr[num++] = 0x0;
428 arr[num++] = 0x8;
429 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
430 arr[num++] = 0x22;
431 arr[num++] = 0x22;
432 arr[num++] = 0x20;
433 arr[num++] = (port_a >> 24);
434 arr[num++] = (port_a >> 16) & 0xff;
435 arr[num++] = (port_a >> 8) & 0xff;
436 arr[num++] = port_a & 0xff;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200437 /* NAA-5, Target port group identifier */
438 arr[num++] = 0x61; /* proto=sas, binary */
439 arr[num++] = 0x95; /* piv=1, target port group id */
440 arr[num++] = 0x0;
441 arr[num++] = 0x4;
442 arr[num++] = 0;
443 arr[num++] = 0;
444 arr[num++] = (port_group_id >> 8) & 0xff;
445 arr[num++] = port_group_id & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400446 /* NAA-5, Target device identifier */
447 arr[num++] = 0x61; /* proto=sas, binary */
448 arr[num++] = 0xa3; /* piv=1, target device, naa */
449 arr[num++] = 0x0;
450 arr[num++] = 0x8;
451 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
452 arr[num++] = 0x22;
453 arr[num++] = 0x22;
454 arr[num++] = 0x20;
455 arr[num++] = (target_dev_id >> 24);
456 arr[num++] = (target_dev_id >> 16) & 0xff;
457 arr[num++] = (target_dev_id >> 8) & 0xff;
458 arr[num++] = target_dev_id & 0xff;
459 /* SCSI name string: Target device identifier */
460 arr[num++] = 0x63; /* proto=sas, UTF-8 */
461 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
462 arr[num++] = 0x0;
463 arr[num++] = 24;
464 memcpy(arr + num, "naa.52222220", 12);
465 num += 12;
466 snprintf(b, sizeof(b), "%08X", target_dev_id);
467 memcpy(arr + num, b, 8);
468 num += 8;
469 memset(arr + num, 0, 4);
470 num += 4;
471 return num;
472}
473
474
475static unsigned char vpd84_data[] = {
476/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
477 0x22,0x22,0x22,0x0,0xbb,0x1,
478 0x22,0x22,0x22,0x0,0xbb,0x2,
479};
480
481static int inquiry_evpd_84(unsigned char * arr)
482{
483 memcpy(arr, vpd84_data, sizeof(vpd84_data));
484 return sizeof(vpd84_data);
485}
486
487static int inquiry_evpd_85(unsigned char * arr)
488{
489 int num = 0;
490 const char * na1 = "https://www.kernel.org/config";
491 const char * na2 = "http://www.kernel.org/log";
492 int plen, olen;
493
494 arr[num++] = 0x1; /* lu, storage config */
495 arr[num++] = 0x0; /* reserved */
496 arr[num++] = 0x0;
497 olen = strlen(na1);
498 plen = olen + 1;
499 if (plen % 4)
500 plen = ((plen / 4) + 1) * 4;
501 arr[num++] = plen; /* length, null termianted, padded */
502 memcpy(arr + num, na1, olen);
503 memset(arr + num + olen, 0, plen - olen);
504 num += plen;
505
506 arr[num++] = 0x4; /* lu, logging */
507 arr[num++] = 0x0; /* reserved */
508 arr[num++] = 0x0;
509 olen = strlen(na2);
510 plen = olen + 1;
511 if (plen % 4)
512 plen = ((plen / 4) + 1) * 4;
513 arr[num++] = plen; /* length, null terminated, padded */
514 memcpy(arr + num, na2, olen);
515 memset(arr + num + olen, 0, plen - olen);
516 num += plen;
517
518 return num;
519}
520
521/* SCSI ports VPD page */
522static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
523{
524 int num = 0;
525 int port_a, port_b;
526
527 port_a = target_dev_id + 1;
528 port_b = port_a + 1;
529 arr[num++] = 0x0; /* reserved */
530 arr[num++] = 0x0; /* reserved */
531 arr[num++] = 0x0;
532 arr[num++] = 0x1; /* relative port 1 (primary) */
533 memset(arr + num, 0, 6);
534 num += 6;
535 arr[num++] = 0x0;
536 arr[num++] = 12; /* length tp descriptor */
537 /* naa-5 target port identifier (A) */
538 arr[num++] = 0x61; /* proto=sas, binary */
539 arr[num++] = 0x93; /* PIV=1, target port, NAA */
540 arr[num++] = 0x0; /* reserved */
541 arr[num++] = 0x8; /* length */
542 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
543 arr[num++] = 0x22;
544 arr[num++] = 0x22;
545 arr[num++] = 0x20;
546 arr[num++] = (port_a >> 24);
547 arr[num++] = (port_a >> 16) & 0xff;
548 arr[num++] = (port_a >> 8) & 0xff;
549 arr[num++] = port_a & 0xff;
550
551 arr[num++] = 0x0; /* reserved */
552 arr[num++] = 0x0; /* reserved */
553 arr[num++] = 0x0;
554 arr[num++] = 0x2; /* relative port 2 (secondary) */
555 memset(arr + num, 0, 6);
556 num += 6;
557 arr[num++] = 0x0;
558 arr[num++] = 12; /* length tp descriptor */
559 /* naa-5 target port identifier (B) */
560 arr[num++] = 0x61; /* proto=sas, binary */
561 arr[num++] = 0x93; /* PIV=1, target port, NAA */
562 arr[num++] = 0x0; /* reserved */
563 arr[num++] = 0x8; /* length */
564 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
565 arr[num++] = 0x22;
566 arr[num++] = 0x22;
567 arr[num++] = 0x20;
568 arr[num++] = (port_b >> 24);
569 arr[num++] = (port_b >> 16) & 0xff;
570 arr[num++] = (port_b >> 8) & 0xff;
571 arr[num++] = port_b & 0xff;
572
573 return num;
574}
575
576
577static unsigned char vpd89_data[] = {
578/* from 4th byte */ 0,0,0,0,
579'l','i','n','u','x',' ',' ',' ',
580'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
581'1','2','3','4',
5820x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
5830xec,0,0,0,
5840x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
5850,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
5860x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
5870x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
5880x53,0x41,
5890x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
5900x20,0x20,
5910x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
5920x10,0x80,
5930,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
5940x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
5950x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
5960,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
5970x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
5980x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
5990,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
6000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6010,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6020,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6030x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
6040,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
6050xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
6060,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
6070,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6080,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6090,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6120,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6170,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6180,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
619};
620
621static int inquiry_evpd_89(unsigned char * arr)
622{
623 memcpy(arr, vpd89_data, sizeof(vpd89_data));
624 return sizeof(vpd89_data);
625}
626
627
628static unsigned char vpdb0_data[] = {
629 /* from 4th byte */ 0,0,0,4,
630 0,0,0x4,0,
631 0,0,0,64,
632};
633
634static int inquiry_evpd_b0(unsigned char * arr)
635{
636 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
637 if (sdebug_store_sectors > 0x400) {
638 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
639 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
640 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
641 arr[7] = sdebug_store_sectors & 0xff;
642 }
643 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644}
645
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600646static int inquiry_evpd_b1(unsigned char *arr)
647{
648 memset(arr, 0, 0x3c);
649 arr[0] = 0;
650 arr[1] = 1;
651
652 return 0x3c;
653}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
655#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400656#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657
658static int resp_inquiry(struct scsi_cmnd * scp, int target,
659 struct sdebug_dev_info * devip)
660{
661 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200662 unsigned char * arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 unsigned char *cmd = (unsigned char *)scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200664 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665
666 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500667 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
668 if (! arr)
669 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400670 if (devip->wlun)
671 pq_pdt = 0x1e; /* present, wlun */
672 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
673 pq_pdt = 0x7f; /* not present, no device type */
674 else
675 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 arr[0] = pq_pdt;
677 if (0x2 & cmd[1]) { /* CMDDT bit set */
678 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
679 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200680 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 return check_condition_result;
682 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200683 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400684 char lu_id_str[6];
685 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200687 port_group_id = (((host_no + 1) & 0x7f) << 8) +
688 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -0400689 if (0 == scsi_debug_vpd_use_hostno)
690 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400691 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
692 (devip->target * 1000) + devip->lun);
693 target_dev_id = ((host_no + 1) * 2000) +
694 (devip->target * 1000) - 3;
695 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400697 arr[1] = cmd[2]; /*sanity */
698 n = 4;
699 arr[n++] = 0x0; /* this page */
700 arr[n++] = 0x80; /* unit serial number */
701 arr[n++] = 0x83; /* device identification */
702 arr[n++] = 0x84; /* software interface ident. */
703 arr[n++] = 0x85; /* management network addresses */
704 arr[n++] = 0x86; /* extended inquiry */
705 arr[n++] = 0x87; /* mode page policy */
706 arr[n++] = 0x88; /* SCSI ports */
707 arr[n++] = 0x89; /* ATA information */
708 arr[n++] = 0xb0; /* Block limits (SBC) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600709 arr[n++] = 0xb1; /* Block characteristics (SBC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400710 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400712 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400714 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400716 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200717 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
718 target_dev_id, lu_id_num,
719 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400720 } else if (0x84 == cmd[2]) { /* Software interface ident. */
721 arr[1] = cmd[2]; /*sanity */
722 arr[3] = inquiry_evpd_84(&arr[4]);
723 } else if (0x85 == cmd[2]) { /* Management network addresses */
724 arr[1] = cmd[2]; /*sanity */
725 arr[3] = inquiry_evpd_85(&arr[4]);
726 } else if (0x86 == cmd[2]) { /* extended inquiry */
727 arr[1] = cmd[2]; /*sanity */
728 arr[3] = 0x3c; /* number of following entries */
729 arr[4] = 0x0; /* no protection stuff */
730 arr[5] = 0x7; /* head of q, ordered + simple q's */
731 } else if (0x87 == cmd[2]) { /* mode page policy */
732 arr[1] = cmd[2]; /*sanity */
733 arr[3] = 0x8; /* number of following entries */
734 arr[4] = 0x2; /* disconnect-reconnect mp */
735 arr[6] = 0x80; /* mlus, shared */
736 arr[8] = 0x18; /* protocol specific lu */
737 arr[10] = 0x82; /* mlus, per initiator port */
738 } else if (0x88 == cmd[2]) { /* SCSI Ports */
739 arr[1] = cmd[2]; /*sanity */
740 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
741 } else if (0x89 == cmd[2]) { /* ATA information */
742 arr[1] = cmd[2]; /*sanity */
743 n = inquiry_evpd_89(&arr[4]);
744 arr[2] = (n >> 8);
745 arr[3] = (n & 0xff);
746 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
747 arr[1] = cmd[2]; /*sanity */
748 arr[3] = inquiry_evpd_b0(&arr[4]);
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600749 } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
750 arr[1] = cmd[2]; /*sanity */
751 arr[3] = inquiry_evpd_b1(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 } else {
753 /* Illegal request, invalid field in cdb */
754 mk_sense_buffer(devip, ILLEGAL_REQUEST,
755 INVALID_FIELD_IN_CDB, 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200756 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 return check_condition_result;
758 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400759 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200760 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400761 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200762 kfree(arr);
763 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 }
765 /* drops through here for a standard inquiry */
766 arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
767 arr[2] = scsi_debug_scsi_level;
768 arr[3] = 2; /* response_data_format==2 */
769 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200770 if (0 == scsi_debug_vpd_use_hostno)
771 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400772 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400774 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 memcpy(&arr[8], inq_vendor_id, 8);
776 memcpy(&arr[16], inq_product_id, 16);
777 memcpy(&arr[32], inq_product_rev, 4);
778 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400779 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
780 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
781 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400783 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400785 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400787 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200788 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200790 kfree(arr);
791 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792}
793
794static int resp_requests(struct scsi_cmnd * scp,
795 struct sdebug_dev_info * devip)
796{
797 unsigned char * sbuff;
798 unsigned char *cmd = (unsigned char *)scp->cmnd;
799 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400800 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 int len = 18;
802
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400803 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400805 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
806 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400808 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
809 if (want_dsense) {
810 arr[0] = 0x72;
811 arr[1] = 0x0; /* NO_SENSE in sense_key */
812 arr[2] = THRESHOLD_EXCEEDED;
813 arr[3] = 0xff; /* TEST set and MRIE==6 */
814 } else {
815 arr[0] = 0x70;
816 arr[2] = 0x0; /* NO_SENSE in sense_key */
817 arr[7] = 0xa; /* 18 byte sense buffer */
818 arr[12] = THRESHOLD_EXCEEDED;
819 arr[13] = 0xff; /* TEST set and MRIE==6 */
820 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400821 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400823 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
824 /* DESC bit set and sense_buff in fixed format */
825 memset(arr, 0, sizeof(arr));
826 arr[0] = 0x72;
827 arr[1] = sbuff[2]; /* sense key */
828 arr[2] = sbuff[12]; /* asc */
829 arr[3] = sbuff[13]; /* ascq */
830 len = 8;
831 }
832 }
833 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 return fill_from_dev_buffer(scp, arr, len);
835}
836
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400837static int resp_start_stop(struct scsi_cmnd * scp,
838 struct sdebug_dev_info * devip)
839{
840 unsigned char *cmd = (unsigned char *)scp->cmnd;
841 int power_cond, errsts, start;
842
843 if ((errsts = check_readiness(scp, 1, devip)))
844 return errsts;
845 power_cond = (cmd[4] & 0xf0) >> 4;
846 if (power_cond) {
847 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
848 0);
849 return check_condition_result;
850 }
851 start = cmd[4] & 1;
852 if (start == devip->stopped)
853 devip->stopped = !start;
854 return 0;
855}
856
FUJITA Tomonori28898872008-03-30 00:59:55 +0900857static sector_t get_sdebug_capacity(void)
858{
859 if (scsi_debug_virtual_gb > 0)
860 return 2048 * 1024 * scsi_debug_virtual_gb;
861 else
862 return sdebug_store_sectors;
863}
864
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865#define SDEBUG_READCAP_ARR_SZ 8
866static int resp_readcap(struct scsi_cmnd * scp,
867 struct sdebug_dev_info * devip)
868{
869 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400870 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 int errsts;
872
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400873 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400875 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +0900876 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400878 if (sdebug_capacity < 0xffffffff) {
879 capac = (unsigned int)sdebug_capacity - 1;
880 arr[0] = (capac >> 24);
881 arr[1] = (capac >> 16) & 0xff;
882 arr[2] = (capac >> 8) & 0xff;
883 arr[3] = capac & 0xff;
884 } else {
885 arr[0] = 0xff;
886 arr[1] = 0xff;
887 arr[2] = 0xff;
888 arr[3] = 0xff;
889 }
Martin K. Petersen597136a2008-06-05 00:12:59 -0400890 arr[6] = (scsi_debug_sector_size >> 8) & 0xff;
891 arr[7] = scsi_debug_sector_size & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
893}
894
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400895#define SDEBUG_READCAP16_ARR_SZ 32
896static int resp_readcap16(struct scsi_cmnd * scp,
897 struct sdebug_dev_info * devip)
898{
899 unsigned char *cmd = (unsigned char *)scp->cmnd;
900 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
901 unsigned long long capac;
902 int errsts, k, alloc_len;
903
904 if ((errsts = check_readiness(scp, 1, devip)))
905 return errsts;
906 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
907 + cmd[13]);
908 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +0900909 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400910 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
911 capac = sdebug_capacity - 1;
912 for (k = 0; k < 8; ++k, capac >>= 8)
913 arr[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -0400914 arr[8] = (scsi_debug_sector_size >> 24) & 0xff;
915 arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
916 arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
917 arr[11] = scsi_debug_sector_size & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400918 return fill_from_dev_buffer(scp, arr,
919 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
920}
921
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200922#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
923
924static int resp_report_tgtpgs(struct scsi_cmnd * scp,
925 struct sdebug_dev_info * devip)
926{
927 unsigned char *cmd = (unsigned char *)scp->cmnd;
928 unsigned char * arr;
929 int host_no = devip->sdbg_host->shost->host_no;
930 int n, ret, alen, rlen;
931 int port_group_a, port_group_b, port_a, port_b;
932
933 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
934 + cmd[9]);
935
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500936 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
937 if (! arr)
938 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200939 /*
940 * EVPD page 0x88 states we have two ports, one
941 * real and a fake port with no device connected.
942 * So we create two port groups with one port each
943 * and set the group with port B to unavailable.
944 */
945 port_a = 0x1; /* relative port A */
946 port_b = 0x2; /* relative port B */
947 port_group_a = (((host_no + 1) & 0x7f) << 8) +
948 (devip->channel & 0x7f);
949 port_group_b = (((host_no + 1) & 0x7f) << 8) +
950 (devip->channel & 0x7f) + 0x80;
951
952 /*
953 * The asymmetric access state is cycled according to the host_id.
954 */
955 n = 4;
956 if (0 == scsi_debug_vpd_use_hostno) {
957 arr[n++] = host_no % 3; /* Asymm access state */
958 arr[n++] = 0x0F; /* claim: all states are supported */
959 } else {
960 arr[n++] = 0x0; /* Active/Optimized path */
961 arr[n++] = 0x01; /* claim: only support active/optimized paths */
962 }
963 arr[n++] = (port_group_a >> 8) & 0xff;
964 arr[n++] = port_group_a & 0xff;
965 arr[n++] = 0; /* Reserved */
966 arr[n++] = 0; /* Status code */
967 arr[n++] = 0; /* Vendor unique */
968 arr[n++] = 0x1; /* One port per group */
969 arr[n++] = 0; /* Reserved */
970 arr[n++] = 0; /* Reserved */
971 arr[n++] = (port_a >> 8) & 0xff;
972 arr[n++] = port_a & 0xff;
973 arr[n++] = 3; /* Port unavailable */
974 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
975 arr[n++] = (port_group_b >> 8) & 0xff;
976 arr[n++] = port_group_b & 0xff;
977 arr[n++] = 0; /* Reserved */
978 arr[n++] = 0; /* Status code */
979 arr[n++] = 0; /* Vendor unique */
980 arr[n++] = 0x1; /* One port per group */
981 arr[n++] = 0; /* Reserved */
982 arr[n++] = 0; /* Reserved */
983 arr[n++] = (port_b >> 8) & 0xff;
984 arr[n++] = port_b & 0xff;
985
986 rlen = n - 4;
987 arr[0] = (rlen >> 24) & 0xff;
988 arr[1] = (rlen >> 16) & 0xff;
989 arr[2] = (rlen >> 8) & 0xff;
990 arr[3] = rlen & 0xff;
991
992 /*
993 * Return the smallest value of either
994 * - The allocated length
995 * - The constructed command length
996 * - The maximum array size
997 */
998 rlen = min(alen,n);
999 ret = fill_from_dev_buffer(scp, arr,
1000 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1001 kfree(arr);
1002 return ret;
1003}
1004
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005/* <<Following mode page info copied from ST318451LW>> */
1006
1007static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1008{ /* Read-Write Error Recovery page for mode_sense */
1009 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1010 5, 0, 0xff, 0xff};
1011
1012 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1013 if (1 == pcontrol)
1014 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1015 return sizeof(err_recov_pg);
1016}
1017
1018static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1019{ /* Disconnect-Reconnect page for mode_sense */
1020 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1021 0, 0, 0, 0, 0, 0, 0, 0};
1022
1023 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1024 if (1 == pcontrol)
1025 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1026 return sizeof(disconnect_pg);
1027}
1028
1029static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1030{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001031 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1032 0, 0, 0, 0, 0, 0, 0, 0,
1033 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034
Martin K. Petersen597136a2008-06-05 00:12:59 -04001035 memcpy(p, format_pg, sizeof(format_pg));
1036 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1037 p[11] = sdebug_sectors_per & 0xff;
1038 p[12] = (scsi_debug_sector_size >> 8) & 0xff;
1039 p[13] = scsi_debug_sector_size & 0xff;
1040 if (DEV_REMOVEABLE(target))
1041 p[20] |= 0x20; /* should agree with INQUIRY */
1042 if (1 == pcontrol)
1043 memset(p + 2, 0, sizeof(format_pg) - 2);
1044 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045}
1046
1047static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1048{ /* Caching page for mode_sense */
1049 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1050 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1051
1052 memcpy(p, caching_pg, sizeof(caching_pg));
1053 if (1 == pcontrol)
1054 memset(p + 2, 0, sizeof(caching_pg) - 2);
1055 return sizeof(caching_pg);
1056}
1057
1058static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1059{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001060 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1061 0, 0, 0, 0};
1062 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 0, 0, 0x2, 0x4b};
1064
1065 if (scsi_debug_dsense)
1066 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001067 else
1068 ctrl_m_pg[2] &= ~0x4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1070 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001071 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1072 else if (2 == pcontrol)
1073 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 return sizeof(ctrl_m_pg);
1075}
1076
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001077
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1079{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001080 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1081 0, 0, 0x0, 0x0};
1082 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1083 0, 0, 0x0, 0x0};
1084
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1086 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001087 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1088 else if (2 == pcontrol)
1089 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 return sizeof(iec_m_pg);
1091}
1092
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001093static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1094{ /* SAS SSP mode page - short format for mode_sense */
1095 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1096 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1097
1098 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1099 if (1 == pcontrol)
1100 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1101 return sizeof(sas_sf_m_pg);
1102}
1103
1104
1105static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1106 int target_dev_id)
1107{ /* SAS phy control and discover mode page for mode_sense */
1108 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1109 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1110 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1111 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1112 0x2, 0, 0, 0, 0, 0, 0, 0,
1113 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1114 0, 0, 0, 0, 0, 0, 0, 0,
1115 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1116 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1117 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1118 0x3, 0, 0, 0, 0, 0, 0, 0,
1119 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1120 0, 0, 0, 0, 0, 0, 0, 0,
1121 };
1122 int port_a, port_b;
1123
1124 port_a = target_dev_id + 1;
1125 port_b = port_a + 1;
1126 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1127 p[20] = (port_a >> 24);
1128 p[21] = (port_a >> 16) & 0xff;
1129 p[22] = (port_a >> 8) & 0xff;
1130 p[23] = port_a & 0xff;
1131 p[48 + 20] = (port_b >> 24);
1132 p[48 + 21] = (port_b >> 16) & 0xff;
1133 p[48 + 22] = (port_b >> 8) & 0xff;
1134 p[48 + 23] = port_b & 0xff;
1135 if (1 == pcontrol)
1136 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1137 return sizeof(sas_pcd_m_pg);
1138}
1139
1140static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1141{ /* SAS SSP shared protocol specific port mode subpage */
1142 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1143 0, 0, 0, 0, 0, 0, 0, 0,
1144 };
1145
1146 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1147 if (1 == pcontrol)
1148 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1149 return sizeof(sas_sha_m_pg);
1150}
1151
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152#define SDEBUG_MAX_MSENSE_SZ 256
1153
1154static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1155 struct sdebug_dev_info * devip)
1156{
Douglas Gilbert23183912006-09-16 20:30:47 -04001157 unsigned char dbd, llbaa;
1158 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001160 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 unsigned char * ap;
1162 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1163 unsigned char *cmd = (unsigned char *)scp->cmnd;
1164
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001165 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001167 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 pcontrol = (cmd[2] & 0xc0) >> 6;
1169 pcode = cmd[2] & 0x3f;
1170 subpcode = cmd[3];
1171 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001172 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1173 if ((0 == scsi_debug_ptype) && (0 == dbd))
1174 bd_len = llbaa ? 16 : 8;
1175 else
1176 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1178 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1179 if (0x3 == pcontrol) { /* Saving values not supported */
1180 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1181 0);
1182 return check_condition_result;
1183 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001184 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1185 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001186 /* set DPOFUA bit for disks */
1187 if (0 == scsi_debug_ptype)
1188 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1189 else
1190 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 if (msense_6) {
1192 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001193 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 offset = 4;
1195 } else {
1196 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001197 if (16 == bd_len)
1198 arr[4] = 0x1; /* set LONGLBA bit */
1199 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 offset = 8;
1201 }
1202 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09001203 if ((bd_len > 0) && (!sdebug_capacity))
1204 sdebug_capacity = get_sdebug_capacity();
1205
Douglas Gilbert23183912006-09-16 20:30:47 -04001206 if (8 == bd_len) {
1207 if (sdebug_capacity > 0xfffffffe) {
1208 ap[0] = 0xff;
1209 ap[1] = 0xff;
1210 ap[2] = 0xff;
1211 ap[3] = 0xff;
1212 } else {
1213 ap[0] = (sdebug_capacity >> 24) & 0xff;
1214 ap[1] = (sdebug_capacity >> 16) & 0xff;
1215 ap[2] = (sdebug_capacity >> 8) & 0xff;
1216 ap[3] = sdebug_capacity & 0xff;
1217 }
Martin K. Petersen597136a2008-06-05 00:12:59 -04001218 ap[6] = (scsi_debug_sector_size >> 8) & 0xff;
1219 ap[7] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001220 offset += bd_len;
1221 ap = arr + offset;
1222 } else if (16 == bd_len) {
1223 unsigned long long capac = sdebug_capacity;
1224
1225 for (k = 0; k < 8; ++k, capac >>= 8)
1226 ap[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -04001227 ap[12] = (scsi_debug_sector_size >> 24) & 0xff;
1228 ap[13] = (scsi_debug_sector_size >> 16) & 0xff;
1229 ap[14] = (scsi_debug_sector_size >> 8) & 0xff;
1230 ap[15] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001231 offset += bd_len;
1232 ap = arr + offset;
1233 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001235 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1236 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1238 0);
1239 return check_condition_result;
1240 }
1241 switch (pcode) {
1242 case 0x1: /* Read-Write error recovery page, direct access */
1243 len = resp_err_recov_pg(ap, pcontrol, target);
1244 offset += len;
1245 break;
1246 case 0x2: /* Disconnect-Reconnect page, all devices */
1247 len = resp_disconnect_pg(ap, pcontrol, target);
1248 offset += len;
1249 break;
1250 case 0x3: /* Format device page, direct access */
1251 len = resp_format_pg(ap, pcontrol, target);
1252 offset += len;
1253 break;
1254 case 0x8: /* Caching page, direct access */
1255 len = resp_caching_pg(ap, pcontrol, target);
1256 offset += len;
1257 break;
1258 case 0xa: /* Control Mode page, all devices */
1259 len = resp_ctrl_m_pg(ap, pcontrol, target);
1260 offset += len;
1261 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001262 case 0x19: /* if spc==1 then sas phy, control+discover */
1263 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1264 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1265 INVALID_FIELD_IN_CDB, 0);
1266 return check_condition_result;
1267 }
1268 len = 0;
1269 if ((0x0 == subpcode) || (0xff == subpcode))
1270 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1271 if ((0x1 == subpcode) || (0xff == subpcode))
1272 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1273 target_dev_id);
1274 if ((0x2 == subpcode) || (0xff == subpcode))
1275 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1276 offset += len;
1277 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 case 0x1c: /* Informational Exceptions Mode page, all devices */
1279 len = resp_iec_m_pg(ap, pcontrol, target);
1280 offset += len;
1281 break;
1282 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001283 if ((0 == subpcode) || (0xff == subpcode)) {
1284 len = resp_err_recov_pg(ap, pcontrol, target);
1285 len += resp_disconnect_pg(ap + len, pcontrol, target);
1286 len += resp_format_pg(ap + len, pcontrol, target);
1287 len += resp_caching_pg(ap + len, pcontrol, target);
1288 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1289 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1290 if (0xff == subpcode) {
1291 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1292 target, target_dev_id);
1293 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1294 }
1295 len += resp_iec_m_pg(ap + len, pcontrol, target);
1296 } else {
1297 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1298 INVALID_FIELD_IN_CDB, 0);
1299 return check_condition_result;
1300 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 offset += len;
1302 break;
1303 default:
1304 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1305 0);
1306 return check_condition_result;
1307 }
1308 if (msense_6)
1309 arr[0] = offset - 1;
1310 else {
1311 arr[0] = ((offset - 2) >> 8) & 0xff;
1312 arr[1] = (offset - 2) & 0xff;
1313 }
1314 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1315}
1316
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001317#define SDEBUG_MAX_MSELECT_SZ 512
1318
1319static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1320 struct sdebug_dev_info * devip)
1321{
1322 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1323 int param_len, res, errsts, mpage;
1324 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1325 unsigned char *cmd = (unsigned char *)scp->cmnd;
1326
1327 if ((errsts = check_readiness(scp, 1, devip)))
1328 return errsts;
1329 memset(arr, 0, sizeof(arr));
1330 pf = cmd[1] & 0x10;
1331 sp = cmd[1] & 0x1;
1332 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1333 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1334 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1335 INVALID_FIELD_IN_CDB, 0);
1336 return check_condition_result;
1337 }
1338 res = fetch_to_dev_buffer(scp, arr, param_len);
1339 if (-1 == res)
1340 return (DID_ERROR << 16);
1341 else if ((res < param_len) &&
1342 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1343 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1344 " IO sent=%d bytes\n", param_len, res);
1345 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1346 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001347 if (md_len > 2) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001348 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1349 INVALID_FIELD_IN_PARAM_LIST, 0);
1350 return check_condition_result;
1351 }
1352 off = bd_len + (mselect6 ? 4 : 8);
1353 mpage = arr[off] & 0x3f;
1354 ps = !!(arr[off] & 0x80);
1355 if (ps) {
1356 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1357 INVALID_FIELD_IN_PARAM_LIST, 0);
1358 return check_condition_result;
1359 }
1360 spf = !!(arr[off] & 0x40);
1361 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1362 (arr[off + 1] + 2);
1363 if ((pg_len + off) > param_len) {
1364 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1365 PARAMETER_LIST_LENGTH_ERR, 0);
1366 return check_condition_result;
1367 }
1368 switch (mpage) {
1369 case 0xa: /* Control Mode page */
1370 if (ctrl_m_pg[1] == arr[off + 1]) {
1371 memcpy(ctrl_m_pg + 2, arr + off + 2,
1372 sizeof(ctrl_m_pg) - 2);
1373 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1374 return 0;
1375 }
1376 break;
1377 case 0x1c: /* Informational Exceptions Mode page */
1378 if (iec_m_pg[1] == arr[off + 1]) {
1379 memcpy(iec_m_pg + 2, arr + off + 2,
1380 sizeof(iec_m_pg) - 2);
1381 return 0;
1382 }
1383 break;
1384 default:
1385 break;
1386 }
1387 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1388 INVALID_FIELD_IN_PARAM_LIST, 0);
1389 return check_condition_result;
1390}
1391
1392static int resp_temp_l_pg(unsigned char * arr)
1393{
1394 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1395 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1396 };
1397
1398 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1399 return sizeof(temp_l_pg);
1400}
1401
1402static int resp_ie_l_pg(unsigned char * arr)
1403{
1404 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1405 };
1406
1407 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1408 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1409 arr[4] = THRESHOLD_EXCEEDED;
1410 arr[5] = 0xff;
1411 }
1412 return sizeof(ie_l_pg);
1413}
1414
1415#define SDEBUG_MAX_LSENSE_SZ 512
1416
1417static int resp_log_sense(struct scsi_cmnd * scp,
1418 struct sdebug_dev_info * devip)
1419{
Douglas Gilbert23183912006-09-16 20:30:47 -04001420 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001421 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1422 unsigned char *cmd = (unsigned char *)scp->cmnd;
1423
1424 if ((errsts = check_readiness(scp, 1, devip)))
1425 return errsts;
1426 memset(arr, 0, sizeof(arr));
1427 ppc = cmd[1] & 0x2;
1428 sp = cmd[1] & 0x1;
1429 if (ppc || sp) {
1430 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1431 INVALID_FIELD_IN_CDB, 0);
1432 return check_condition_result;
1433 }
1434 pcontrol = (cmd[2] & 0xc0) >> 6;
1435 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001436 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001437 alloc_len = (cmd[7] << 8) + cmd[8];
1438 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001439 if (0 == subpcode) {
1440 switch (pcode) {
1441 case 0x0: /* Supported log pages log page */
1442 n = 4;
1443 arr[n++] = 0x0; /* this page */
1444 arr[n++] = 0xd; /* Temperature */
1445 arr[n++] = 0x2f; /* Informational exceptions */
1446 arr[3] = n - 4;
1447 break;
1448 case 0xd: /* Temperature log page */
1449 arr[3] = resp_temp_l_pg(arr + 4);
1450 break;
1451 case 0x2f: /* Informational exceptions log page */
1452 arr[3] = resp_ie_l_pg(arr + 4);
1453 break;
1454 default:
1455 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1456 INVALID_FIELD_IN_CDB, 0);
1457 return check_condition_result;
1458 }
1459 } else if (0xff == subpcode) {
1460 arr[0] |= 0x40;
1461 arr[1] = subpcode;
1462 switch (pcode) {
1463 case 0x0: /* Supported log pages and subpages log page */
1464 n = 4;
1465 arr[n++] = 0x0;
1466 arr[n++] = 0x0; /* 0,0 page */
1467 arr[n++] = 0x0;
1468 arr[n++] = 0xff; /* this page */
1469 arr[n++] = 0xd;
1470 arr[n++] = 0x0; /* Temperature */
1471 arr[n++] = 0x2f;
1472 arr[n++] = 0x0; /* Informational exceptions */
1473 arr[3] = n - 4;
1474 break;
1475 case 0xd: /* Temperature subpages */
1476 n = 4;
1477 arr[n++] = 0xd;
1478 arr[n++] = 0x0; /* Temperature */
1479 arr[3] = n - 4;
1480 break;
1481 case 0x2f: /* Informational exceptions subpages */
1482 n = 4;
1483 arr[n++] = 0x2f;
1484 arr[n++] = 0x0; /* Informational exceptions */
1485 arr[3] = n - 4;
1486 break;
1487 default:
1488 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1489 INVALID_FIELD_IN_CDB, 0);
1490 return check_condition_result;
1491 }
1492 } else {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001493 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1494 INVALID_FIELD_IN_CDB, 0);
1495 return check_condition_result;
1496 }
1497 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1498 return fill_from_dev_buffer(scp, arr,
1499 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1500}
1501
FUJITA Tomonori19789102008-03-30 00:59:56 +09001502static int check_device_access_params(struct sdebug_dev_info *devi,
1503 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001505 if (lba + num > sdebug_capacity) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001506 mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 return check_condition_result;
1508 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001509 /* transfer length excessive (tie in to block limits VPD page) */
1510 if (num > sdebug_store_sectors) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001511 mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001512 return check_condition_result;
1513 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09001514 return 0;
1515}
1516
1517static int do_device_access(struct scsi_cmnd *scmd,
1518 struct sdebug_dev_info *devi,
1519 unsigned long long lba, unsigned int num, int write)
1520{
1521 int ret;
1522 unsigned int block, rest = 0;
1523 int (*func)(struct scsi_cmnd *, unsigned char *, int);
1524
1525 func = write ? fetch_to_dev_buffer : fill_from_dev_buffer;
1526
1527 block = do_div(lba, sdebug_store_sectors);
1528 if (block + num > sdebug_store_sectors)
1529 rest = block + num - sdebug_store_sectors;
1530
Martin K. Petersen597136a2008-06-05 00:12:59 -04001531 ret = func(scmd, fake_storep + (block * scsi_debug_sector_size),
1532 (num - rest) * scsi_debug_sector_size);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001533 if (!ret && rest)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001534 ret = func(scmd, fake_storep, rest * scsi_debug_sector_size);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001535
1536 return ret;
1537}
1538
1539static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
1540 unsigned int num, struct sdebug_dev_info *devip)
1541{
1542 unsigned long iflags;
1543 int ret;
1544
1545 ret = check_device_access_params(devip, lba, num);
1546 if (ret)
1547 return ret;
1548
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001550 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1551 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1552 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1554 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001555 /* set info field and valid bit for fixed descriptor */
1556 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1557 devip->sense_buff[0] |= 0x80; /* Valid bit */
1558 ret = OPT_MEDIUM_ERR_ADDR;
1559 devip->sense_buff[3] = (ret >> 24) & 0xff;
1560 devip->sense_buff[4] = (ret >> 16) & 0xff;
1561 devip->sense_buff[5] = (ret >> 8) & 0xff;
1562 devip->sense_buff[6] = ret & 0xff;
1563 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 return check_condition_result;
1565 }
1566 read_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001567 ret = do_device_access(SCpnt, devip, lba, num, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 read_unlock_irqrestore(&atomic_rw, iflags);
1569 return ret;
1570}
1571
FUJITA Tomonori19789102008-03-30 00:59:56 +09001572static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
1573 unsigned int num, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574{
1575 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09001576 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577
FUJITA Tomonori19789102008-03-30 00:59:56 +09001578 ret = check_device_access_params(devip, lba, num);
1579 if (ret)
1580 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581
1582 write_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001583 ret = do_device_access(SCpnt, devip, lba, num, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 write_unlock_irqrestore(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001585 if (-1 == ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 return (DID_ERROR << 16);
Martin K. Petersen597136a2008-06-05 00:12:59 -04001587 else if ((ret < (num * scsi_debug_sector_size)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001589 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Martin K. Petersen597136a2008-06-05 00:12:59 -04001590 " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 return 0;
1592}
1593
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001594#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595
1596static int resp_report_luns(struct scsi_cmnd * scp,
1597 struct sdebug_dev_info * devip)
1598{
1599 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001600 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 unsigned char *cmd = (unsigned char *)scp->cmnd;
1602 int select_report = (int)cmd[2];
1603 struct scsi_lun *one_lun;
1604 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001605 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606
1607 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001608 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1610 0);
1611 return check_condition_result;
1612 }
1613 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
1614 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
1615 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001616 if (1 == select_report)
1617 lun_cnt = 0;
1618 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
1619 --lun_cnt;
1620 wlun = (select_report > 0) ? 1 : 0;
1621 num = lun_cnt + wlun;
1622 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
1623 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
1624 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
1625 sizeof(struct scsi_lun)), num);
1626 if (n < num) {
1627 wlun = 0;
1628 lun_cnt = n;
1629 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001631 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
1632 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
1633 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
1634 i++, lun++) {
1635 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 if (upper)
1637 one_lun[i].scsi_lun[0] =
1638 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001639 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001641 if (wlun) {
1642 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
1643 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
1644 i++;
1645 }
1646 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 return fill_from_dev_buffer(scp, arr,
1648 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
1649}
1650
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001651static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
1652 unsigned int num, struct sdebug_dev_info *devip)
1653{
1654 int i, j, ret = -1;
1655 unsigned char *kaddr, *buf;
1656 unsigned int offset;
1657 struct scatterlist *sg;
1658 struct scsi_data_buffer *sdb = scsi_in(scp);
1659
1660 /* better not to use temporary buffer. */
1661 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
1662 if (!buf)
1663 return ret;
1664
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001665 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001666
1667 offset = 0;
1668 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
1669 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
1670 if (!kaddr)
1671 goto out;
1672
1673 for (j = 0; j < sg->length; j++)
1674 *(kaddr + sg->offset + j) ^= *(buf + offset + j);
1675
1676 offset += sg->length;
1677 kunmap_atomic(kaddr, KM_USER0);
1678 }
1679 ret = 0;
1680out:
1681 kfree(buf);
1682
1683 return ret;
1684}
1685
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686/* When timer goes off this function is called. */
1687static void timer_intr_handler(unsigned long indx)
1688{
1689 struct sdebug_queued_cmd * sqcp;
1690 unsigned long iflags;
1691
1692 if (indx >= SCSI_DEBUG_CANQUEUE) {
1693 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
1694 "large\n");
1695 return;
1696 }
1697 spin_lock_irqsave(&queued_arr_lock, iflags);
1698 sqcp = &queued_arr[(int)indx];
1699 if (! sqcp->in_use) {
1700 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
1701 "interrupt\n");
1702 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1703 return;
1704 }
1705 sqcp->in_use = 0;
1706 if (sqcp->done_funct) {
1707 sqcp->a_cmnd->result = sqcp->scsi_result;
1708 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
1709 }
1710 sqcp->done_funct = NULL;
1711 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1712}
1713
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09001715static struct sdebug_dev_info *
1716sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09001717{
1718 struct sdebug_dev_info *devip;
1719
1720 devip = kzalloc(sizeof(*devip), flags);
1721 if (devip) {
1722 devip->sdbg_host = sdbg_host;
1723 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
1724 }
1725 return devip;
1726}
1727
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
1729{
1730 struct sdebug_host_info * sdbg_host;
1731 struct sdebug_dev_info * open_devip = NULL;
1732 struct sdebug_dev_info * devip =
1733 (struct sdebug_dev_info *)sdev->hostdata;
1734
1735 if (devip)
1736 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09001737 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
1738 if (!sdbg_host) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 printk(KERN_ERR "Host info NULL\n");
1740 return NULL;
1741 }
1742 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
1743 if ((devip->used) && (devip->channel == sdev->channel) &&
1744 (devip->target == sdev->id) &&
1745 (devip->lun == sdev->lun))
1746 return devip;
1747 else {
1748 if ((!devip->used) && (!open_devip))
1749 open_devip = devip;
1750 }
1751 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09001752 if (!open_devip) { /* try and make a new one */
1753 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
1754 if (!open_devip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001756 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 return NULL;
1758 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09001760
1761 open_devip->channel = sdev->channel;
1762 open_devip->target = sdev->id;
1763 open_devip->lun = sdev->lun;
1764 open_devip->sdbg_host = sdbg_host;
1765 open_devip->reset = 1;
1766 open_devip->used = 1;
1767 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
1768 if (scsi_debug_dsense)
1769 open_devip->sense_buff[0] = 0x72;
1770 else {
1771 open_devip->sense_buff[0] = 0x70;
1772 open_devip->sense_buff[7] = 0xa;
1773 }
1774 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
1775 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
1776
1777 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778}
1779
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09001780static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09001782 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1783 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
1784 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02001785 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09001786 return 0;
1787}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09001789static int scsi_debug_slave_configure(struct scsi_device *sdp)
1790{
1791 struct sdebug_dev_info *devip;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09001792
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09001794 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
1795 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
1796 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
1797 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
1798 devip = devInfoReg(sdp);
1799 if (NULL == devip)
1800 return 1; /* no resources, will be marked offline */
1801 sdp->hostdata = devip;
1802 if (sdp->host->cmd_per_lun)
1803 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
1804 sdp->host->cmd_per_lun);
1805 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
1806 return 0;
1807}
1808
1809static void scsi_debug_slave_destroy(struct scsi_device *sdp)
1810{
1811 struct sdebug_dev_info *devip =
1812 (struct sdebug_dev_info *)sdp->hostdata;
1813
1814 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1815 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
1816 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
1817 if (devip) {
1818 /* make this slot avaliable for re-use */
1819 devip->used = 0;
1820 sdp->hostdata = NULL;
1821 }
1822}
1823
1824/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
1825static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
1826{
1827 unsigned long iflags;
1828 int k;
1829 struct sdebug_queued_cmd *sqcp;
1830
1831 spin_lock_irqsave(&queued_arr_lock, iflags);
1832 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1833 sqcp = &queued_arr[k];
1834 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
1835 del_timer_sync(&sqcp->cmnd_timer);
1836 sqcp->in_use = 0;
1837 sqcp->a_cmnd = NULL;
1838 break;
1839 }
1840 }
1841 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1842 return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
1843}
1844
1845/* Deletes (stops) timers of all queued commands */
1846static void stop_all_queued(void)
1847{
1848 unsigned long iflags;
1849 int k;
1850 struct sdebug_queued_cmd *sqcp;
1851
1852 spin_lock_irqsave(&queued_arr_lock, iflags);
1853 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1854 sqcp = &queued_arr[k];
1855 if (sqcp->in_use && sqcp->a_cmnd) {
1856 del_timer_sync(&sqcp->cmnd_timer);
1857 sqcp->in_use = 0;
1858 sqcp->a_cmnd = NULL;
1859 }
1860 }
1861 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862}
1863
1864static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
1865{
1866 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1867 printk(KERN_INFO "scsi_debug: abort\n");
1868 ++num_aborts;
1869 stop_queued_cmnd(SCpnt);
1870 return SUCCESS;
1871}
1872
1873static int scsi_debug_biosparam(struct scsi_device *sdev,
1874 struct block_device * bdev, sector_t capacity, int *info)
1875{
1876 int res;
1877 unsigned char *buf;
1878
1879 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1880 printk(KERN_INFO "scsi_debug: biosparam\n");
1881 buf = scsi_bios_ptable(bdev);
1882 if (buf) {
1883 res = scsi_partsize(buf, capacity,
1884 &info[2], &info[0], &info[1]);
1885 kfree(buf);
1886 if (! res)
1887 return res;
1888 }
1889 info[0] = sdebug_heads;
1890 info[1] = sdebug_sectors_per;
1891 info[2] = sdebug_cylinders_per;
1892 return 0;
1893}
1894
1895static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
1896{
1897 struct sdebug_dev_info * devip;
1898
1899 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1900 printk(KERN_INFO "scsi_debug: device_reset\n");
1901 ++num_dev_resets;
1902 if (SCpnt) {
1903 devip = devInfoReg(SCpnt->device);
1904 if (devip)
1905 devip->reset = 1;
1906 }
1907 return SUCCESS;
1908}
1909
1910static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
1911{
1912 struct sdebug_host_info *sdbg_host;
1913 struct sdebug_dev_info * dev_info;
1914 struct scsi_device * sdp;
1915 struct Scsi_Host * hp;
1916
1917 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1918 printk(KERN_INFO "scsi_debug: bus_reset\n");
1919 ++num_bus_resets;
1920 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09001921 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 if (sdbg_host) {
1923 list_for_each_entry(dev_info,
1924 &sdbg_host->dev_info_list,
1925 dev_list)
1926 dev_info->reset = 1;
1927 }
1928 }
1929 return SUCCESS;
1930}
1931
1932static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
1933{
1934 struct sdebug_host_info * sdbg_host;
1935 struct sdebug_dev_info * dev_info;
1936
1937 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1938 printk(KERN_INFO "scsi_debug: host_reset\n");
1939 ++num_host_resets;
1940 spin_lock(&sdebug_host_list_lock);
1941 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
1942 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
1943 dev_list)
1944 dev_info->reset = 1;
1945 }
1946 spin_unlock(&sdebug_host_list_lock);
1947 stop_all_queued();
1948 return SUCCESS;
1949}
1950
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951/* Initializes timers in queued array */
1952static void __init init_all_queued(void)
1953{
1954 unsigned long iflags;
1955 int k;
1956 struct sdebug_queued_cmd * sqcp;
1957
1958 spin_lock_irqsave(&queued_arr_lock, iflags);
1959 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1960 sqcp = &queued_arr[k];
1961 init_timer(&sqcp->cmnd_timer);
1962 sqcp->in_use = 0;
1963 sqcp->a_cmnd = NULL;
1964 }
1965 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1966}
1967
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09001968static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09001969 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970{
1971 struct partition * pp;
1972 int starts[SDEBUG_MAX_PARTS + 2];
1973 int sectors_per_part, num_sectors, k;
1974 int heads_by_sects, start_sec, end_sec;
1975
1976 /* assume partition table already zeroed */
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09001977 if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 return;
1979 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
1980 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
1981 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
1982 "partitions to %d\n", SDEBUG_MAX_PARTS);
1983 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001984 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 sectors_per_part = (num_sectors - sdebug_sectors_per)
1986 / scsi_debug_num_parts;
1987 heads_by_sects = sdebug_heads * sdebug_sectors_per;
1988 starts[0] = sdebug_sectors_per;
1989 for (k = 1; k < scsi_debug_num_parts; ++k)
1990 starts[k] = ((k * sectors_per_part) / heads_by_sects)
1991 * heads_by_sects;
1992 starts[scsi_debug_num_parts] = num_sectors;
1993 starts[scsi_debug_num_parts + 1] = 0;
1994
1995 ramp[510] = 0x55; /* magic partition markings */
1996 ramp[511] = 0xAA;
1997 pp = (struct partition *)(ramp + 0x1be);
1998 for (k = 0; starts[k + 1]; ++k, ++pp) {
1999 start_sec = starts[k];
2000 end_sec = starts[k + 1] - 1;
2001 pp->boot_ind = 0;
2002
2003 pp->cyl = start_sec / heads_by_sects;
2004 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2005 / sdebug_sectors_per;
2006 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2007
2008 pp->end_cyl = end_sec / heads_by_sects;
2009 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2010 / sdebug_sectors_per;
2011 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2012
2013 pp->start_sect = start_sec;
2014 pp->nr_sects = end_sec - start_sec + 1;
2015 pp->sys_ind = 0x83; /* plain Linux partition */
2016 }
2017}
2018
2019static int schedule_resp(struct scsi_cmnd * cmnd,
2020 struct sdebug_dev_info * devip,
2021 done_funct_t done, int scsi_result, int delta_jiff)
2022{
2023 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2024 if (scsi_result) {
2025 struct scsi_device * sdp = cmnd->device;
2026
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002027 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2028 "non-zero result=0x%x\n", sdp->host->host_no,
2029 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 }
2031 }
2032 if (cmnd && devip) {
2033 /* simulate autosense by this driver */
2034 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2035 memcpy(cmnd->sense_buffer, devip->sense_buff,
2036 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2037 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2038 }
2039 if (delta_jiff <= 0) {
2040 if (cmnd)
2041 cmnd->result = scsi_result;
2042 if (done)
2043 done(cmnd);
2044 return 0;
2045 } else {
2046 unsigned long iflags;
2047 int k;
2048 struct sdebug_queued_cmd * sqcp = NULL;
2049
2050 spin_lock_irqsave(&queued_arr_lock, iflags);
2051 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2052 sqcp = &queued_arr[k];
2053 if (! sqcp->in_use)
2054 break;
2055 }
2056 if (k >= SCSI_DEBUG_CANQUEUE) {
2057 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2058 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2059 return 1; /* report busy to mid level */
2060 }
2061 sqcp->in_use = 1;
2062 sqcp->a_cmnd = cmnd;
2063 sqcp->scsi_result = scsi_result;
2064 sqcp->done_funct = done;
2065 sqcp->cmnd_timer.function = timer_intr_handler;
2066 sqcp->cmnd_timer.data = k;
2067 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2068 add_timer(&sqcp->cmnd_timer);
2069 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2070 if (cmnd)
2071 cmnd->result = 0;
2072 return 0;
2073 }
2074}
Douglas Gilbert23183912006-09-16 20:30:47 -04002075/* Note: The following macros create attribute files in the
2076 /sys/module/scsi_debug/parameters directory. Unfortunately this
2077 driver is unaware of a change and cannot trigger auxiliary actions
2078 as it can when the corresponding attribute in the
2079 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2080 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002081module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2082module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2083module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2084module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2085module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002086module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002087module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2088module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2089module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2090module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2091module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2092module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2093module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2094module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002095module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2096 S_IRUGO | S_IWUSR);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002097module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098
2099MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2100MODULE_DESCRIPTION("SCSI debug adapter driver");
2101MODULE_LICENSE("GPL");
2102MODULE_VERSION(SCSI_DEBUG_VERSION);
2103
2104MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2105MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002106MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2107MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07002108MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002109MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002110MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2111MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002113MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002114MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2116MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002117MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002118MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Martin K. Petersen597136a2008-06-05 00:12:59 -04002119MODULE_PARM_DESC(sector_size, "hardware sector size in bytes (def=512)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120
2121
2122static char sdebug_info[256];
2123
2124static const char * scsi_debug_info(struct Scsi_Host * shp)
2125{
2126 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2127 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2128 scsi_debug_version_date, scsi_debug_dev_size_mb,
2129 scsi_debug_opts);
2130 return sdebug_info;
2131}
2132
2133/* scsi_debug_proc_info
2134 * Used if the driver currently has no own support for /proc/scsi
2135 */
2136static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2137 int length, int inout)
2138{
2139 int len, pos, begin;
2140 int orig_length;
2141
2142 orig_length = length;
2143
2144 if (inout == 1) {
2145 char arr[16];
2146 int minLen = length > 15 ? 15 : length;
2147
2148 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2149 return -EACCES;
2150 memcpy(arr, buffer, minLen);
2151 arr[minLen] = '\0';
2152 if (1 != sscanf(arr, "%d", &pos))
2153 return -EINVAL;
2154 scsi_debug_opts = pos;
2155 if (scsi_debug_every_nth != 0)
2156 scsi_debug_cmnd_count = 0;
2157 return length;
2158 }
2159 begin = 0;
2160 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2161 "%s [%s]\n"
2162 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2163 "every_nth=%d(curr:%d)\n"
2164 "delay=%d, max_luns=%d, scsi_level=%d\n"
2165 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2166 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
2167 "host_resets=%d\n",
2168 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2169 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2170 scsi_debug_cmnd_count, scsi_debug_delay,
2171 scsi_debug_max_luns, scsi_debug_scsi_level,
Martin K. Petersen597136a2008-06-05 00:12:59 -04002172 scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
2173 sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets,
2174 num_host_resets);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 if (pos < offset) {
2176 len = 0;
2177 begin = pos;
2178 }
2179 *start = buffer + (offset - begin); /* Start of wanted data */
2180 len -= (offset - begin);
2181 if (len > length)
2182 len = length;
2183 return len;
2184}
2185
2186static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2187{
2188 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2189}
2190
2191static ssize_t sdebug_delay_store(struct device_driver * ddp,
2192 const char * buf, size_t count)
2193{
2194 int delay;
2195 char work[20];
2196
2197 if (1 == sscanf(buf, "%10s", work)) {
2198 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2199 scsi_debug_delay = delay;
2200 return count;
2201 }
2202 }
2203 return -EINVAL;
2204}
2205DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2206 sdebug_delay_store);
2207
2208static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2209{
2210 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2211}
2212
2213static ssize_t sdebug_opts_store(struct device_driver * ddp,
2214 const char * buf, size_t count)
2215{
2216 int opts;
2217 char work[20];
2218
2219 if (1 == sscanf(buf, "%10s", work)) {
2220 if (0 == strnicmp(work,"0x", 2)) {
2221 if (1 == sscanf(&work[2], "%x", &opts))
2222 goto opts_done;
2223 } else {
2224 if (1 == sscanf(work, "%d", &opts))
2225 goto opts_done;
2226 }
2227 }
2228 return -EINVAL;
2229opts_done:
2230 scsi_debug_opts = opts;
2231 scsi_debug_cmnd_count = 0;
2232 return count;
2233}
2234DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2235 sdebug_opts_store);
2236
2237static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2238{
2239 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2240}
2241static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2242 const char * buf, size_t count)
2243{
2244 int n;
2245
2246 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2247 scsi_debug_ptype = n;
2248 return count;
2249 }
2250 return -EINVAL;
2251}
2252DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2253
2254static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2255{
2256 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2257}
2258static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2259 const char * buf, size_t count)
2260{
2261 int n;
2262
2263 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2264 scsi_debug_dsense = n;
2265 return count;
2266 }
2267 return -EINVAL;
2268}
2269DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2270 sdebug_dsense_store);
2271
Douglas Gilbert23183912006-09-16 20:30:47 -04002272static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2273{
2274 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2275}
2276static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2277 const char * buf, size_t count)
2278{
2279 int n;
2280
2281 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2282 scsi_debug_fake_rw = n;
2283 return count;
2284 }
2285 return -EINVAL;
2286}
2287DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2288 sdebug_fake_rw_store);
2289
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002290static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2291{
2292 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2293}
2294static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2295 const char * buf, size_t count)
2296{
2297 int n;
2298
2299 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2300 scsi_debug_no_lun_0 = n;
2301 return count;
2302 }
2303 return -EINVAL;
2304}
2305DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2306 sdebug_no_lun_0_store);
2307
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2309{
2310 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2311}
2312static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2313 const char * buf, size_t count)
2314{
2315 int n;
2316
2317 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2318 scsi_debug_num_tgts = n;
2319 sdebug_max_tgts_luns();
2320 return count;
2321 }
2322 return -EINVAL;
2323}
2324DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2325 sdebug_num_tgts_store);
2326
2327static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2328{
2329 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2330}
2331DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2332
2333static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2334{
2335 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2336}
2337DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2338
2339static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2340{
2341 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2342}
2343static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2344 const char * buf, size_t count)
2345{
2346 int nth;
2347
2348 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2349 scsi_debug_every_nth = nth;
2350 scsi_debug_cmnd_count = 0;
2351 return count;
2352 }
2353 return -EINVAL;
2354}
2355DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2356 sdebug_every_nth_store);
2357
2358static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2359{
2360 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2361}
2362static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2363 const char * buf, size_t count)
2364{
2365 int n;
2366
2367 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2368 scsi_debug_max_luns = n;
2369 sdebug_max_tgts_luns();
2370 return count;
2371 }
2372 return -EINVAL;
2373}
2374DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2375 sdebug_max_luns_store);
2376
2377static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
2378{
2379 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
2380}
2381DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
2382
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002383static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2384{
2385 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2386}
2387static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2388 const char * buf, size_t count)
2389{
2390 int n;
2391
2392 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2393 scsi_debug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002394
2395 sdebug_capacity = get_sdebug_capacity();
2396
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002397 return count;
2398 }
2399 return -EINVAL;
2400}
2401DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2402 sdebug_virtual_gb_store);
2403
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
2405{
2406 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
2407}
2408
2409static ssize_t sdebug_add_host_store(struct device_driver * ddp,
2410 const char * buf, size_t count)
2411{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002412 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002414 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416 if (delta_hosts > 0) {
2417 do {
2418 sdebug_add_adapter();
2419 } while (--delta_hosts);
2420 } else if (delta_hosts < 0) {
2421 do {
2422 sdebug_remove_adapter();
2423 } while (++delta_hosts);
2424 }
2425 return count;
2426}
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002427DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428 sdebug_add_host_store);
2429
Douglas Gilbert23183912006-09-16 20:30:47 -04002430static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
2431 char * buf)
2432{
2433 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
2434}
2435static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
2436 const char * buf, size_t count)
2437{
2438 int n;
2439
2440 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2441 scsi_debug_vpd_use_hostno = n;
2442 return count;
2443 }
2444 return -EINVAL;
2445}
2446DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
2447 sdebug_vpd_use_hostno_store);
2448
Martin K. Petersen597136a2008-06-05 00:12:59 -04002449static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf)
2450{
2451 return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size);
2452}
2453DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL);
2454
Douglas Gilbert23183912006-09-16 20:30:47 -04002455/* Note: The following function creates attribute files in the
2456 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
2457 files (over those found in the /sys/module/scsi_debug/parameters
2458 directory) is that auxiliary actions can be triggered when an attribute
2459 is changed. For example see: sdebug_add_host_store() above.
2460 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002461static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002463 int ret;
2464
2465 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2466 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
2467 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2468 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2469 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04002470 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002471 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002472 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002473 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002474 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002475 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
2476 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
2477 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04002478 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
2479 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002480 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
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{
Martin K. Petersen597136a2008-06-05 00:12:59 -04002486 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
Douglas Gilbert23183912006-09-16 20:30:47 -04002487 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
2488 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
2490 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
2491 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002493 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
2494 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002496 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
2498 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2499 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2500 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
2501 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2502}
2503
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002504static void pseudo_0_release(struct device *dev)
2505{
2506 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2507 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
2508}
2509
2510static struct device pseudo_primary = {
2511 .bus_id = "pseudo_0",
2512 .release = pseudo_0_release,
2513};
2514
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515static int __init scsi_debug_init(void)
2516{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09002517 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 int host_to_add;
2519 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002520 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521
Martin K. Petersen597136a2008-06-05 00:12:59 -04002522 switch (scsi_debug_sector_size) {
2523 case 512:
2524 case 1024:
2525 case 2048:
2526 case 4096:
2527 break;
2528 default:
2529 printk(KERN_ERR "scsi_debug_init: invalid sector_size %u\n",
2530 scsi_debug_sector_size);
2531 return -EINVAL;
2532 }
2533
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 if (scsi_debug_dev_size_mb < 1)
2535 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09002536 sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
Martin K. Petersen597136a2008-06-05 00:12:59 -04002537 sdebug_store_sectors = sz / scsi_debug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002538 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539
2540 /* play around with geometry, don't waste too much on track 0 */
2541 sdebug_heads = 8;
2542 sdebug_sectors_per = 32;
2543 if (scsi_debug_dev_size_mb >= 16)
2544 sdebug_heads = 32;
2545 else if (scsi_debug_dev_size_mb >= 256)
2546 sdebug_heads = 64;
2547 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2548 (sdebug_sectors_per * sdebug_heads);
2549 if (sdebug_cylinders_per >= 1024) {
2550 /* other LLDs do this; implies >= 1GB ram disk ... */
2551 sdebug_heads = 255;
2552 sdebug_sectors_per = 63;
2553 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2554 (sdebug_sectors_per * sdebug_heads);
2555 }
2556
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 fake_storep = vmalloc(sz);
2558 if (NULL == fake_storep) {
2559 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
2560 return -ENOMEM;
2561 }
2562 memset(fake_storep, 0, sz);
2563 if (scsi_debug_num_parts > 0)
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002564 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002566 ret = device_register(&pseudo_primary);
2567 if (ret < 0) {
2568 printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
2569 ret);
2570 goto free_vm;
2571 }
2572 ret = bus_register(&pseudo_lld_bus);
2573 if (ret < 0) {
2574 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
2575 ret);
2576 goto dev_unreg;
2577 }
2578 ret = driver_register(&sdebug_driverfs_driver);
2579 if (ret < 0) {
2580 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
2581 ret);
2582 goto bus_unreg;
2583 }
2584 ret = do_create_driverfs_files();
2585 if (ret < 0) {
2586 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
2587 ret);
2588 goto del_files;
2589 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002591 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 host_to_add = scsi_debug_add_host;
2594 scsi_debug_add_host = 0;
2595
2596 for (k = 0; k < host_to_add; k++) {
2597 if (sdebug_add_adapter()) {
2598 printk(KERN_ERR "scsi_debug_init: "
2599 "sdebug_add_adapter failed k=%d\n", k);
2600 break;
2601 }
2602 }
2603
2604 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
2605 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
2606 scsi_debug_add_host);
2607 }
2608 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002609
2610del_files:
2611 do_remove_driverfs_files();
2612 driver_unregister(&sdebug_driverfs_driver);
2613bus_unreg:
2614 bus_unregister(&pseudo_lld_bus);
2615dev_unreg:
2616 device_unregister(&pseudo_primary);
2617free_vm:
2618 vfree(fake_storep);
2619
2620 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621}
2622
2623static void __exit scsi_debug_exit(void)
2624{
2625 int k = scsi_debug_add_host;
2626
2627 stop_all_queued();
2628 for (; k; k--)
2629 sdebug_remove_adapter();
2630 do_remove_driverfs_files();
2631 driver_unregister(&sdebug_driverfs_driver);
2632 bus_unregister(&pseudo_lld_bus);
2633 device_unregister(&pseudo_primary);
2634
2635 vfree(fake_storep);
2636}
2637
2638device_initcall(scsi_debug_init);
2639module_exit(scsi_debug_exit);
2640
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641static void sdebug_release_adapter(struct device * dev)
2642{
2643 struct sdebug_host_info *sdbg_host;
2644
2645 sdbg_host = to_sdebug_host(dev);
2646 kfree(sdbg_host);
2647}
2648
2649static int sdebug_add_adapter(void)
2650{
2651 int k, devs_per_host;
2652 int error = 0;
2653 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09002654 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002656 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 if (NULL == sdbg_host) {
2658 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002659 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 return -ENOMEM;
2661 }
2662
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
2664
2665 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
2666 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002667 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
2668 if (!sdbg_devinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002670 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 error = -ENOMEM;
2672 goto clean;
2673 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 }
2675
2676 spin_lock(&sdebug_host_list_lock);
2677 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
2678 spin_unlock(&sdebug_host_list_lock);
2679
2680 sdbg_host->dev.bus = &pseudo_lld_bus;
2681 sdbg_host->dev.parent = &pseudo_primary;
2682 sdbg_host->dev.release = &sdebug_release_adapter;
2683 sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host);
2684
2685 error = device_register(&sdbg_host->dev);
2686
2687 if (error)
2688 goto clean;
2689
2690 ++scsi_debug_add_host;
2691 return error;
2692
2693clean:
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09002694 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
2695 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 list_del(&sdbg_devinfo->dev_list);
2697 kfree(sdbg_devinfo);
2698 }
2699
2700 kfree(sdbg_host);
2701 return error;
2702}
2703
2704static void sdebug_remove_adapter(void)
2705{
2706 struct sdebug_host_info * sdbg_host = NULL;
2707
2708 spin_lock(&sdebug_host_list_lock);
2709 if (!list_empty(&sdebug_host_list)) {
2710 sdbg_host = list_entry(sdebug_host_list.prev,
2711 struct sdebug_host_info, host_list);
2712 list_del(&sdbg_host->host_list);
2713 }
2714 spin_unlock(&sdebug_host_list_lock);
2715
2716 if (!sdbg_host)
2717 return;
2718
2719 device_unregister(&sdbg_host->dev);
2720 --scsi_debug_add_host;
2721}
2722
FUJITA Tomonori639db472008-03-20 11:09:19 +09002723static
2724int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
2725{
2726 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
2727 int len, k;
2728 unsigned int num;
2729 unsigned long long lba;
2730 int errsts = 0;
2731 int target = SCpnt->device->id;
2732 struct sdebug_dev_info *devip = NULL;
2733 int inj_recovered = 0;
2734 int inj_transport = 0;
2735 int delay_override = 0;
2736
2737 scsi_set_resid(SCpnt, 0);
2738 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
2739 printk(KERN_INFO "scsi_debug: cmd ");
2740 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
2741 printk("%02x ", (int)cmd[k]);
2742 printk("\n");
2743 }
2744
2745 if (target == SCpnt->device->host->hostt->this_id) {
2746 printk(KERN_INFO "scsi_debug: initiator's id used as "
2747 "target!\n");
2748 return schedule_resp(SCpnt, NULL, done,
2749 DID_NO_CONNECT << 16, 0);
2750 }
2751
2752 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
2753 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
2754 return schedule_resp(SCpnt, NULL, done,
2755 DID_NO_CONNECT << 16, 0);
2756 devip = devInfoReg(SCpnt->device);
2757 if (NULL == devip)
2758 return schedule_resp(SCpnt, NULL, done,
2759 DID_NO_CONNECT << 16, 0);
2760
2761 if ((scsi_debug_every_nth != 0) &&
2762 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
2763 scsi_debug_cmnd_count = 0;
2764 if (scsi_debug_every_nth < -1)
2765 scsi_debug_every_nth = -1;
2766 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
2767 return 0; /* ignore command causing timeout */
2768 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
2769 inj_recovered = 1; /* to reads and writes below */
2770 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
2771 inj_transport = 1; /* to reads and writes below */
2772 }
2773
2774 if (devip->wlun) {
2775 switch (*cmd) {
2776 case INQUIRY:
2777 case REQUEST_SENSE:
2778 case TEST_UNIT_READY:
2779 case REPORT_LUNS:
2780 break; /* only allowable wlun commands */
2781 default:
2782 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2783 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
2784 "not supported for wlun\n", *cmd);
2785 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2786 INVALID_OPCODE, 0);
2787 errsts = check_condition_result;
2788 return schedule_resp(SCpnt, devip, done, errsts,
2789 0);
2790 }
2791 }
2792
2793 switch (*cmd) {
2794 case INQUIRY: /* mandatory, ignore unit attention */
2795 delay_override = 1;
2796 errsts = resp_inquiry(SCpnt, target, devip);
2797 break;
2798 case REQUEST_SENSE: /* mandatory, ignore unit attention */
2799 delay_override = 1;
2800 errsts = resp_requests(SCpnt, devip);
2801 break;
2802 case REZERO_UNIT: /* actually this is REWIND for SSC */
2803 case START_STOP:
2804 errsts = resp_start_stop(SCpnt, devip);
2805 break;
2806 case ALLOW_MEDIUM_REMOVAL:
2807 errsts = check_readiness(SCpnt, 1, devip);
2808 if (errsts)
2809 break;
2810 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2811 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
2812 cmd[4] ? "inhibited" : "enabled");
2813 break;
2814 case SEND_DIAGNOSTIC: /* mandatory */
2815 errsts = check_readiness(SCpnt, 1, devip);
2816 break;
2817 case TEST_UNIT_READY: /* mandatory */
2818 delay_override = 1;
2819 errsts = check_readiness(SCpnt, 0, devip);
2820 break;
2821 case RESERVE:
2822 errsts = check_readiness(SCpnt, 1, devip);
2823 break;
2824 case RESERVE_10:
2825 errsts = check_readiness(SCpnt, 1, devip);
2826 break;
2827 case RELEASE:
2828 errsts = check_readiness(SCpnt, 1, devip);
2829 break;
2830 case RELEASE_10:
2831 errsts = check_readiness(SCpnt, 1, devip);
2832 break;
2833 case READ_CAPACITY:
2834 errsts = resp_readcap(SCpnt, devip);
2835 break;
2836 case SERVICE_ACTION_IN:
2837 if (SAI_READ_CAPACITY_16 != cmd[1]) {
2838 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2839 INVALID_OPCODE, 0);
2840 errsts = check_condition_result;
2841 break;
2842 }
2843 errsts = resp_readcap16(SCpnt, devip);
2844 break;
2845 case MAINTENANCE_IN:
2846 if (MI_REPORT_TARGET_PGS != cmd[1]) {
2847 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2848 INVALID_OPCODE, 0);
2849 errsts = check_condition_result;
2850 break;
2851 }
2852 errsts = resp_report_tgtpgs(SCpnt, devip);
2853 break;
2854 case READ_16:
2855 case READ_12:
2856 case READ_10:
2857 case READ_6:
2858 errsts = check_readiness(SCpnt, 0, devip);
2859 if (errsts)
2860 break;
2861 if (scsi_debug_fake_rw)
2862 break;
2863 get_data_transfer_info(cmd, &lba, &num);
2864 errsts = resp_read(SCpnt, lba, num, devip);
2865 if (inj_recovered && (0 == errsts)) {
2866 mk_sense_buffer(devip, RECOVERED_ERROR,
2867 THRESHOLD_EXCEEDED, 0);
2868 errsts = check_condition_result;
2869 } else if (inj_transport && (0 == errsts)) {
2870 mk_sense_buffer(devip, ABORTED_COMMAND,
2871 TRANSPORT_PROBLEM, ACK_NAK_TO);
2872 errsts = check_condition_result;
2873 }
2874 break;
2875 case REPORT_LUNS: /* mandatory, ignore unit attention */
2876 delay_override = 1;
2877 errsts = resp_report_luns(SCpnt, devip);
2878 break;
2879 case VERIFY: /* 10 byte SBC-2 command */
2880 errsts = check_readiness(SCpnt, 0, devip);
2881 break;
2882 case WRITE_16:
2883 case WRITE_12:
2884 case WRITE_10:
2885 case WRITE_6:
2886 errsts = check_readiness(SCpnt, 0, devip);
2887 if (errsts)
2888 break;
2889 if (scsi_debug_fake_rw)
2890 break;
2891 get_data_transfer_info(cmd, &lba, &num);
2892 errsts = resp_write(SCpnt, lba, num, devip);
2893 if (inj_recovered && (0 == errsts)) {
2894 mk_sense_buffer(devip, RECOVERED_ERROR,
2895 THRESHOLD_EXCEEDED, 0);
2896 errsts = check_condition_result;
2897 }
2898 break;
2899 case MODE_SENSE:
2900 case MODE_SENSE_10:
2901 errsts = resp_mode_sense(SCpnt, target, devip);
2902 break;
2903 case MODE_SELECT:
2904 errsts = resp_mode_select(SCpnt, 1, devip);
2905 break;
2906 case MODE_SELECT_10:
2907 errsts = resp_mode_select(SCpnt, 0, devip);
2908 break;
2909 case LOG_SENSE:
2910 errsts = resp_log_sense(SCpnt, devip);
2911 break;
2912 case SYNCHRONIZE_CACHE:
2913 delay_override = 1;
2914 errsts = check_readiness(SCpnt, 0, devip);
2915 break;
2916 case WRITE_BUFFER:
2917 errsts = check_readiness(SCpnt, 1, devip);
2918 break;
2919 case XDWRITEREAD_10:
2920 if (!scsi_bidi_cmnd(SCpnt)) {
2921 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2922 INVALID_FIELD_IN_CDB, 0);
2923 errsts = check_condition_result;
2924 break;
2925 }
2926
2927 errsts = check_readiness(SCpnt, 0, devip);
2928 if (errsts)
2929 break;
2930 if (scsi_debug_fake_rw)
2931 break;
2932 get_data_transfer_info(cmd, &lba, &num);
2933 errsts = resp_read(SCpnt, lba, num, devip);
2934 if (errsts)
2935 break;
2936 errsts = resp_write(SCpnt, lba, num, devip);
2937 if (errsts)
2938 break;
2939 errsts = resp_xdwriteread(SCpnt, lba, num, devip);
2940 break;
2941 default:
2942 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2943 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
2944 "supported\n", *cmd);
2945 errsts = check_readiness(SCpnt, 1, devip);
2946 if (errsts)
2947 break; /* Unit attention takes precedence */
2948 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
2949 errsts = check_condition_result;
2950 break;
2951 }
2952 return schedule_resp(SCpnt, devip, done, errsts,
2953 (delay_override ? 0 : scsi_debug_delay));
2954}
2955
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09002956static struct scsi_host_template sdebug_driver_template = {
2957 .proc_info = scsi_debug_proc_info,
2958 .proc_name = sdebug_proc_name,
2959 .name = "SCSI DEBUG",
2960 .info = scsi_debug_info,
2961 .slave_alloc = scsi_debug_slave_alloc,
2962 .slave_configure = scsi_debug_slave_configure,
2963 .slave_destroy = scsi_debug_slave_destroy,
2964 .ioctl = scsi_debug_ioctl,
2965 .queuecommand = scsi_debug_queuecommand,
2966 .eh_abort_handler = scsi_debug_abort,
2967 .eh_bus_reset_handler = scsi_debug_bus_reset,
2968 .eh_device_reset_handler = scsi_debug_device_reset,
2969 .eh_host_reset_handler = scsi_debug_host_reset,
2970 .bios_param = scsi_debug_biosparam,
2971 .can_queue = SCSI_DEBUG_CANQUEUE,
2972 .this_id = 7,
2973 .sg_tablesize = 256,
2974 .cmd_per_lun = 16,
2975 .max_sectors = 0xffff,
2976 .use_clustering = DISABLE_CLUSTERING,
2977 .module = THIS_MODULE,
2978};
2979
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980static int sdebug_driver_probe(struct device * dev)
2981{
2982 int error = 0;
2983 struct sdebug_host_info *sdbg_host;
2984 struct Scsi_Host *hpnt;
2985
2986 sdbg_host = to_sdebug_host(dev);
2987
2988 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
2989 if (NULL == hpnt) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002990 printk(KERN_ERR "%s: scsi_register failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991 error = -ENODEV;
2992 return error;
2993 }
2994
2995 sdbg_host->shost = hpnt;
2996 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
2997 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
2998 hpnt->max_id = scsi_debug_num_tgts + 1;
2999 else
3000 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003001 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002
3003 error = scsi_add_host(hpnt, &sdbg_host->dev);
3004 if (error) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003005 printk(KERN_ERR "%s: scsi_add_host failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 error = -ENODEV;
3007 scsi_host_put(hpnt);
3008 } else
3009 scsi_scan_host(hpnt);
3010
3011
3012 return error;
3013}
3014
3015static int sdebug_driver_remove(struct device * dev)
3016{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003018 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019
3020 sdbg_host = to_sdebug_host(dev);
3021
3022 if (!sdbg_host) {
3023 printk(KERN_ERR "%s: Unable to locate host info\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003024 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 return -ENODEV;
3026 }
3027
3028 scsi_remove_host(sdbg_host->shost);
3029
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003030 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
3031 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032 list_del(&sdbg_devinfo->dev_list);
3033 kfree(sdbg_devinfo);
3034 }
3035
3036 scsi_host_put(sdbg_host->shost);
3037 return 0;
3038}
3039
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003040static int pseudo_lld_bus_match(struct device *dev,
3041 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003043 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003045
3046static struct bus_type pseudo_lld_bus = {
3047 .name = "pseudo",
3048 .match = pseudo_lld_bus_match,
3049 .probe = sdebug_driver_probe,
3050 .remove = sdebug_driver_remove,
3051};