blob: 3901125455c9fa6ec281e851676728695c83e073 [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
646
647#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400648#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
650static int resp_inquiry(struct scsi_cmnd * scp, int target,
651 struct sdebug_dev_info * devip)
652{
653 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200654 unsigned char * arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 unsigned char *cmd = (unsigned char *)scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200656 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657
658 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500659 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
660 if (! arr)
661 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400662 if (devip->wlun)
663 pq_pdt = 0x1e; /* present, wlun */
664 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
665 pq_pdt = 0x7f; /* not present, no device type */
666 else
667 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 arr[0] = pq_pdt;
669 if (0x2 & cmd[1]) { /* CMDDT bit set */
670 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
671 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200672 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 return check_condition_result;
674 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200675 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400676 char lu_id_str[6];
677 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200679 port_group_id = (((host_no + 1) & 0x7f) << 8) +
680 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -0400681 if (0 == scsi_debug_vpd_use_hostno)
682 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400683 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
684 (devip->target * 1000) + devip->lun);
685 target_dev_id = ((host_no + 1) * 2000) +
686 (devip->target * 1000) - 3;
687 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400689 arr[1] = cmd[2]; /*sanity */
690 n = 4;
691 arr[n++] = 0x0; /* this page */
692 arr[n++] = 0x80; /* unit serial number */
693 arr[n++] = 0x83; /* device identification */
694 arr[n++] = 0x84; /* software interface ident. */
695 arr[n++] = 0x85; /* management network addresses */
696 arr[n++] = 0x86; /* extended inquiry */
697 arr[n++] = 0x87; /* mode page policy */
698 arr[n++] = 0x88; /* SCSI ports */
699 arr[n++] = 0x89; /* ATA information */
700 arr[n++] = 0xb0; /* Block limits (SBC) */
701 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400703 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400705 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400707 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200708 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
709 target_dev_id, lu_id_num,
710 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400711 } else if (0x84 == cmd[2]) { /* Software interface ident. */
712 arr[1] = cmd[2]; /*sanity */
713 arr[3] = inquiry_evpd_84(&arr[4]);
714 } else if (0x85 == cmd[2]) { /* Management network addresses */
715 arr[1] = cmd[2]; /*sanity */
716 arr[3] = inquiry_evpd_85(&arr[4]);
717 } else if (0x86 == cmd[2]) { /* extended inquiry */
718 arr[1] = cmd[2]; /*sanity */
719 arr[3] = 0x3c; /* number of following entries */
720 arr[4] = 0x0; /* no protection stuff */
721 arr[5] = 0x7; /* head of q, ordered + simple q's */
722 } else if (0x87 == cmd[2]) { /* mode page policy */
723 arr[1] = cmd[2]; /*sanity */
724 arr[3] = 0x8; /* number of following entries */
725 arr[4] = 0x2; /* disconnect-reconnect mp */
726 arr[6] = 0x80; /* mlus, shared */
727 arr[8] = 0x18; /* protocol specific lu */
728 arr[10] = 0x82; /* mlus, per initiator port */
729 } else if (0x88 == cmd[2]) { /* SCSI Ports */
730 arr[1] = cmd[2]; /*sanity */
731 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
732 } else if (0x89 == cmd[2]) { /* ATA information */
733 arr[1] = cmd[2]; /*sanity */
734 n = inquiry_evpd_89(&arr[4]);
735 arr[2] = (n >> 8);
736 arr[3] = (n & 0xff);
737 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
738 arr[1] = cmd[2]; /*sanity */
739 arr[3] = inquiry_evpd_b0(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 } else {
741 /* Illegal request, invalid field in cdb */
742 mk_sense_buffer(devip, ILLEGAL_REQUEST,
743 INVALID_FIELD_IN_CDB, 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200744 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 return check_condition_result;
746 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400747 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200748 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400749 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200750 kfree(arr);
751 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 }
753 /* drops through here for a standard inquiry */
754 arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
755 arr[2] = scsi_debug_scsi_level;
756 arr[3] = 2; /* response_data_format==2 */
757 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200758 if (0 == scsi_debug_vpd_use_hostno)
759 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400760 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400762 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 memcpy(&arr[8], inq_vendor_id, 8);
764 memcpy(&arr[16], inq_product_id, 16);
765 memcpy(&arr[32], inq_product_rev, 4);
766 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400767 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
768 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
769 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400771 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400773 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400775 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200776 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200778 kfree(arr);
779 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780}
781
782static int resp_requests(struct scsi_cmnd * scp,
783 struct sdebug_dev_info * devip)
784{
785 unsigned char * sbuff;
786 unsigned char *cmd = (unsigned char *)scp->cmnd;
787 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400788 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 int len = 18;
790
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400791 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400793 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
794 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400796 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
797 if (want_dsense) {
798 arr[0] = 0x72;
799 arr[1] = 0x0; /* NO_SENSE in sense_key */
800 arr[2] = THRESHOLD_EXCEEDED;
801 arr[3] = 0xff; /* TEST set and MRIE==6 */
802 } else {
803 arr[0] = 0x70;
804 arr[2] = 0x0; /* NO_SENSE in sense_key */
805 arr[7] = 0xa; /* 18 byte sense buffer */
806 arr[12] = THRESHOLD_EXCEEDED;
807 arr[13] = 0xff; /* TEST set and MRIE==6 */
808 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400809 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400811 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
812 /* DESC bit set and sense_buff in fixed format */
813 memset(arr, 0, sizeof(arr));
814 arr[0] = 0x72;
815 arr[1] = sbuff[2]; /* sense key */
816 arr[2] = sbuff[12]; /* asc */
817 arr[3] = sbuff[13]; /* ascq */
818 len = 8;
819 }
820 }
821 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 return fill_from_dev_buffer(scp, arr, len);
823}
824
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400825static int resp_start_stop(struct scsi_cmnd * scp,
826 struct sdebug_dev_info * devip)
827{
828 unsigned char *cmd = (unsigned char *)scp->cmnd;
829 int power_cond, errsts, start;
830
831 if ((errsts = check_readiness(scp, 1, devip)))
832 return errsts;
833 power_cond = (cmd[4] & 0xf0) >> 4;
834 if (power_cond) {
835 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
836 0);
837 return check_condition_result;
838 }
839 start = cmd[4] & 1;
840 if (start == devip->stopped)
841 devip->stopped = !start;
842 return 0;
843}
844
FUJITA Tomonori28898872008-03-30 00:59:55 +0900845static sector_t get_sdebug_capacity(void)
846{
847 if (scsi_debug_virtual_gb > 0)
848 return 2048 * 1024 * scsi_debug_virtual_gb;
849 else
850 return sdebug_store_sectors;
851}
852
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853#define SDEBUG_READCAP_ARR_SZ 8
854static int resp_readcap(struct scsi_cmnd * scp,
855 struct sdebug_dev_info * devip)
856{
857 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400858 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 int errsts;
860
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400861 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400863 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +0900864 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400866 if (sdebug_capacity < 0xffffffff) {
867 capac = (unsigned int)sdebug_capacity - 1;
868 arr[0] = (capac >> 24);
869 arr[1] = (capac >> 16) & 0xff;
870 arr[2] = (capac >> 8) & 0xff;
871 arr[3] = capac & 0xff;
872 } else {
873 arr[0] = 0xff;
874 arr[1] = 0xff;
875 arr[2] = 0xff;
876 arr[3] = 0xff;
877 }
Martin K. Petersen597136a2008-06-05 00:12:59 -0400878 arr[6] = (scsi_debug_sector_size >> 8) & 0xff;
879 arr[7] = scsi_debug_sector_size & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
881}
882
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400883#define SDEBUG_READCAP16_ARR_SZ 32
884static int resp_readcap16(struct scsi_cmnd * scp,
885 struct sdebug_dev_info * devip)
886{
887 unsigned char *cmd = (unsigned char *)scp->cmnd;
888 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
889 unsigned long long capac;
890 int errsts, k, alloc_len;
891
892 if ((errsts = check_readiness(scp, 1, devip)))
893 return errsts;
894 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
895 + cmd[13]);
896 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +0900897 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400898 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
899 capac = sdebug_capacity - 1;
900 for (k = 0; k < 8; ++k, capac >>= 8)
901 arr[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -0400902 arr[8] = (scsi_debug_sector_size >> 24) & 0xff;
903 arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
904 arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
905 arr[11] = scsi_debug_sector_size & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400906 return fill_from_dev_buffer(scp, arr,
907 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
908}
909
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200910#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
911
912static int resp_report_tgtpgs(struct scsi_cmnd * scp,
913 struct sdebug_dev_info * devip)
914{
915 unsigned char *cmd = (unsigned char *)scp->cmnd;
916 unsigned char * arr;
917 int host_no = devip->sdbg_host->shost->host_no;
918 int n, ret, alen, rlen;
919 int port_group_a, port_group_b, port_a, port_b;
920
921 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
922 + cmd[9]);
923
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500924 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
925 if (! arr)
926 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200927 /*
928 * EVPD page 0x88 states we have two ports, one
929 * real and a fake port with no device connected.
930 * So we create two port groups with one port each
931 * and set the group with port B to unavailable.
932 */
933 port_a = 0x1; /* relative port A */
934 port_b = 0x2; /* relative port B */
935 port_group_a = (((host_no + 1) & 0x7f) << 8) +
936 (devip->channel & 0x7f);
937 port_group_b = (((host_no + 1) & 0x7f) << 8) +
938 (devip->channel & 0x7f) + 0x80;
939
940 /*
941 * The asymmetric access state is cycled according to the host_id.
942 */
943 n = 4;
944 if (0 == scsi_debug_vpd_use_hostno) {
945 arr[n++] = host_no % 3; /* Asymm access state */
946 arr[n++] = 0x0F; /* claim: all states are supported */
947 } else {
948 arr[n++] = 0x0; /* Active/Optimized path */
949 arr[n++] = 0x01; /* claim: only support active/optimized paths */
950 }
951 arr[n++] = (port_group_a >> 8) & 0xff;
952 arr[n++] = port_group_a & 0xff;
953 arr[n++] = 0; /* Reserved */
954 arr[n++] = 0; /* Status code */
955 arr[n++] = 0; /* Vendor unique */
956 arr[n++] = 0x1; /* One port per group */
957 arr[n++] = 0; /* Reserved */
958 arr[n++] = 0; /* Reserved */
959 arr[n++] = (port_a >> 8) & 0xff;
960 arr[n++] = port_a & 0xff;
961 arr[n++] = 3; /* Port unavailable */
962 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
963 arr[n++] = (port_group_b >> 8) & 0xff;
964 arr[n++] = port_group_b & 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_b >> 8) & 0xff;
972 arr[n++] = port_b & 0xff;
973
974 rlen = n - 4;
975 arr[0] = (rlen >> 24) & 0xff;
976 arr[1] = (rlen >> 16) & 0xff;
977 arr[2] = (rlen >> 8) & 0xff;
978 arr[3] = rlen & 0xff;
979
980 /*
981 * Return the smallest value of either
982 * - The allocated length
983 * - The constructed command length
984 * - The maximum array size
985 */
986 rlen = min(alen,n);
987 ret = fill_from_dev_buffer(scp, arr,
988 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
989 kfree(arr);
990 return ret;
991}
992
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993/* <<Following mode page info copied from ST318451LW>> */
994
995static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
996{ /* Read-Write Error Recovery page for mode_sense */
997 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
998 5, 0, 0xff, 0xff};
999
1000 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1001 if (1 == pcontrol)
1002 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1003 return sizeof(err_recov_pg);
1004}
1005
1006static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1007{ /* Disconnect-Reconnect page for mode_sense */
1008 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1009 0, 0, 0, 0, 0, 0, 0, 0};
1010
1011 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1012 if (1 == pcontrol)
1013 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1014 return sizeof(disconnect_pg);
1015}
1016
1017static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1018{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001019 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1020 0, 0, 0, 0, 0, 0, 0, 0,
1021 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022
Martin K. Petersen597136a2008-06-05 00:12:59 -04001023 memcpy(p, format_pg, sizeof(format_pg));
1024 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1025 p[11] = sdebug_sectors_per & 0xff;
1026 p[12] = (scsi_debug_sector_size >> 8) & 0xff;
1027 p[13] = scsi_debug_sector_size & 0xff;
1028 if (DEV_REMOVEABLE(target))
1029 p[20] |= 0x20; /* should agree with INQUIRY */
1030 if (1 == pcontrol)
1031 memset(p + 2, 0, sizeof(format_pg) - 2);
1032 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033}
1034
1035static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1036{ /* Caching page for mode_sense */
1037 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1038 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1039
1040 memcpy(p, caching_pg, sizeof(caching_pg));
1041 if (1 == pcontrol)
1042 memset(p + 2, 0, sizeof(caching_pg) - 2);
1043 return sizeof(caching_pg);
1044}
1045
1046static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1047{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001048 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1049 0, 0, 0, 0};
1050 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 0, 0, 0x2, 0x4b};
1052
1053 if (scsi_debug_dsense)
1054 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001055 else
1056 ctrl_m_pg[2] &= ~0x4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1058 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001059 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1060 else if (2 == pcontrol)
1061 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 return sizeof(ctrl_m_pg);
1063}
1064
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001065
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1067{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001068 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1069 0, 0, 0x0, 0x0};
1070 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1071 0, 0, 0x0, 0x0};
1072
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1074 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001075 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1076 else if (2 == pcontrol)
1077 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 return sizeof(iec_m_pg);
1079}
1080
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001081static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1082{ /* SAS SSP mode page - short format for mode_sense */
1083 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1084 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1085
1086 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1087 if (1 == pcontrol)
1088 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1089 return sizeof(sas_sf_m_pg);
1090}
1091
1092
1093static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1094 int target_dev_id)
1095{ /* SAS phy control and discover mode page for mode_sense */
1096 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1097 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1098 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1099 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1100 0x2, 0, 0, 0, 0, 0, 0, 0,
1101 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1102 0, 0, 0, 0, 0, 0, 0, 0,
1103 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1104 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1105 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1106 0x3, 0, 0, 0, 0, 0, 0, 0,
1107 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1108 0, 0, 0, 0, 0, 0, 0, 0,
1109 };
1110 int port_a, port_b;
1111
1112 port_a = target_dev_id + 1;
1113 port_b = port_a + 1;
1114 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1115 p[20] = (port_a >> 24);
1116 p[21] = (port_a >> 16) & 0xff;
1117 p[22] = (port_a >> 8) & 0xff;
1118 p[23] = port_a & 0xff;
1119 p[48 + 20] = (port_b >> 24);
1120 p[48 + 21] = (port_b >> 16) & 0xff;
1121 p[48 + 22] = (port_b >> 8) & 0xff;
1122 p[48 + 23] = port_b & 0xff;
1123 if (1 == pcontrol)
1124 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1125 return sizeof(sas_pcd_m_pg);
1126}
1127
1128static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1129{ /* SAS SSP shared protocol specific port mode subpage */
1130 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1131 0, 0, 0, 0, 0, 0, 0, 0,
1132 };
1133
1134 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1135 if (1 == pcontrol)
1136 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1137 return sizeof(sas_sha_m_pg);
1138}
1139
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140#define SDEBUG_MAX_MSENSE_SZ 256
1141
1142static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1143 struct sdebug_dev_info * devip)
1144{
Douglas Gilbert23183912006-09-16 20:30:47 -04001145 unsigned char dbd, llbaa;
1146 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001148 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 unsigned char * ap;
1150 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1151 unsigned char *cmd = (unsigned char *)scp->cmnd;
1152
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001153 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001155 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 pcontrol = (cmd[2] & 0xc0) >> 6;
1157 pcode = cmd[2] & 0x3f;
1158 subpcode = cmd[3];
1159 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001160 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1161 if ((0 == scsi_debug_ptype) && (0 == dbd))
1162 bd_len = llbaa ? 16 : 8;
1163 else
1164 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1166 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1167 if (0x3 == pcontrol) { /* Saving values not supported */
1168 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1169 0);
1170 return check_condition_result;
1171 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001172 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1173 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001174 /* set DPOFUA bit for disks */
1175 if (0 == scsi_debug_ptype)
1176 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1177 else
1178 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 if (msense_6) {
1180 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001181 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 offset = 4;
1183 } else {
1184 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001185 if (16 == bd_len)
1186 arr[4] = 0x1; /* set LONGLBA bit */
1187 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 offset = 8;
1189 }
1190 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09001191 if ((bd_len > 0) && (!sdebug_capacity))
1192 sdebug_capacity = get_sdebug_capacity();
1193
Douglas Gilbert23183912006-09-16 20:30:47 -04001194 if (8 == bd_len) {
1195 if (sdebug_capacity > 0xfffffffe) {
1196 ap[0] = 0xff;
1197 ap[1] = 0xff;
1198 ap[2] = 0xff;
1199 ap[3] = 0xff;
1200 } else {
1201 ap[0] = (sdebug_capacity >> 24) & 0xff;
1202 ap[1] = (sdebug_capacity >> 16) & 0xff;
1203 ap[2] = (sdebug_capacity >> 8) & 0xff;
1204 ap[3] = sdebug_capacity & 0xff;
1205 }
Martin K. Petersen597136a2008-06-05 00:12:59 -04001206 ap[6] = (scsi_debug_sector_size >> 8) & 0xff;
1207 ap[7] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001208 offset += bd_len;
1209 ap = arr + offset;
1210 } else if (16 == bd_len) {
1211 unsigned long long capac = sdebug_capacity;
1212
1213 for (k = 0; k < 8; ++k, capac >>= 8)
1214 ap[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -04001215 ap[12] = (scsi_debug_sector_size >> 24) & 0xff;
1216 ap[13] = (scsi_debug_sector_size >> 16) & 0xff;
1217 ap[14] = (scsi_debug_sector_size >> 8) & 0xff;
1218 ap[15] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001219 offset += bd_len;
1220 ap = arr + offset;
1221 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001223 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1224 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1226 0);
1227 return check_condition_result;
1228 }
1229 switch (pcode) {
1230 case 0x1: /* Read-Write error recovery page, direct access */
1231 len = resp_err_recov_pg(ap, pcontrol, target);
1232 offset += len;
1233 break;
1234 case 0x2: /* Disconnect-Reconnect page, all devices */
1235 len = resp_disconnect_pg(ap, pcontrol, target);
1236 offset += len;
1237 break;
1238 case 0x3: /* Format device page, direct access */
1239 len = resp_format_pg(ap, pcontrol, target);
1240 offset += len;
1241 break;
1242 case 0x8: /* Caching page, direct access */
1243 len = resp_caching_pg(ap, pcontrol, target);
1244 offset += len;
1245 break;
1246 case 0xa: /* Control Mode page, all devices */
1247 len = resp_ctrl_m_pg(ap, pcontrol, target);
1248 offset += len;
1249 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001250 case 0x19: /* if spc==1 then sas phy, control+discover */
1251 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1252 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1253 INVALID_FIELD_IN_CDB, 0);
1254 return check_condition_result;
1255 }
1256 len = 0;
1257 if ((0x0 == subpcode) || (0xff == subpcode))
1258 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1259 if ((0x1 == subpcode) || (0xff == subpcode))
1260 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1261 target_dev_id);
1262 if ((0x2 == subpcode) || (0xff == subpcode))
1263 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1264 offset += len;
1265 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 case 0x1c: /* Informational Exceptions Mode page, all devices */
1267 len = resp_iec_m_pg(ap, pcontrol, target);
1268 offset += len;
1269 break;
1270 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001271 if ((0 == subpcode) || (0xff == subpcode)) {
1272 len = resp_err_recov_pg(ap, pcontrol, target);
1273 len += resp_disconnect_pg(ap + len, pcontrol, target);
1274 len += resp_format_pg(ap + len, pcontrol, target);
1275 len += resp_caching_pg(ap + len, pcontrol, target);
1276 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1277 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1278 if (0xff == subpcode) {
1279 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1280 target, target_dev_id);
1281 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1282 }
1283 len += resp_iec_m_pg(ap + len, pcontrol, target);
1284 } else {
1285 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1286 INVALID_FIELD_IN_CDB, 0);
1287 return check_condition_result;
1288 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 offset += len;
1290 break;
1291 default:
1292 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1293 0);
1294 return check_condition_result;
1295 }
1296 if (msense_6)
1297 arr[0] = offset - 1;
1298 else {
1299 arr[0] = ((offset - 2) >> 8) & 0xff;
1300 arr[1] = (offset - 2) & 0xff;
1301 }
1302 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1303}
1304
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001305#define SDEBUG_MAX_MSELECT_SZ 512
1306
1307static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1308 struct sdebug_dev_info * devip)
1309{
1310 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1311 int param_len, res, errsts, mpage;
1312 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1313 unsigned char *cmd = (unsigned char *)scp->cmnd;
1314
1315 if ((errsts = check_readiness(scp, 1, devip)))
1316 return errsts;
1317 memset(arr, 0, sizeof(arr));
1318 pf = cmd[1] & 0x10;
1319 sp = cmd[1] & 0x1;
1320 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1321 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1322 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1323 INVALID_FIELD_IN_CDB, 0);
1324 return check_condition_result;
1325 }
1326 res = fetch_to_dev_buffer(scp, arr, param_len);
1327 if (-1 == res)
1328 return (DID_ERROR << 16);
1329 else if ((res < param_len) &&
1330 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1331 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1332 " IO sent=%d bytes\n", param_len, res);
1333 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1334 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001335 if (md_len > 2) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001336 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1337 INVALID_FIELD_IN_PARAM_LIST, 0);
1338 return check_condition_result;
1339 }
1340 off = bd_len + (mselect6 ? 4 : 8);
1341 mpage = arr[off] & 0x3f;
1342 ps = !!(arr[off] & 0x80);
1343 if (ps) {
1344 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1345 INVALID_FIELD_IN_PARAM_LIST, 0);
1346 return check_condition_result;
1347 }
1348 spf = !!(arr[off] & 0x40);
1349 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1350 (arr[off + 1] + 2);
1351 if ((pg_len + off) > param_len) {
1352 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1353 PARAMETER_LIST_LENGTH_ERR, 0);
1354 return check_condition_result;
1355 }
1356 switch (mpage) {
1357 case 0xa: /* Control Mode page */
1358 if (ctrl_m_pg[1] == arr[off + 1]) {
1359 memcpy(ctrl_m_pg + 2, arr + off + 2,
1360 sizeof(ctrl_m_pg) - 2);
1361 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1362 return 0;
1363 }
1364 break;
1365 case 0x1c: /* Informational Exceptions Mode page */
1366 if (iec_m_pg[1] == arr[off + 1]) {
1367 memcpy(iec_m_pg + 2, arr + off + 2,
1368 sizeof(iec_m_pg) - 2);
1369 return 0;
1370 }
1371 break;
1372 default:
1373 break;
1374 }
1375 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1376 INVALID_FIELD_IN_PARAM_LIST, 0);
1377 return check_condition_result;
1378}
1379
1380static int resp_temp_l_pg(unsigned char * arr)
1381{
1382 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1383 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1384 };
1385
1386 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1387 return sizeof(temp_l_pg);
1388}
1389
1390static int resp_ie_l_pg(unsigned char * arr)
1391{
1392 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1393 };
1394
1395 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1396 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1397 arr[4] = THRESHOLD_EXCEEDED;
1398 arr[5] = 0xff;
1399 }
1400 return sizeof(ie_l_pg);
1401}
1402
1403#define SDEBUG_MAX_LSENSE_SZ 512
1404
1405static int resp_log_sense(struct scsi_cmnd * scp,
1406 struct sdebug_dev_info * devip)
1407{
Douglas Gilbert23183912006-09-16 20:30:47 -04001408 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001409 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1410 unsigned char *cmd = (unsigned char *)scp->cmnd;
1411
1412 if ((errsts = check_readiness(scp, 1, devip)))
1413 return errsts;
1414 memset(arr, 0, sizeof(arr));
1415 ppc = cmd[1] & 0x2;
1416 sp = cmd[1] & 0x1;
1417 if (ppc || sp) {
1418 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1419 INVALID_FIELD_IN_CDB, 0);
1420 return check_condition_result;
1421 }
1422 pcontrol = (cmd[2] & 0xc0) >> 6;
1423 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001424 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001425 alloc_len = (cmd[7] << 8) + cmd[8];
1426 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001427 if (0 == subpcode) {
1428 switch (pcode) {
1429 case 0x0: /* Supported log pages log page */
1430 n = 4;
1431 arr[n++] = 0x0; /* this page */
1432 arr[n++] = 0xd; /* Temperature */
1433 arr[n++] = 0x2f; /* Informational exceptions */
1434 arr[3] = n - 4;
1435 break;
1436 case 0xd: /* Temperature log page */
1437 arr[3] = resp_temp_l_pg(arr + 4);
1438 break;
1439 case 0x2f: /* Informational exceptions log page */
1440 arr[3] = resp_ie_l_pg(arr + 4);
1441 break;
1442 default:
1443 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1444 INVALID_FIELD_IN_CDB, 0);
1445 return check_condition_result;
1446 }
1447 } else if (0xff == subpcode) {
1448 arr[0] |= 0x40;
1449 arr[1] = subpcode;
1450 switch (pcode) {
1451 case 0x0: /* Supported log pages and subpages log page */
1452 n = 4;
1453 arr[n++] = 0x0;
1454 arr[n++] = 0x0; /* 0,0 page */
1455 arr[n++] = 0x0;
1456 arr[n++] = 0xff; /* this page */
1457 arr[n++] = 0xd;
1458 arr[n++] = 0x0; /* Temperature */
1459 arr[n++] = 0x2f;
1460 arr[n++] = 0x0; /* Informational exceptions */
1461 arr[3] = n - 4;
1462 break;
1463 case 0xd: /* Temperature subpages */
1464 n = 4;
1465 arr[n++] = 0xd;
1466 arr[n++] = 0x0; /* Temperature */
1467 arr[3] = n - 4;
1468 break;
1469 case 0x2f: /* Informational exceptions subpages */
1470 n = 4;
1471 arr[n++] = 0x2f;
1472 arr[n++] = 0x0; /* Informational exceptions */
1473 arr[3] = n - 4;
1474 break;
1475 default:
1476 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1477 INVALID_FIELD_IN_CDB, 0);
1478 return check_condition_result;
1479 }
1480 } else {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001481 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1482 INVALID_FIELD_IN_CDB, 0);
1483 return check_condition_result;
1484 }
1485 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1486 return fill_from_dev_buffer(scp, arr,
1487 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1488}
1489
FUJITA Tomonori19789102008-03-30 00:59:56 +09001490static int check_device_access_params(struct sdebug_dev_info *devi,
1491 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001493 if (lba + num > sdebug_capacity) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001494 mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 return check_condition_result;
1496 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001497 /* transfer length excessive (tie in to block limits VPD page) */
1498 if (num > sdebug_store_sectors) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001499 mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001500 return check_condition_result;
1501 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09001502 return 0;
1503}
1504
1505static int do_device_access(struct scsi_cmnd *scmd,
1506 struct sdebug_dev_info *devi,
1507 unsigned long long lba, unsigned int num, int write)
1508{
1509 int ret;
1510 unsigned int block, rest = 0;
1511 int (*func)(struct scsi_cmnd *, unsigned char *, int);
1512
1513 func = write ? fetch_to_dev_buffer : fill_from_dev_buffer;
1514
1515 block = do_div(lba, sdebug_store_sectors);
1516 if (block + num > sdebug_store_sectors)
1517 rest = block + num - sdebug_store_sectors;
1518
Martin K. Petersen597136a2008-06-05 00:12:59 -04001519 ret = func(scmd, fake_storep + (block * scsi_debug_sector_size),
1520 (num - rest) * scsi_debug_sector_size);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001521 if (!ret && rest)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001522 ret = func(scmd, fake_storep, rest * scsi_debug_sector_size);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001523
1524 return ret;
1525}
1526
1527static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
1528 unsigned int num, struct sdebug_dev_info *devip)
1529{
1530 unsigned long iflags;
1531 int ret;
1532
1533 ret = check_device_access_params(devip, lba, num);
1534 if (ret)
1535 return ret;
1536
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001538 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1539 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1540 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1542 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001543 /* set info field and valid bit for fixed descriptor */
1544 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1545 devip->sense_buff[0] |= 0x80; /* Valid bit */
1546 ret = OPT_MEDIUM_ERR_ADDR;
1547 devip->sense_buff[3] = (ret >> 24) & 0xff;
1548 devip->sense_buff[4] = (ret >> 16) & 0xff;
1549 devip->sense_buff[5] = (ret >> 8) & 0xff;
1550 devip->sense_buff[6] = ret & 0xff;
1551 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 return check_condition_result;
1553 }
1554 read_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001555 ret = do_device_access(SCpnt, devip, lba, num, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 read_unlock_irqrestore(&atomic_rw, iflags);
1557 return ret;
1558}
1559
FUJITA Tomonori19789102008-03-30 00:59:56 +09001560static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
1561 unsigned int num, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562{
1563 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09001564 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565
FUJITA Tomonori19789102008-03-30 00:59:56 +09001566 ret = check_device_access_params(devip, lba, num);
1567 if (ret)
1568 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569
1570 write_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001571 ret = do_device_access(SCpnt, devip, lba, num, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 write_unlock_irqrestore(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001573 if (-1 == ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 return (DID_ERROR << 16);
Martin K. Petersen597136a2008-06-05 00:12:59 -04001575 else if ((ret < (num * scsi_debug_sector_size)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001577 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Martin K. Petersen597136a2008-06-05 00:12:59 -04001578 " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 return 0;
1580}
1581
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001582#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583
1584static int resp_report_luns(struct scsi_cmnd * scp,
1585 struct sdebug_dev_info * devip)
1586{
1587 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001588 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 unsigned char *cmd = (unsigned char *)scp->cmnd;
1590 int select_report = (int)cmd[2];
1591 struct scsi_lun *one_lun;
1592 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001593 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594
1595 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001596 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1598 0);
1599 return check_condition_result;
1600 }
1601 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
1602 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
1603 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001604 if (1 == select_report)
1605 lun_cnt = 0;
1606 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
1607 --lun_cnt;
1608 wlun = (select_report > 0) ? 1 : 0;
1609 num = lun_cnt + wlun;
1610 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
1611 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
1612 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
1613 sizeof(struct scsi_lun)), num);
1614 if (n < num) {
1615 wlun = 0;
1616 lun_cnt = n;
1617 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001619 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
1620 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
1621 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
1622 i++, lun++) {
1623 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 if (upper)
1625 one_lun[i].scsi_lun[0] =
1626 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001627 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001629 if (wlun) {
1630 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
1631 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
1632 i++;
1633 }
1634 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 return fill_from_dev_buffer(scp, arr,
1636 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
1637}
1638
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001639static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
1640 unsigned int num, struct sdebug_dev_info *devip)
1641{
1642 int i, j, ret = -1;
1643 unsigned char *kaddr, *buf;
1644 unsigned int offset;
1645 struct scatterlist *sg;
1646 struct scsi_data_buffer *sdb = scsi_in(scp);
1647
1648 /* better not to use temporary buffer. */
1649 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
1650 if (!buf)
1651 return ret;
1652
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001653 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001654
1655 offset = 0;
1656 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
1657 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
1658 if (!kaddr)
1659 goto out;
1660
1661 for (j = 0; j < sg->length; j++)
1662 *(kaddr + sg->offset + j) ^= *(buf + offset + j);
1663
1664 offset += sg->length;
1665 kunmap_atomic(kaddr, KM_USER0);
1666 }
1667 ret = 0;
1668out:
1669 kfree(buf);
1670
1671 return ret;
1672}
1673
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674/* When timer goes off this function is called. */
1675static void timer_intr_handler(unsigned long indx)
1676{
1677 struct sdebug_queued_cmd * sqcp;
1678 unsigned long iflags;
1679
1680 if (indx >= SCSI_DEBUG_CANQUEUE) {
1681 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
1682 "large\n");
1683 return;
1684 }
1685 spin_lock_irqsave(&queued_arr_lock, iflags);
1686 sqcp = &queued_arr[(int)indx];
1687 if (! sqcp->in_use) {
1688 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
1689 "interrupt\n");
1690 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1691 return;
1692 }
1693 sqcp->in_use = 0;
1694 if (sqcp->done_funct) {
1695 sqcp->a_cmnd->result = sqcp->scsi_result;
1696 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
1697 }
1698 sqcp->done_funct = NULL;
1699 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1700}
1701
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09001703static struct sdebug_dev_info *
1704sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09001705{
1706 struct sdebug_dev_info *devip;
1707
1708 devip = kzalloc(sizeof(*devip), flags);
1709 if (devip) {
1710 devip->sdbg_host = sdbg_host;
1711 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
1712 }
1713 return devip;
1714}
1715
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
1717{
1718 struct sdebug_host_info * sdbg_host;
1719 struct sdebug_dev_info * open_devip = NULL;
1720 struct sdebug_dev_info * devip =
1721 (struct sdebug_dev_info *)sdev->hostdata;
1722
1723 if (devip)
1724 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09001725 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
1726 if (!sdbg_host) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 printk(KERN_ERR "Host info NULL\n");
1728 return NULL;
1729 }
1730 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
1731 if ((devip->used) && (devip->channel == sdev->channel) &&
1732 (devip->target == sdev->id) &&
1733 (devip->lun == sdev->lun))
1734 return devip;
1735 else {
1736 if ((!devip->used) && (!open_devip))
1737 open_devip = devip;
1738 }
1739 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09001740 if (!open_devip) { /* try and make a new one */
1741 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
1742 if (!open_devip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 printk(KERN_ERR "%s: out of memory at line %d\n",
1744 __FUNCTION__, __LINE__);
1745 return NULL;
1746 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09001748
1749 open_devip->channel = sdev->channel;
1750 open_devip->target = sdev->id;
1751 open_devip->lun = sdev->lun;
1752 open_devip->sdbg_host = sdbg_host;
1753 open_devip->reset = 1;
1754 open_devip->used = 1;
1755 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
1756 if (scsi_debug_dsense)
1757 open_devip->sense_buff[0] = 0x72;
1758 else {
1759 open_devip->sense_buff[0] = 0x70;
1760 open_devip->sense_buff[7] = 0xa;
1761 }
1762 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
1763 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
1764
1765 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766}
1767
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09001768static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09001770 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1771 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
1772 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02001773 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09001774 return 0;
1775}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09001777static int scsi_debug_slave_configure(struct scsi_device *sdp)
1778{
1779 struct sdebug_dev_info *devip;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09001780
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09001782 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
1783 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
1784 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
1785 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
1786 devip = devInfoReg(sdp);
1787 if (NULL == devip)
1788 return 1; /* no resources, will be marked offline */
1789 sdp->hostdata = devip;
1790 if (sdp->host->cmd_per_lun)
1791 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
1792 sdp->host->cmd_per_lun);
1793 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
1794 return 0;
1795}
1796
1797static void scsi_debug_slave_destroy(struct scsi_device *sdp)
1798{
1799 struct sdebug_dev_info *devip =
1800 (struct sdebug_dev_info *)sdp->hostdata;
1801
1802 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1803 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
1804 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
1805 if (devip) {
1806 /* make this slot avaliable for re-use */
1807 devip->used = 0;
1808 sdp->hostdata = NULL;
1809 }
1810}
1811
1812/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
1813static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
1814{
1815 unsigned long iflags;
1816 int k;
1817 struct sdebug_queued_cmd *sqcp;
1818
1819 spin_lock_irqsave(&queued_arr_lock, iflags);
1820 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1821 sqcp = &queued_arr[k];
1822 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
1823 del_timer_sync(&sqcp->cmnd_timer);
1824 sqcp->in_use = 0;
1825 sqcp->a_cmnd = NULL;
1826 break;
1827 }
1828 }
1829 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1830 return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
1831}
1832
1833/* Deletes (stops) timers of all queued commands */
1834static void stop_all_queued(void)
1835{
1836 unsigned long iflags;
1837 int k;
1838 struct sdebug_queued_cmd *sqcp;
1839
1840 spin_lock_irqsave(&queued_arr_lock, iflags);
1841 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1842 sqcp = &queued_arr[k];
1843 if (sqcp->in_use && sqcp->a_cmnd) {
1844 del_timer_sync(&sqcp->cmnd_timer);
1845 sqcp->in_use = 0;
1846 sqcp->a_cmnd = NULL;
1847 }
1848 }
1849 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850}
1851
1852static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
1853{
1854 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1855 printk(KERN_INFO "scsi_debug: abort\n");
1856 ++num_aborts;
1857 stop_queued_cmnd(SCpnt);
1858 return SUCCESS;
1859}
1860
1861static int scsi_debug_biosparam(struct scsi_device *sdev,
1862 struct block_device * bdev, sector_t capacity, int *info)
1863{
1864 int res;
1865 unsigned char *buf;
1866
1867 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1868 printk(KERN_INFO "scsi_debug: biosparam\n");
1869 buf = scsi_bios_ptable(bdev);
1870 if (buf) {
1871 res = scsi_partsize(buf, capacity,
1872 &info[2], &info[0], &info[1]);
1873 kfree(buf);
1874 if (! res)
1875 return res;
1876 }
1877 info[0] = sdebug_heads;
1878 info[1] = sdebug_sectors_per;
1879 info[2] = sdebug_cylinders_per;
1880 return 0;
1881}
1882
1883static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
1884{
1885 struct sdebug_dev_info * devip;
1886
1887 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1888 printk(KERN_INFO "scsi_debug: device_reset\n");
1889 ++num_dev_resets;
1890 if (SCpnt) {
1891 devip = devInfoReg(SCpnt->device);
1892 if (devip)
1893 devip->reset = 1;
1894 }
1895 return SUCCESS;
1896}
1897
1898static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
1899{
1900 struct sdebug_host_info *sdbg_host;
1901 struct sdebug_dev_info * dev_info;
1902 struct scsi_device * sdp;
1903 struct Scsi_Host * hp;
1904
1905 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1906 printk(KERN_INFO "scsi_debug: bus_reset\n");
1907 ++num_bus_resets;
1908 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09001909 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 if (sdbg_host) {
1911 list_for_each_entry(dev_info,
1912 &sdbg_host->dev_info_list,
1913 dev_list)
1914 dev_info->reset = 1;
1915 }
1916 }
1917 return SUCCESS;
1918}
1919
1920static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
1921{
1922 struct sdebug_host_info * sdbg_host;
1923 struct sdebug_dev_info * dev_info;
1924
1925 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1926 printk(KERN_INFO "scsi_debug: host_reset\n");
1927 ++num_host_resets;
1928 spin_lock(&sdebug_host_list_lock);
1929 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
1930 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
1931 dev_list)
1932 dev_info->reset = 1;
1933 }
1934 spin_unlock(&sdebug_host_list_lock);
1935 stop_all_queued();
1936 return SUCCESS;
1937}
1938
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939/* Initializes timers in queued array */
1940static void __init init_all_queued(void)
1941{
1942 unsigned long iflags;
1943 int k;
1944 struct sdebug_queued_cmd * sqcp;
1945
1946 spin_lock_irqsave(&queued_arr_lock, iflags);
1947 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1948 sqcp = &queued_arr[k];
1949 init_timer(&sqcp->cmnd_timer);
1950 sqcp->in_use = 0;
1951 sqcp->a_cmnd = NULL;
1952 }
1953 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1954}
1955
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09001956static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09001957 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958{
1959 struct partition * pp;
1960 int starts[SDEBUG_MAX_PARTS + 2];
1961 int sectors_per_part, num_sectors, k;
1962 int heads_by_sects, start_sec, end_sec;
1963
1964 /* assume partition table already zeroed */
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09001965 if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 return;
1967 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
1968 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
1969 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
1970 "partitions to %d\n", SDEBUG_MAX_PARTS);
1971 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001972 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 sectors_per_part = (num_sectors - sdebug_sectors_per)
1974 / scsi_debug_num_parts;
1975 heads_by_sects = sdebug_heads * sdebug_sectors_per;
1976 starts[0] = sdebug_sectors_per;
1977 for (k = 1; k < scsi_debug_num_parts; ++k)
1978 starts[k] = ((k * sectors_per_part) / heads_by_sects)
1979 * heads_by_sects;
1980 starts[scsi_debug_num_parts] = num_sectors;
1981 starts[scsi_debug_num_parts + 1] = 0;
1982
1983 ramp[510] = 0x55; /* magic partition markings */
1984 ramp[511] = 0xAA;
1985 pp = (struct partition *)(ramp + 0x1be);
1986 for (k = 0; starts[k + 1]; ++k, ++pp) {
1987 start_sec = starts[k];
1988 end_sec = starts[k + 1] - 1;
1989 pp->boot_ind = 0;
1990
1991 pp->cyl = start_sec / heads_by_sects;
1992 pp->head = (start_sec - (pp->cyl * heads_by_sects))
1993 / sdebug_sectors_per;
1994 pp->sector = (start_sec % sdebug_sectors_per) + 1;
1995
1996 pp->end_cyl = end_sec / heads_by_sects;
1997 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
1998 / sdebug_sectors_per;
1999 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2000
2001 pp->start_sect = start_sec;
2002 pp->nr_sects = end_sec - start_sec + 1;
2003 pp->sys_ind = 0x83; /* plain Linux partition */
2004 }
2005}
2006
2007static int schedule_resp(struct scsi_cmnd * cmnd,
2008 struct sdebug_dev_info * devip,
2009 done_funct_t done, int scsi_result, int delta_jiff)
2010{
2011 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2012 if (scsi_result) {
2013 struct scsi_device * sdp = cmnd->device;
2014
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002015 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2016 "non-zero result=0x%x\n", sdp->host->host_no,
2017 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018 }
2019 }
2020 if (cmnd && devip) {
2021 /* simulate autosense by this driver */
2022 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2023 memcpy(cmnd->sense_buffer, devip->sense_buff,
2024 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2025 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2026 }
2027 if (delta_jiff <= 0) {
2028 if (cmnd)
2029 cmnd->result = scsi_result;
2030 if (done)
2031 done(cmnd);
2032 return 0;
2033 } else {
2034 unsigned long iflags;
2035 int k;
2036 struct sdebug_queued_cmd * sqcp = NULL;
2037
2038 spin_lock_irqsave(&queued_arr_lock, iflags);
2039 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2040 sqcp = &queued_arr[k];
2041 if (! sqcp->in_use)
2042 break;
2043 }
2044 if (k >= SCSI_DEBUG_CANQUEUE) {
2045 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2046 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2047 return 1; /* report busy to mid level */
2048 }
2049 sqcp->in_use = 1;
2050 sqcp->a_cmnd = cmnd;
2051 sqcp->scsi_result = scsi_result;
2052 sqcp->done_funct = done;
2053 sqcp->cmnd_timer.function = timer_intr_handler;
2054 sqcp->cmnd_timer.data = k;
2055 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2056 add_timer(&sqcp->cmnd_timer);
2057 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2058 if (cmnd)
2059 cmnd->result = 0;
2060 return 0;
2061 }
2062}
Douglas Gilbert23183912006-09-16 20:30:47 -04002063/* Note: The following macros create attribute files in the
2064 /sys/module/scsi_debug/parameters directory. Unfortunately this
2065 driver is unaware of a change and cannot trigger auxiliary actions
2066 as it can when the corresponding attribute in the
2067 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2068 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002069module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2070module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2071module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2072module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2073module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002074module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002075module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2076module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2077module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2078module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2079module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2080module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2081module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2082module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002083module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2084 S_IRUGO | S_IWUSR);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002085module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086
2087MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2088MODULE_DESCRIPTION("SCSI debug adapter driver");
2089MODULE_LICENSE("GPL");
2090MODULE_VERSION(SCSI_DEBUG_VERSION);
2091
2092MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2093MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002094MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2095MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07002096MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002097MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002098MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2099MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002101MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002102MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2104MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002105MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002106MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Martin K. Petersen597136a2008-06-05 00:12:59 -04002107MODULE_PARM_DESC(sector_size, "hardware sector size in bytes (def=512)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108
2109
2110static char sdebug_info[256];
2111
2112static const char * scsi_debug_info(struct Scsi_Host * shp)
2113{
2114 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2115 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2116 scsi_debug_version_date, scsi_debug_dev_size_mb,
2117 scsi_debug_opts);
2118 return sdebug_info;
2119}
2120
2121/* scsi_debug_proc_info
2122 * Used if the driver currently has no own support for /proc/scsi
2123 */
2124static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2125 int length, int inout)
2126{
2127 int len, pos, begin;
2128 int orig_length;
2129
2130 orig_length = length;
2131
2132 if (inout == 1) {
2133 char arr[16];
2134 int minLen = length > 15 ? 15 : length;
2135
2136 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2137 return -EACCES;
2138 memcpy(arr, buffer, minLen);
2139 arr[minLen] = '\0';
2140 if (1 != sscanf(arr, "%d", &pos))
2141 return -EINVAL;
2142 scsi_debug_opts = pos;
2143 if (scsi_debug_every_nth != 0)
2144 scsi_debug_cmnd_count = 0;
2145 return length;
2146 }
2147 begin = 0;
2148 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2149 "%s [%s]\n"
2150 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2151 "every_nth=%d(curr:%d)\n"
2152 "delay=%d, max_luns=%d, scsi_level=%d\n"
2153 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2154 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
2155 "host_resets=%d\n",
2156 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2157 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2158 scsi_debug_cmnd_count, scsi_debug_delay,
2159 scsi_debug_max_luns, scsi_debug_scsi_level,
Martin K. Petersen597136a2008-06-05 00:12:59 -04002160 scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
2161 sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets,
2162 num_host_resets);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 if (pos < offset) {
2164 len = 0;
2165 begin = pos;
2166 }
2167 *start = buffer + (offset - begin); /* Start of wanted data */
2168 len -= (offset - begin);
2169 if (len > length)
2170 len = length;
2171 return len;
2172}
2173
2174static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2175{
2176 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2177}
2178
2179static ssize_t sdebug_delay_store(struct device_driver * ddp,
2180 const char * buf, size_t count)
2181{
2182 int delay;
2183 char work[20];
2184
2185 if (1 == sscanf(buf, "%10s", work)) {
2186 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2187 scsi_debug_delay = delay;
2188 return count;
2189 }
2190 }
2191 return -EINVAL;
2192}
2193DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2194 sdebug_delay_store);
2195
2196static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2197{
2198 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2199}
2200
2201static ssize_t sdebug_opts_store(struct device_driver * ddp,
2202 const char * buf, size_t count)
2203{
2204 int opts;
2205 char work[20];
2206
2207 if (1 == sscanf(buf, "%10s", work)) {
2208 if (0 == strnicmp(work,"0x", 2)) {
2209 if (1 == sscanf(&work[2], "%x", &opts))
2210 goto opts_done;
2211 } else {
2212 if (1 == sscanf(work, "%d", &opts))
2213 goto opts_done;
2214 }
2215 }
2216 return -EINVAL;
2217opts_done:
2218 scsi_debug_opts = opts;
2219 scsi_debug_cmnd_count = 0;
2220 return count;
2221}
2222DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2223 sdebug_opts_store);
2224
2225static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2226{
2227 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2228}
2229static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2230 const char * buf, size_t count)
2231{
2232 int n;
2233
2234 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2235 scsi_debug_ptype = n;
2236 return count;
2237 }
2238 return -EINVAL;
2239}
2240DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2241
2242static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2243{
2244 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2245}
2246static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2247 const char * buf, size_t count)
2248{
2249 int n;
2250
2251 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2252 scsi_debug_dsense = n;
2253 return count;
2254 }
2255 return -EINVAL;
2256}
2257DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2258 sdebug_dsense_store);
2259
Douglas Gilbert23183912006-09-16 20:30:47 -04002260static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2261{
2262 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2263}
2264static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2265 const char * buf, size_t count)
2266{
2267 int n;
2268
2269 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2270 scsi_debug_fake_rw = n;
2271 return count;
2272 }
2273 return -EINVAL;
2274}
2275DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2276 sdebug_fake_rw_store);
2277
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002278static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2279{
2280 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2281}
2282static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2283 const char * buf, size_t count)
2284{
2285 int n;
2286
2287 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2288 scsi_debug_no_lun_0 = n;
2289 return count;
2290 }
2291 return -EINVAL;
2292}
2293DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2294 sdebug_no_lun_0_store);
2295
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2297{
2298 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2299}
2300static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2301 const char * buf, size_t count)
2302{
2303 int n;
2304
2305 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2306 scsi_debug_num_tgts = n;
2307 sdebug_max_tgts_luns();
2308 return count;
2309 }
2310 return -EINVAL;
2311}
2312DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2313 sdebug_num_tgts_store);
2314
2315static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2316{
2317 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2318}
2319DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2320
2321static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2322{
2323 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2324}
2325DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2326
2327static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2328{
2329 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2330}
2331static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2332 const char * buf, size_t count)
2333{
2334 int nth;
2335
2336 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2337 scsi_debug_every_nth = nth;
2338 scsi_debug_cmnd_count = 0;
2339 return count;
2340 }
2341 return -EINVAL;
2342}
2343DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2344 sdebug_every_nth_store);
2345
2346static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2347{
2348 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2349}
2350static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2351 const char * buf, size_t count)
2352{
2353 int n;
2354
2355 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2356 scsi_debug_max_luns = n;
2357 sdebug_max_tgts_luns();
2358 return count;
2359 }
2360 return -EINVAL;
2361}
2362DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2363 sdebug_max_luns_store);
2364
2365static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
2366{
2367 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
2368}
2369DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
2370
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002371static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2372{
2373 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2374}
2375static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2376 const char * buf, size_t count)
2377{
2378 int n;
2379
2380 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2381 scsi_debug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002382
2383 sdebug_capacity = get_sdebug_capacity();
2384
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002385 return count;
2386 }
2387 return -EINVAL;
2388}
2389DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2390 sdebug_virtual_gb_store);
2391
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
2393{
2394 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
2395}
2396
2397static ssize_t sdebug_add_host_store(struct device_driver * ddp,
2398 const char * buf, size_t count)
2399{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002400 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002402 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 if (delta_hosts > 0) {
2405 do {
2406 sdebug_add_adapter();
2407 } while (--delta_hosts);
2408 } else if (delta_hosts < 0) {
2409 do {
2410 sdebug_remove_adapter();
2411 } while (++delta_hosts);
2412 }
2413 return count;
2414}
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002415DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416 sdebug_add_host_store);
2417
Douglas Gilbert23183912006-09-16 20:30:47 -04002418static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
2419 char * buf)
2420{
2421 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
2422}
2423static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
2424 const char * buf, size_t count)
2425{
2426 int n;
2427
2428 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2429 scsi_debug_vpd_use_hostno = n;
2430 return count;
2431 }
2432 return -EINVAL;
2433}
2434DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
2435 sdebug_vpd_use_hostno_store);
2436
Martin K. Petersen597136a2008-06-05 00:12:59 -04002437static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf)
2438{
2439 return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size);
2440}
2441DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL);
2442
Douglas Gilbert23183912006-09-16 20:30:47 -04002443/* Note: The following function creates attribute files in the
2444 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
2445 files (over those found in the /sys/module/scsi_debug/parameters
2446 directory) is that auxiliary actions can be triggered when an attribute
2447 is changed. For example see: sdebug_add_host_store() above.
2448 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002449static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002451 int ret;
2452
2453 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2454 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
2455 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2456 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2457 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04002458 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002459 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002460 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002461 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002462 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002463 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
2464 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
2465 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04002466 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
2467 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002468 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002469 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470}
2471
2472static void do_remove_driverfs_files(void)
2473{
Martin K. Petersen597136a2008-06-05 00:12:59 -04002474 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
Douglas Gilbert23183912006-09-16 20:30:47 -04002475 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
2476 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
2478 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
2479 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002481 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
2482 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002484 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
2486 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2487 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2488 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
2489 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2490}
2491
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002492static void pseudo_0_release(struct device *dev)
2493{
2494 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2495 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
2496}
2497
2498static struct device pseudo_primary = {
2499 .bus_id = "pseudo_0",
2500 .release = pseudo_0_release,
2501};
2502
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503static int __init scsi_debug_init(void)
2504{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09002505 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 int host_to_add;
2507 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002508 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509
Martin K. Petersen597136a2008-06-05 00:12:59 -04002510 switch (scsi_debug_sector_size) {
2511 case 512:
2512 case 1024:
2513 case 2048:
2514 case 4096:
2515 break;
2516 default:
2517 printk(KERN_ERR "scsi_debug_init: invalid sector_size %u\n",
2518 scsi_debug_sector_size);
2519 return -EINVAL;
2520 }
2521
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 if (scsi_debug_dev_size_mb < 1)
2523 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09002524 sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
Martin K. Petersen597136a2008-06-05 00:12:59 -04002525 sdebug_store_sectors = sz / scsi_debug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002526 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527
2528 /* play around with geometry, don't waste too much on track 0 */
2529 sdebug_heads = 8;
2530 sdebug_sectors_per = 32;
2531 if (scsi_debug_dev_size_mb >= 16)
2532 sdebug_heads = 32;
2533 else if (scsi_debug_dev_size_mb >= 256)
2534 sdebug_heads = 64;
2535 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2536 (sdebug_sectors_per * sdebug_heads);
2537 if (sdebug_cylinders_per >= 1024) {
2538 /* other LLDs do this; implies >= 1GB ram disk ... */
2539 sdebug_heads = 255;
2540 sdebug_sectors_per = 63;
2541 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2542 (sdebug_sectors_per * sdebug_heads);
2543 }
2544
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 fake_storep = vmalloc(sz);
2546 if (NULL == fake_storep) {
2547 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
2548 return -ENOMEM;
2549 }
2550 memset(fake_storep, 0, sz);
2551 if (scsi_debug_num_parts > 0)
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002552 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002554 ret = device_register(&pseudo_primary);
2555 if (ret < 0) {
2556 printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
2557 ret);
2558 goto free_vm;
2559 }
2560 ret = bus_register(&pseudo_lld_bus);
2561 if (ret < 0) {
2562 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
2563 ret);
2564 goto dev_unreg;
2565 }
2566 ret = driver_register(&sdebug_driverfs_driver);
2567 if (ret < 0) {
2568 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
2569 ret);
2570 goto bus_unreg;
2571 }
2572 ret = do_create_driverfs_files();
2573 if (ret < 0) {
2574 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
2575 ret);
2576 goto del_files;
2577 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002579 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 host_to_add = scsi_debug_add_host;
2582 scsi_debug_add_host = 0;
2583
2584 for (k = 0; k < host_to_add; k++) {
2585 if (sdebug_add_adapter()) {
2586 printk(KERN_ERR "scsi_debug_init: "
2587 "sdebug_add_adapter failed k=%d\n", k);
2588 break;
2589 }
2590 }
2591
2592 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
2593 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
2594 scsi_debug_add_host);
2595 }
2596 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002597
2598del_files:
2599 do_remove_driverfs_files();
2600 driver_unregister(&sdebug_driverfs_driver);
2601bus_unreg:
2602 bus_unregister(&pseudo_lld_bus);
2603dev_unreg:
2604 device_unregister(&pseudo_primary);
2605free_vm:
2606 vfree(fake_storep);
2607
2608 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609}
2610
2611static void __exit scsi_debug_exit(void)
2612{
2613 int k = scsi_debug_add_host;
2614
2615 stop_all_queued();
2616 for (; k; k--)
2617 sdebug_remove_adapter();
2618 do_remove_driverfs_files();
2619 driver_unregister(&sdebug_driverfs_driver);
2620 bus_unregister(&pseudo_lld_bus);
2621 device_unregister(&pseudo_primary);
2622
2623 vfree(fake_storep);
2624}
2625
2626device_initcall(scsi_debug_init);
2627module_exit(scsi_debug_exit);
2628
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629static void sdebug_release_adapter(struct device * dev)
2630{
2631 struct sdebug_host_info *sdbg_host;
2632
2633 sdbg_host = to_sdebug_host(dev);
2634 kfree(sdbg_host);
2635}
2636
2637static int sdebug_add_adapter(void)
2638{
2639 int k, devs_per_host;
2640 int error = 0;
2641 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09002642 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002644 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 if (NULL == sdbg_host) {
2646 printk(KERN_ERR "%s: out of memory at line %d\n",
2647 __FUNCTION__, __LINE__);
2648 return -ENOMEM;
2649 }
2650
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
2652
2653 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
2654 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002655 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
2656 if (!sdbg_devinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 printk(KERN_ERR "%s: out of memory at line %d\n",
2658 __FUNCTION__, __LINE__);
2659 error = -ENOMEM;
2660 goto clean;
2661 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 }
2663
2664 spin_lock(&sdebug_host_list_lock);
2665 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
2666 spin_unlock(&sdebug_host_list_lock);
2667
2668 sdbg_host->dev.bus = &pseudo_lld_bus;
2669 sdbg_host->dev.parent = &pseudo_primary;
2670 sdbg_host->dev.release = &sdebug_release_adapter;
2671 sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host);
2672
2673 error = device_register(&sdbg_host->dev);
2674
2675 if (error)
2676 goto clean;
2677
2678 ++scsi_debug_add_host;
2679 return error;
2680
2681clean:
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09002682 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
2683 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 list_del(&sdbg_devinfo->dev_list);
2685 kfree(sdbg_devinfo);
2686 }
2687
2688 kfree(sdbg_host);
2689 return error;
2690}
2691
2692static void sdebug_remove_adapter(void)
2693{
2694 struct sdebug_host_info * sdbg_host = NULL;
2695
2696 spin_lock(&sdebug_host_list_lock);
2697 if (!list_empty(&sdebug_host_list)) {
2698 sdbg_host = list_entry(sdebug_host_list.prev,
2699 struct sdebug_host_info, host_list);
2700 list_del(&sdbg_host->host_list);
2701 }
2702 spin_unlock(&sdebug_host_list_lock);
2703
2704 if (!sdbg_host)
2705 return;
2706
2707 device_unregister(&sdbg_host->dev);
2708 --scsi_debug_add_host;
2709}
2710
FUJITA Tomonori639db472008-03-20 11:09:19 +09002711static
2712int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
2713{
2714 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
2715 int len, k;
2716 unsigned int num;
2717 unsigned long long lba;
2718 int errsts = 0;
2719 int target = SCpnt->device->id;
2720 struct sdebug_dev_info *devip = NULL;
2721 int inj_recovered = 0;
2722 int inj_transport = 0;
2723 int delay_override = 0;
2724
2725 scsi_set_resid(SCpnt, 0);
2726 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
2727 printk(KERN_INFO "scsi_debug: cmd ");
2728 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
2729 printk("%02x ", (int)cmd[k]);
2730 printk("\n");
2731 }
2732
2733 if (target == SCpnt->device->host->hostt->this_id) {
2734 printk(KERN_INFO "scsi_debug: initiator's id used as "
2735 "target!\n");
2736 return schedule_resp(SCpnt, NULL, done,
2737 DID_NO_CONNECT << 16, 0);
2738 }
2739
2740 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
2741 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
2742 return schedule_resp(SCpnt, NULL, done,
2743 DID_NO_CONNECT << 16, 0);
2744 devip = devInfoReg(SCpnt->device);
2745 if (NULL == devip)
2746 return schedule_resp(SCpnt, NULL, done,
2747 DID_NO_CONNECT << 16, 0);
2748
2749 if ((scsi_debug_every_nth != 0) &&
2750 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
2751 scsi_debug_cmnd_count = 0;
2752 if (scsi_debug_every_nth < -1)
2753 scsi_debug_every_nth = -1;
2754 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
2755 return 0; /* ignore command causing timeout */
2756 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
2757 inj_recovered = 1; /* to reads and writes below */
2758 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
2759 inj_transport = 1; /* to reads and writes below */
2760 }
2761
2762 if (devip->wlun) {
2763 switch (*cmd) {
2764 case INQUIRY:
2765 case REQUEST_SENSE:
2766 case TEST_UNIT_READY:
2767 case REPORT_LUNS:
2768 break; /* only allowable wlun commands */
2769 default:
2770 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2771 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
2772 "not supported for wlun\n", *cmd);
2773 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2774 INVALID_OPCODE, 0);
2775 errsts = check_condition_result;
2776 return schedule_resp(SCpnt, devip, done, errsts,
2777 0);
2778 }
2779 }
2780
2781 switch (*cmd) {
2782 case INQUIRY: /* mandatory, ignore unit attention */
2783 delay_override = 1;
2784 errsts = resp_inquiry(SCpnt, target, devip);
2785 break;
2786 case REQUEST_SENSE: /* mandatory, ignore unit attention */
2787 delay_override = 1;
2788 errsts = resp_requests(SCpnt, devip);
2789 break;
2790 case REZERO_UNIT: /* actually this is REWIND for SSC */
2791 case START_STOP:
2792 errsts = resp_start_stop(SCpnt, devip);
2793 break;
2794 case ALLOW_MEDIUM_REMOVAL:
2795 errsts = check_readiness(SCpnt, 1, devip);
2796 if (errsts)
2797 break;
2798 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2799 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
2800 cmd[4] ? "inhibited" : "enabled");
2801 break;
2802 case SEND_DIAGNOSTIC: /* mandatory */
2803 errsts = check_readiness(SCpnt, 1, devip);
2804 break;
2805 case TEST_UNIT_READY: /* mandatory */
2806 delay_override = 1;
2807 errsts = check_readiness(SCpnt, 0, devip);
2808 break;
2809 case RESERVE:
2810 errsts = check_readiness(SCpnt, 1, devip);
2811 break;
2812 case RESERVE_10:
2813 errsts = check_readiness(SCpnt, 1, devip);
2814 break;
2815 case RELEASE:
2816 errsts = check_readiness(SCpnt, 1, devip);
2817 break;
2818 case RELEASE_10:
2819 errsts = check_readiness(SCpnt, 1, devip);
2820 break;
2821 case READ_CAPACITY:
2822 errsts = resp_readcap(SCpnt, devip);
2823 break;
2824 case SERVICE_ACTION_IN:
2825 if (SAI_READ_CAPACITY_16 != cmd[1]) {
2826 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2827 INVALID_OPCODE, 0);
2828 errsts = check_condition_result;
2829 break;
2830 }
2831 errsts = resp_readcap16(SCpnt, devip);
2832 break;
2833 case MAINTENANCE_IN:
2834 if (MI_REPORT_TARGET_PGS != cmd[1]) {
2835 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2836 INVALID_OPCODE, 0);
2837 errsts = check_condition_result;
2838 break;
2839 }
2840 errsts = resp_report_tgtpgs(SCpnt, devip);
2841 break;
2842 case READ_16:
2843 case READ_12:
2844 case READ_10:
2845 case READ_6:
2846 errsts = check_readiness(SCpnt, 0, devip);
2847 if (errsts)
2848 break;
2849 if (scsi_debug_fake_rw)
2850 break;
2851 get_data_transfer_info(cmd, &lba, &num);
2852 errsts = resp_read(SCpnt, lba, num, devip);
2853 if (inj_recovered && (0 == errsts)) {
2854 mk_sense_buffer(devip, RECOVERED_ERROR,
2855 THRESHOLD_EXCEEDED, 0);
2856 errsts = check_condition_result;
2857 } else if (inj_transport && (0 == errsts)) {
2858 mk_sense_buffer(devip, ABORTED_COMMAND,
2859 TRANSPORT_PROBLEM, ACK_NAK_TO);
2860 errsts = check_condition_result;
2861 }
2862 break;
2863 case REPORT_LUNS: /* mandatory, ignore unit attention */
2864 delay_override = 1;
2865 errsts = resp_report_luns(SCpnt, devip);
2866 break;
2867 case VERIFY: /* 10 byte SBC-2 command */
2868 errsts = check_readiness(SCpnt, 0, devip);
2869 break;
2870 case WRITE_16:
2871 case WRITE_12:
2872 case WRITE_10:
2873 case WRITE_6:
2874 errsts = check_readiness(SCpnt, 0, devip);
2875 if (errsts)
2876 break;
2877 if (scsi_debug_fake_rw)
2878 break;
2879 get_data_transfer_info(cmd, &lba, &num);
2880 errsts = resp_write(SCpnt, lba, num, devip);
2881 if (inj_recovered && (0 == errsts)) {
2882 mk_sense_buffer(devip, RECOVERED_ERROR,
2883 THRESHOLD_EXCEEDED, 0);
2884 errsts = check_condition_result;
2885 }
2886 break;
2887 case MODE_SENSE:
2888 case MODE_SENSE_10:
2889 errsts = resp_mode_sense(SCpnt, target, devip);
2890 break;
2891 case MODE_SELECT:
2892 errsts = resp_mode_select(SCpnt, 1, devip);
2893 break;
2894 case MODE_SELECT_10:
2895 errsts = resp_mode_select(SCpnt, 0, devip);
2896 break;
2897 case LOG_SENSE:
2898 errsts = resp_log_sense(SCpnt, devip);
2899 break;
2900 case SYNCHRONIZE_CACHE:
2901 delay_override = 1;
2902 errsts = check_readiness(SCpnt, 0, devip);
2903 break;
2904 case WRITE_BUFFER:
2905 errsts = check_readiness(SCpnt, 1, devip);
2906 break;
2907 case XDWRITEREAD_10:
2908 if (!scsi_bidi_cmnd(SCpnt)) {
2909 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2910 INVALID_FIELD_IN_CDB, 0);
2911 errsts = check_condition_result;
2912 break;
2913 }
2914
2915 errsts = check_readiness(SCpnt, 0, devip);
2916 if (errsts)
2917 break;
2918 if (scsi_debug_fake_rw)
2919 break;
2920 get_data_transfer_info(cmd, &lba, &num);
2921 errsts = resp_read(SCpnt, lba, num, devip);
2922 if (errsts)
2923 break;
2924 errsts = resp_write(SCpnt, lba, num, devip);
2925 if (errsts)
2926 break;
2927 errsts = resp_xdwriteread(SCpnt, lba, num, devip);
2928 break;
2929 default:
2930 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2931 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
2932 "supported\n", *cmd);
2933 errsts = check_readiness(SCpnt, 1, devip);
2934 if (errsts)
2935 break; /* Unit attention takes precedence */
2936 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
2937 errsts = check_condition_result;
2938 break;
2939 }
2940 return schedule_resp(SCpnt, devip, done, errsts,
2941 (delay_override ? 0 : scsi_debug_delay));
2942}
2943
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09002944static struct scsi_host_template sdebug_driver_template = {
2945 .proc_info = scsi_debug_proc_info,
2946 .proc_name = sdebug_proc_name,
2947 .name = "SCSI DEBUG",
2948 .info = scsi_debug_info,
2949 .slave_alloc = scsi_debug_slave_alloc,
2950 .slave_configure = scsi_debug_slave_configure,
2951 .slave_destroy = scsi_debug_slave_destroy,
2952 .ioctl = scsi_debug_ioctl,
2953 .queuecommand = scsi_debug_queuecommand,
2954 .eh_abort_handler = scsi_debug_abort,
2955 .eh_bus_reset_handler = scsi_debug_bus_reset,
2956 .eh_device_reset_handler = scsi_debug_device_reset,
2957 .eh_host_reset_handler = scsi_debug_host_reset,
2958 .bios_param = scsi_debug_biosparam,
2959 .can_queue = SCSI_DEBUG_CANQUEUE,
2960 .this_id = 7,
2961 .sg_tablesize = 256,
2962 .cmd_per_lun = 16,
2963 .max_sectors = 0xffff,
2964 .use_clustering = DISABLE_CLUSTERING,
2965 .module = THIS_MODULE,
2966};
2967
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968static int sdebug_driver_probe(struct device * dev)
2969{
2970 int error = 0;
2971 struct sdebug_host_info *sdbg_host;
2972 struct Scsi_Host *hpnt;
2973
2974 sdbg_host = to_sdebug_host(dev);
2975
2976 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
2977 if (NULL == hpnt) {
2978 printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__);
2979 error = -ENODEV;
2980 return error;
2981 }
2982
2983 sdbg_host->shost = hpnt;
2984 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
2985 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
2986 hpnt->max_id = scsi_debug_num_tgts + 1;
2987 else
2988 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002989 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990
2991 error = scsi_add_host(hpnt, &sdbg_host->dev);
2992 if (error) {
2993 printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
2994 error = -ENODEV;
2995 scsi_host_put(hpnt);
2996 } else
2997 scsi_scan_host(hpnt);
2998
2999
3000 return error;
3001}
3002
3003static int sdebug_driver_remove(struct device * dev)
3004{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003006 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007
3008 sdbg_host = to_sdebug_host(dev);
3009
3010 if (!sdbg_host) {
3011 printk(KERN_ERR "%s: Unable to locate host info\n",
3012 __FUNCTION__);
3013 return -ENODEV;
3014 }
3015
3016 scsi_remove_host(sdbg_host->shost);
3017
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003018 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
3019 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 list_del(&sdbg_devinfo->dev_list);
3021 kfree(sdbg_devinfo);
3022 }
3023
3024 scsi_host_put(sdbg_host->shost);
3025 return 0;
3026}
3027
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003028static int pseudo_lld_bus_match(struct device *dev,
3029 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003031 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003033
3034static struct bus_type pseudo_lld_bus = {
3035 .name = "pseudo",
3036 .match = pseudo_lld_bus_match,
3037 .probe = sdebug_driver_probe,
3038 .remove = sdebug_driver_remove,
3039};