blob: 65c88dde72b40063e79ddaac47f5e9fa38051984 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
98/* bit mask values for scsi_debug_opts */
99#define SCSI_DEBUG_OPT_NOISE 1
100#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
101#define SCSI_DEBUG_OPT_TIMEOUT 4
102#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500103#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104/* When "every_nth" > 0 then modulo "every_nth" commands:
105 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
106 * - a RECOVERED_ERROR is simulated on successful read and write
107 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500108 * - a TRANSPORT_ERROR is simulated on successful read and write
109 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 *
111 * When "every_nth" < 0 then after "- every_nth" commands:
112 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
113 * - a RECOVERED_ERROR is simulated on successful read and write
114 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500115 * - a TRANSPORT_ERROR is simulated on successful read and write
116 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 * This will continue until some other action occurs (e.g. the user
118 * writing a new value (other than -1 or 1) to every_nth via sysfs).
119 */
120
121/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
122 * sector on read commands: */
123#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
124
125/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
126 * or "peripheral device" addressing (value 0) */
127#define SAM2_LUN_ADDRESS_METHOD 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400128#define SAM2_WLUN_REPORT_LUNS 0xc101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
130static int scsi_debug_add_host = DEF_NUM_HOST;
131static int scsi_debug_delay = DEF_DELAY;
132static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
133static int scsi_debug_every_nth = DEF_EVERY_NTH;
134static int scsi_debug_max_luns = DEF_MAX_LUNS;
135static int scsi_debug_num_parts = DEF_NUM_PARTS;
136static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
137static int scsi_debug_opts = DEF_OPTS;
138static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
139static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
140static int scsi_debug_dsense = DEF_D_SENSE;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400141static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
142static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
Douglas Gilbert23183912006-09-16 20:30:47 -0400143static int scsi_debug_fake_rw = DEF_FAKE_RW;
144static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
146static int scsi_debug_cmnd_count = 0;
147
148#define DEV_READONLY(TGT) (0)
149#define DEV_REMOVEABLE(TGT) (0)
150
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400151static unsigned int sdebug_store_size; /* in bytes */
152static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153static sector_t sdebug_capacity; /* in sectors */
154
155/* old BIOS stuff, kernel may get rid of them but some mode sense pages
156 may still need them */
157static int sdebug_heads; /* heads per disk */
158static int sdebug_cylinders_per; /* cylinders per surface */
159static int sdebug_sectors_per; /* sectors per cylinder */
160
161/* default sector size is 512 bytes, 2**9 bytes */
162#define POW2_SECT_SIZE 9
163#define SECT_SIZE (1 << POW2_SECT_SIZE)
164#define SECT_SIZE_PER(TGT) SECT_SIZE
165
166#define SDEBUG_MAX_PARTS 4
167
168#define SDEBUG_SENSE_LEN 32
169
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +0900170#define SCSI_DEBUG_CANQUEUE 255
171#define SCSI_DEBUG_MAX_CMD_LEN 16
172
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173struct sdebug_dev_info {
174 struct list_head dev_list;
175 unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */
176 unsigned int channel;
177 unsigned int target;
178 unsigned int lun;
179 struct sdebug_host_info *sdbg_host;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400180 unsigned int wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 char reset;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400182 char stopped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 char used;
184};
185
186struct sdebug_host_info {
187 struct list_head host_list;
188 struct Scsi_Host *shost;
189 struct device dev;
190 struct list_head dev_info_list;
191};
192
193#define to_sdebug_host(d) \
194 container_of(d, struct sdebug_host_info, dev)
195
196static LIST_HEAD(sdebug_host_list);
197static DEFINE_SPINLOCK(sdebug_host_list_lock);
198
199typedef void (* done_funct_t) (struct scsi_cmnd *);
200
201struct sdebug_queued_cmd {
202 int in_use;
203 struct timer_list cmnd_timer;
204 done_funct_t done_funct;
205 struct scsi_cmnd * a_cmnd;
206 int scsi_result;
207};
208static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
209
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210static unsigned char * fake_storep; /* ramdisk storage */
211
212static int num_aborts = 0;
213static int num_dev_resets = 0;
214static int num_bus_resets = 0;
215static int num_host_resets = 0;
216
217static DEFINE_SPINLOCK(queued_arr_lock);
218static DEFINE_RWLOCK(atomic_rw);
219
220static char sdebug_proc_name[] = "scsi_debug";
221
222static int sdebug_driver_probe(struct device *);
223static int sdebug_driver_remove(struct device *);
224static struct bus_type pseudo_lld_bus;
225
226static struct device_driver sdebug_driverfs_driver = {
227 .name = sdebug_proc_name,
228 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229};
230
231static const int check_condition_result =
232 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
233
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400234static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
235 0, 0, 0x2, 0x4b};
236static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
237 0, 0, 0x0, 0x0};
238
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev);
240static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
241 int asc, int asq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242static void stop_all_queued(void);
243static int stop_queued_cmnd(struct scsi_cmnd * cmnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
245static int sdebug_add_adapter(void);
246static void sdebug_remove_adapter(void);
247static void sdebug_max_tgts_luns(void);
248
249static struct device pseudo_primary;
250static struct bus_type pseudo_lld_bus;
251
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900252static void get_data_transfer_info(unsigned char *cmd,
253 unsigned long long *lba, unsigned int *num)
254{
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900255 switch (*cmd) {
256 case WRITE_16:
257 case READ_16:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900258 *lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
259 (u64)cmd[7] << 16 | (u64)cmd[6] << 24 |
260 (u64)cmd[5] << 32 | (u64)cmd[4] << 40 |
261 (u64)cmd[3] << 48 | (u64)cmd[2] << 56;
262
263 *num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 |
264 (u32)cmd[10] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900265 break;
266 case WRITE_12:
267 case READ_12:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900268 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
269 (u32)cmd[2] << 24;
270
271 *num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |
272 (u32)cmd[6] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900273 break;
274 case WRITE_10:
275 case READ_10:
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900276 case XDWRITEREAD_10:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900277 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
278 (u32)cmd[2] << 24;
279
280 *num = (u32)cmd[8] | (u32)cmd[7] << 8;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900281 break;
282 case WRITE_6:
283 case READ_6:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900284 *lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
285 (u32)(cmd[1] & 0x1f) << 16;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900286 *num = (0 == cmd[4]) ? 256 : cmd[4];
287 break;
288 default:
289 break;
290 }
291}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
294{
295 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
296 printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
297 }
298 return -EINVAL;
299 /* return -ENOTTY; // correct return but upsets fdisk */
300}
301
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400302static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
303 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304{
305 if (devip->reset) {
306 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
307 printk(KERN_INFO "scsi_debug: Reporting Unit "
308 "attention: power on reset\n");
309 devip->reset = 0;
310 mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
311 return check_condition_result;
312 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400313 if ((0 == reset_only) && devip->stopped) {
314 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
315 printk(KERN_INFO "scsi_debug: Reporting Not "
316 "ready: initializing command required\n");
317 mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
318 0x2);
319 return check_condition_result;
320 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 return 0;
322}
323
324/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900325static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 int arr_len)
327{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900328 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900329 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900331 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900333 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 return (DID_ERROR << 16);
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900335
336 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
337 arr, arr_len);
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900338 if (sdb->resid)
339 sdb->resid -= act_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400340 else
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900341 sdb->resid = scsi_bufflen(scp) - act_len;
342
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 return 0;
344}
345
346/* Returns number of bytes fetched into 'arr' or -1 if error. */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900347static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
348 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900350 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900352 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900354
355 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356}
357
358
359static const char * inq_vendor_id = "Linux ";
360static const char * inq_product_id = "scsi_debug ";
361static const char * inq_product_rev = "0004";
362
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200363static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
364 int target_dev_id, int dev_id_num,
365 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400366 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400368 int num, port_a;
369 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400371 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 /* T10 vendor identifier field format (faked) */
373 arr[0] = 0x2; /* ASCII */
374 arr[1] = 0x1;
375 arr[2] = 0x0;
376 memcpy(&arr[4], inq_vendor_id, 8);
377 memcpy(&arr[12], inq_product_id, 16);
378 memcpy(&arr[28], dev_id_str, dev_id_str_len);
379 num = 8 + 16 + dev_id_str_len;
380 arr[3] = num;
381 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400382 if (dev_id_num >= 0) {
383 /* NAA-5, Logical unit identifier (binary) */
384 arr[num++] = 0x1; /* binary (not necessarily sas) */
385 arr[num++] = 0x3; /* PIV=0, lu, naa */
386 arr[num++] = 0x0;
387 arr[num++] = 0x8;
388 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
389 arr[num++] = 0x33;
390 arr[num++] = 0x33;
391 arr[num++] = 0x30;
392 arr[num++] = (dev_id_num >> 24);
393 arr[num++] = (dev_id_num >> 16) & 0xff;
394 arr[num++] = (dev_id_num >> 8) & 0xff;
395 arr[num++] = dev_id_num & 0xff;
396 /* Target relative port number */
397 arr[num++] = 0x61; /* proto=sas, binary */
398 arr[num++] = 0x94; /* PIV=1, target port, rel port */
399 arr[num++] = 0x0; /* reserved */
400 arr[num++] = 0x4; /* length */
401 arr[num++] = 0x0; /* reserved */
402 arr[num++] = 0x0; /* reserved */
403 arr[num++] = 0x0;
404 arr[num++] = 0x1; /* relative port A */
405 }
406 /* NAA-5, Target port identifier */
407 arr[num++] = 0x61; /* proto=sas, binary */
408 arr[num++] = 0x93; /* piv=1, target port, naa */
409 arr[num++] = 0x0;
410 arr[num++] = 0x8;
411 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
412 arr[num++] = 0x22;
413 arr[num++] = 0x22;
414 arr[num++] = 0x20;
415 arr[num++] = (port_a >> 24);
416 arr[num++] = (port_a >> 16) & 0xff;
417 arr[num++] = (port_a >> 8) & 0xff;
418 arr[num++] = port_a & 0xff;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200419 /* NAA-5, Target port group identifier */
420 arr[num++] = 0x61; /* proto=sas, binary */
421 arr[num++] = 0x95; /* piv=1, target port group id */
422 arr[num++] = 0x0;
423 arr[num++] = 0x4;
424 arr[num++] = 0;
425 arr[num++] = 0;
426 arr[num++] = (port_group_id >> 8) & 0xff;
427 arr[num++] = port_group_id & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400428 /* NAA-5, Target device identifier */
429 arr[num++] = 0x61; /* proto=sas, binary */
430 arr[num++] = 0xa3; /* piv=1, target device, naa */
431 arr[num++] = 0x0;
432 arr[num++] = 0x8;
433 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
434 arr[num++] = 0x22;
435 arr[num++] = 0x22;
436 arr[num++] = 0x20;
437 arr[num++] = (target_dev_id >> 24);
438 arr[num++] = (target_dev_id >> 16) & 0xff;
439 arr[num++] = (target_dev_id >> 8) & 0xff;
440 arr[num++] = target_dev_id & 0xff;
441 /* SCSI name string: Target device identifier */
442 arr[num++] = 0x63; /* proto=sas, UTF-8 */
443 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
444 arr[num++] = 0x0;
445 arr[num++] = 24;
446 memcpy(arr + num, "naa.52222220", 12);
447 num += 12;
448 snprintf(b, sizeof(b), "%08X", target_dev_id);
449 memcpy(arr + num, b, 8);
450 num += 8;
451 memset(arr + num, 0, 4);
452 num += 4;
453 return num;
454}
455
456
457static unsigned char vpd84_data[] = {
458/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
459 0x22,0x22,0x22,0x0,0xbb,0x1,
460 0x22,0x22,0x22,0x0,0xbb,0x2,
461};
462
463static int inquiry_evpd_84(unsigned char * arr)
464{
465 memcpy(arr, vpd84_data, sizeof(vpd84_data));
466 return sizeof(vpd84_data);
467}
468
469static int inquiry_evpd_85(unsigned char * arr)
470{
471 int num = 0;
472 const char * na1 = "https://www.kernel.org/config";
473 const char * na2 = "http://www.kernel.org/log";
474 int plen, olen;
475
476 arr[num++] = 0x1; /* lu, storage config */
477 arr[num++] = 0x0; /* reserved */
478 arr[num++] = 0x0;
479 olen = strlen(na1);
480 plen = olen + 1;
481 if (plen % 4)
482 plen = ((plen / 4) + 1) * 4;
483 arr[num++] = plen; /* length, null termianted, padded */
484 memcpy(arr + num, na1, olen);
485 memset(arr + num + olen, 0, plen - olen);
486 num += plen;
487
488 arr[num++] = 0x4; /* lu, logging */
489 arr[num++] = 0x0; /* reserved */
490 arr[num++] = 0x0;
491 olen = strlen(na2);
492 plen = olen + 1;
493 if (plen % 4)
494 plen = ((plen / 4) + 1) * 4;
495 arr[num++] = plen; /* length, null terminated, padded */
496 memcpy(arr + num, na2, olen);
497 memset(arr + num + olen, 0, plen - olen);
498 num += plen;
499
500 return num;
501}
502
503/* SCSI ports VPD page */
504static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
505{
506 int num = 0;
507 int port_a, port_b;
508
509 port_a = target_dev_id + 1;
510 port_b = port_a + 1;
511 arr[num++] = 0x0; /* reserved */
512 arr[num++] = 0x0; /* reserved */
513 arr[num++] = 0x0;
514 arr[num++] = 0x1; /* relative port 1 (primary) */
515 memset(arr + num, 0, 6);
516 num += 6;
517 arr[num++] = 0x0;
518 arr[num++] = 12; /* length tp descriptor */
519 /* naa-5 target port identifier (A) */
520 arr[num++] = 0x61; /* proto=sas, binary */
521 arr[num++] = 0x93; /* PIV=1, target port, NAA */
522 arr[num++] = 0x0; /* reserved */
523 arr[num++] = 0x8; /* length */
524 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
525 arr[num++] = 0x22;
526 arr[num++] = 0x22;
527 arr[num++] = 0x20;
528 arr[num++] = (port_a >> 24);
529 arr[num++] = (port_a >> 16) & 0xff;
530 arr[num++] = (port_a >> 8) & 0xff;
531 arr[num++] = port_a & 0xff;
532
533 arr[num++] = 0x0; /* reserved */
534 arr[num++] = 0x0; /* reserved */
535 arr[num++] = 0x0;
536 arr[num++] = 0x2; /* relative port 2 (secondary) */
537 memset(arr + num, 0, 6);
538 num += 6;
539 arr[num++] = 0x0;
540 arr[num++] = 12; /* length tp descriptor */
541 /* naa-5 target port identifier (B) */
542 arr[num++] = 0x61; /* proto=sas, binary */
543 arr[num++] = 0x93; /* PIV=1, target port, NAA */
544 arr[num++] = 0x0; /* reserved */
545 arr[num++] = 0x8; /* length */
546 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
547 arr[num++] = 0x22;
548 arr[num++] = 0x22;
549 arr[num++] = 0x20;
550 arr[num++] = (port_b >> 24);
551 arr[num++] = (port_b >> 16) & 0xff;
552 arr[num++] = (port_b >> 8) & 0xff;
553 arr[num++] = port_b & 0xff;
554
555 return num;
556}
557
558
559static unsigned char vpd89_data[] = {
560/* from 4th byte */ 0,0,0,0,
561'l','i','n','u','x',' ',' ',' ',
562'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
563'1','2','3','4',
5640x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
5650xec,0,0,0,
5660x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
5670,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
5680x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
5690x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
5700x53,0x41,
5710x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
5720x20,0x20,
5730x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
5740x10,0x80,
5750,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
5760x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
5770x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
5780,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
5790x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
5800x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
5810,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
5820,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5830,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5840,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5850x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
5860,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
5870xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
5880,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
5890,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5900,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5910,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5920,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5930,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5940,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5950,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5960,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5970,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5980,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5990,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6000,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
601};
602
603static int inquiry_evpd_89(unsigned char * arr)
604{
605 memcpy(arr, vpd89_data, sizeof(vpd89_data));
606 return sizeof(vpd89_data);
607}
608
609
610static unsigned char vpdb0_data[] = {
611 /* from 4th byte */ 0,0,0,4,
612 0,0,0x4,0,
613 0,0,0,64,
614};
615
616static int inquiry_evpd_b0(unsigned char * arr)
617{
618 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
619 if (sdebug_store_sectors > 0x400) {
620 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
621 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
622 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
623 arr[7] = sdebug_store_sectors & 0xff;
624 }
625 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626}
627
628
629#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400630#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631
632static int resp_inquiry(struct scsi_cmnd * scp, int target,
633 struct sdebug_dev_info * devip)
634{
635 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200636 unsigned char * arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 unsigned char *cmd = (unsigned char *)scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200638 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
640 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500641 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
642 if (! arr)
643 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400644 if (devip->wlun)
645 pq_pdt = 0x1e; /* present, wlun */
646 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
647 pq_pdt = 0x7f; /* not present, no device type */
648 else
649 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 arr[0] = pq_pdt;
651 if (0x2 & cmd[1]) { /* CMDDT bit set */
652 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
653 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200654 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 return check_condition_result;
656 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200657 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400658 char lu_id_str[6];
659 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200661 port_group_id = (((host_no + 1) & 0x7f) << 8) +
662 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -0400663 if (0 == scsi_debug_vpd_use_hostno)
664 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400665 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
666 (devip->target * 1000) + devip->lun);
667 target_dev_id = ((host_no + 1) * 2000) +
668 (devip->target * 1000) - 3;
669 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400671 arr[1] = cmd[2]; /*sanity */
672 n = 4;
673 arr[n++] = 0x0; /* this page */
674 arr[n++] = 0x80; /* unit serial number */
675 arr[n++] = 0x83; /* device identification */
676 arr[n++] = 0x84; /* software interface ident. */
677 arr[n++] = 0x85; /* management network addresses */
678 arr[n++] = 0x86; /* extended inquiry */
679 arr[n++] = 0x87; /* mode page policy */
680 arr[n++] = 0x88; /* SCSI ports */
681 arr[n++] = 0x89; /* ATA information */
682 arr[n++] = 0xb0; /* Block limits (SBC) */
683 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400685 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400687 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400689 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200690 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
691 target_dev_id, lu_id_num,
692 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400693 } else if (0x84 == cmd[2]) { /* Software interface ident. */
694 arr[1] = cmd[2]; /*sanity */
695 arr[3] = inquiry_evpd_84(&arr[4]);
696 } else if (0x85 == cmd[2]) { /* Management network addresses */
697 arr[1] = cmd[2]; /*sanity */
698 arr[3] = inquiry_evpd_85(&arr[4]);
699 } else if (0x86 == cmd[2]) { /* extended inquiry */
700 arr[1] = cmd[2]; /*sanity */
701 arr[3] = 0x3c; /* number of following entries */
702 arr[4] = 0x0; /* no protection stuff */
703 arr[5] = 0x7; /* head of q, ordered + simple q's */
704 } else if (0x87 == cmd[2]) { /* mode page policy */
705 arr[1] = cmd[2]; /*sanity */
706 arr[3] = 0x8; /* number of following entries */
707 arr[4] = 0x2; /* disconnect-reconnect mp */
708 arr[6] = 0x80; /* mlus, shared */
709 arr[8] = 0x18; /* protocol specific lu */
710 arr[10] = 0x82; /* mlus, per initiator port */
711 } else if (0x88 == cmd[2]) { /* SCSI Ports */
712 arr[1] = cmd[2]; /*sanity */
713 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
714 } else if (0x89 == cmd[2]) { /* ATA information */
715 arr[1] = cmd[2]; /*sanity */
716 n = inquiry_evpd_89(&arr[4]);
717 arr[2] = (n >> 8);
718 arr[3] = (n & 0xff);
719 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
720 arr[1] = cmd[2]; /*sanity */
721 arr[3] = inquiry_evpd_b0(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 } else {
723 /* Illegal request, invalid field in cdb */
724 mk_sense_buffer(devip, ILLEGAL_REQUEST,
725 INVALID_FIELD_IN_CDB, 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200726 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 return check_condition_result;
728 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400729 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200730 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400731 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200732 kfree(arr);
733 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 }
735 /* drops through here for a standard inquiry */
736 arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
737 arr[2] = scsi_debug_scsi_level;
738 arr[3] = 2; /* response_data_format==2 */
739 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200740 if (0 == scsi_debug_vpd_use_hostno)
741 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400742 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400744 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 memcpy(&arr[8], inq_vendor_id, 8);
746 memcpy(&arr[16], inq_product_id, 16);
747 memcpy(&arr[32], inq_product_rev, 4);
748 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400749 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
750 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
751 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400753 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400755 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400757 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200758 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200760 kfree(arr);
761 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762}
763
764static int resp_requests(struct scsi_cmnd * scp,
765 struct sdebug_dev_info * devip)
766{
767 unsigned char * sbuff;
768 unsigned char *cmd = (unsigned char *)scp->cmnd;
769 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400770 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 int len = 18;
772
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400773 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400775 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
776 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400778 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
779 if (want_dsense) {
780 arr[0] = 0x72;
781 arr[1] = 0x0; /* NO_SENSE in sense_key */
782 arr[2] = THRESHOLD_EXCEEDED;
783 arr[3] = 0xff; /* TEST set and MRIE==6 */
784 } else {
785 arr[0] = 0x70;
786 arr[2] = 0x0; /* NO_SENSE in sense_key */
787 arr[7] = 0xa; /* 18 byte sense buffer */
788 arr[12] = THRESHOLD_EXCEEDED;
789 arr[13] = 0xff; /* TEST set and MRIE==6 */
790 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400791 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400793 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
794 /* DESC bit set and sense_buff in fixed format */
795 memset(arr, 0, sizeof(arr));
796 arr[0] = 0x72;
797 arr[1] = sbuff[2]; /* sense key */
798 arr[2] = sbuff[12]; /* asc */
799 arr[3] = sbuff[13]; /* ascq */
800 len = 8;
801 }
802 }
803 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 return fill_from_dev_buffer(scp, arr, len);
805}
806
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400807static int resp_start_stop(struct scsi_cmnd * scp,
808 struct sdebug_dev_info * devip)
809{
810 unsigned char *cmd = (unsigned char *)scp->cmnd;
811 int power_cond, errsts, start;
812
813 if ((errsts = check_readiness(scp, 1, devip)))
814 return errsts;
815 power_cond = (cmd[4] & 0xf0) >> 4;
816 if (power_cond) {
817 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
818 0);
819 return check_condition_result;
820 }
821 start = cmd[4] & 1;
822 if (start == devip->stopped)
823 devip->stopped = !start;
824 return 0;
825}
826
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827#define SDEBUG_READCAP_ARR_SZ 8
828static int resp_readcap(struct scsi_cmnd * scp,
829 struct sdebug_dev_info * devip)
830{
831 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400832 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 int errsts;
834
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400835 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400837 /* following just in case virtual_gb changed */
838 if (scsi_debug_virtual_gb > 0) {
839 sdebug_capacity = 2048 * 1024;
840 sdebug_capacity *= scsi_debug_virtual_gb;
841 } else
842 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400844 if (sdebug_capacity < 0xffffffff) {
845 capac = (unsigned int)sdebug_capacity - 1;
846 arr[0] = (capac >> 24);
847 arr[1] = (capac >> 16) & 0xff;
848 arr[2] = (capac >> 8) & 0xff;
849 arr[3] = capac & 0xff;
850 } else {
851 arr[0] = 0xff;
852 arr[1] = 0xff;
853 arr[2] = 0xff;
854 arr[3] = 0xff;
855 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
857 arr[7] = SECT_SIZE_PER(target) & 0xff;
858 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
859}
860
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400861#define SDEBUG_READCAP16_ARR_SZ 32
862static int resp_readcap16(struct scsi_cmnd * scp,
863 struct sdebug_dev_info * devip)
864{
865 unsigned char *cmd = (unsigned char *)scp->cmnd;
866 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
867 unsigned long long capac;
868 int errsts, k, alloc_len;
869
870 if ((errsts = check_readiness(scp, 1, devip)))
871 return errsts;
872 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
873 + cmd[13]);
874 /* following just in case virtual_gb changed */
875 if (scsi_debug_virtual_gb > 0) {
876 sdebug_capacity = 2048 * 1024;
877 sdebug_capacity *= scsi_debug_virtual_gb;
878 } else
879 sdebug_capacity = sdebug_store_sectors;
880 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
881 capac = sdebug_capacity - 1;
882 for (k = 0; k < 8; ++k, capac >>= 8)
883 arr[7 - k] = capac & 0xff;
884 arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff;
885 arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff;
886 arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff;
887 arr[11] = SECT_SIZE_PER(target) & 0xff;
888 return fill_from_dev_buffer(scp, arr,
889 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
890}
891
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200892#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
893
894static int resp_report_tgtpgs(struct scsi_cmnd * scp,
895 struct sdebug_dev_info * devip)
896{
897 unsigned char *cmd = (unsigned char *)scp->cmnd;
898 unsigned char * arr;
899 int host_no = devip->sdbg_host->shost->host_no;
900 int n, ret, alen, rlen;
901 int port_group_a, port_group_b, port_a, port_b;
902
903 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
904 + cmd[9]);
905
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500906 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
907 if (! arr)
908 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200909 /*
910 * EVPD page 0x88 states we have two ports, one
911 * real and a fake port with no device connected.
912 * So we create two port groups with one port each
913 * and set the group with port B to unavailable.
914 */
915 port_a = 0x1; /* relative port A */
916 port_b = 0x2; /* relative port B */
917 port_group_a = (((host_no + 1) & 0x7f) << 8) +
918 (devip->channel & 0x7f);
919 port_group_b = (((host_no + 1) & 0x7f) << 8) +
920 (devip->channel & 0x7f) + 0x80;
921
922 /*
923 * The asymmetric access state is cycled according to the host_id.
924 */
925 n = 4;
926 if (0 == scsi_debug_vpd_use_hostno) {
927 arr[n++] = host_no % 3; /* Asymm access state */
928 arr[n++] = 0x0F; /* claim: all states are supported */
929 } else {
930 arr[n++] = 0x0; /* Active/Optimized path */
931 arr[n++] = 0x01; /* claim: only support active/optimized paths */
932 }
933 arr[n++] = (port_group_a >> 8) & 0xff;
934 arr[n++] = port_group_a & 0xff;
935 arr[n++] = 0; /* Reserved */
936 arr[n++] = 0; /* Status code */
937 arr[n++] = 0; /* Vendor unique */
938 arr[n++] = 0x1; /* One port per group */
939 arr[n++] = 0; /* Reserved */
940 arr[n++] = 0; /* Reserved */
941 arr[n++] = (port_a >> 8) & 0xff;
942 arr[n++] = port_a & 0xff;
943 arr[n++] = 3; /* Port unavailable */
944 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
945 arr[n++] = (port_group_b >> 8) & 0xff;
946 arr[n++] = port_group_b & 0xff;
947 arr[n++] = 0; /* Reserved */
948 arr[n++] = 0; /* Status code */
949 arr[n++] = 0; /* Vendor unique */
950 arr[n++] = 0x1; /* One port per group */
951 arr[n++] = 0; /* Reserved */
952 arr[n++] = 0; /* Reserved */
953 arr[n++] = (port_b >> 8) & 0xff;
954 arr[n++] = port_b & 0xff;
955
956 rlen = n - 4;
957 arr[0] = (rlen >> 24) & 0xff;
958 arr[1] = (rlen >> 16) & 0xff;
959 arr[2] = (rlen >> 8) & 0xff;
960 arr[3] = rlen & 0xff;
961
962 /*
963 * Return the smallest value of either
964 * - The allocated length
965 * - The constructed command length
966 * - The maximum array size
967 */
968 rlen = min(alen,n);
969 ret = fill_from_dev_buffer(scp, arr,
970 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
971 kfree(arr);
972 return ret;
973}
974
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975/* <<Following mode page info copied from ST318451LW>> */
976
977static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
978{ /* Read-Write Error Recovery page for mode_sense */
979 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
980 5, 0, 0xff, 0xff};
981
982 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
983 if (1 == pcontrol)
984 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
985 return sizeof(err_recov_pg);
986}
987
988static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
989{ /* Disconnect-Reconnect page for mode_sense */
990 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
991 0, 0, 0, 0, 0, 0, 0, 0};
992
993 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
994 if (1 == pcontrol)
995 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
996 return sizeof(disconnect_pg);
997}
998
999static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1000{ /* Format device page for mode_sense */
1001 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1002 0, 0, 0, 0, 0, 0, 0, 0,
1003 0, 0, 0, 0, 0x40, 0, 0, 0};
1004
1005 memcpy(p, format_pg, sizeof(format_pg));
1006 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1007 p[11] = sdebug_sectors_per & 0xff;
1008 p[12] = (SECT_SIZE >> 8) & 0xff;
1009 p[13] = SECT_SIZE & 0xff;
1010 if (DEV_REMOVEABLE(target))
1011 p[20] |= 0x20; /* should agree with INQUIRY */
1012 if (1 == pcontrol)
1013 memset(p + 2, 0, sizeof(format_pg) - 2);
1014 return sizeof(format_pg);
1015}
1016
1017static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1018{ /* Caching page for mode_sense */
1019 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1020 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1021
1022 memcpy(p, caching_pg, sizeof(caching_pg));
1023 if (1 == pcontrol)
1024 memset(p + 2, 0, sizeof(caching_pg) - 2);
1025 return sizeof(caching_pg);
1026}
1027
1028static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1029{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001030 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1031 0, 0, 0, 0};
1032 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 0, 0, 0x2, 0x4b};
1034
1035 if (scsi_debug_dsense)
1036 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001037 else
1038 ctrl_m_pg[2] &= ~0x4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1040 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001041 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1042 else if (2 == pcontrol)
1043 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 return sizeof(ctrl_m_pg);
1045}
1046
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001047
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1049{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001050 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1051 0, 0, 0x0, 0x0};
1052 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1053 0, 0, 0x0, 0x0};
1054
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1056 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001057 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1058 else if (2 == pcontrol)
1059 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 return sizeof(iec_m_pg);
1061}
1062
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001063static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1064{ /* SAS SSP mode page - short format for mode_sense */
1065 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1066 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1067
1068 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1069 if (1 == pcontrol)
1070 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1071 return sizeof(sas_sf_m_pg);
1072}
1073
1074
1075static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1076 int target_dev_id)
1077{ /* SAS phy control and discover mode page for mode_sense */
1078 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1079 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1080 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1081 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1082 0x2, 0, 0, 0, 0, 0, 0, 0,
1083 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1084 0, 0, 0, 0, 0, 0, 0, 0,
1085 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1086 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1087 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1088 0x3, 0, 0, 0, 0, 0, 0, 0,
1089 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1090 0, 0, 0, 0, 0, 0, 0, 0,
1091 };
1092 int port_a, port_b;
1093
1094 port_a = target_dev_id + 1;
1095 port_b = port_a + 1;
1096 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1097 p[20] = (port_a >> 24);
1098 p[21] = (port_a >> 16) & 0xff;
1099 p[22] = (port_a >> 8) & 0xff;
1100 p[23] = port_a & 0xff;
1101 p[48 + 20] = (port_b >> 24);
1102 p[48 + 21] = (port_b >> 16) & 0xff;
1103 p[48 + 22] = (port_b >> 8) & 0xff;
1104 p[48 + 23] = port_b & 0xff;
1105 if (1 == pcontrol)
1106 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1107 return sizeof(sas_pcd_m_pg);
1108}
1109
1110static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1111{ /* SAS SSP shared protocol specific port mode subpage */
1112 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1113 0, 0, 0, 0, 0, 0, 0, 0,
1114 };
1115
1116 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1117 if (1 == pcontrol)
1118 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1119 return sizeof(sas_sha_m_pg);
1120}
1121
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122#define SDEBUG_MAX_MSENSE_SZ 256
1123
1124static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1125 struct sdebug_dev_info * devip)
1126{
Douglas Gilbert23183912006-09-16 20:30:47 -04001127 unsigned char dbd, llbaa;
1128 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001130 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 unsigned char * ap;
1132 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1133 unsigned char *cmd = (unsigned char *)scp->cmnd;
1134
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001135 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001137 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 pcontrol = (cmd[2] & 0xc0) >> 6;
1139 pcode = cmd[2] & 0x3f;
1140 subpcode = cmd[3];
1141 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001142 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1143 if ((0 == scsi_debug_ptype) && (0 == dbd))
1144 bd_len = llbaa ? 16 : 8;
1145 else
1146 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1148 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1149 if (0x3 == pcontrol) { /* Saving values not supported */
1150 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1151 0);
1152 return check_condition_result;
1153 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001154 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1155 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001156 /* set DPOFUA bit for disks */
1157 if (0 == scsi_debug_ptype)
1158 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1159 else
1160 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 if (msense_6) {
1162 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001163 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 offset = 4;
1165 } else {
1166 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001167 if (16 == bd_len)
1168 arr[4] = 0x1; /* set LONGLBA bit */
1169 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 offset = 8;
1171 }
1172 ap = arr + offset;
Douglas Gilbert23183912006-09-16 20:30:47 -04001173 if ((bd_len > 0) && (0 == sdebug_capacity)) {
1174 if (scsi_debug_virtual_gb > 0) {
1175 sdebug_capacity = 2048 * 1024;
1176 sdebug_capacity *= scsi_debug_virtual_gb;
1177 } else
1178 sdebug_capacity = sdebug_store_sectors;
1179 }
1180 if (8 == bd_len) {
1181 if (sdebug_capacity > 0xfffffffe) {
1182 ap[0] = 0xff;
1183 ap[1] = 0xff;
1184 ap[2] = 0xff;
1185 ap[3] = 0xff;
1186 } else {
1187 ap[0] = (sdebug_capacity >> 24) & 0xff;
1188 ap[1] = (sdebug_capacity >> 16) & 0xff;
1189 ap[2] = (sdebug_capacity >> 8) & 0xff;
1190 ap[3] = sdebug_capacity & 0xff;
1191 }
1192 ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1193 ap[7] = SECT_SIZE_PER(target) & 0xff;
1194 offset += bd_len;
1195 ap = arr + offset;
1196 } else if (16 == bd_len) {
1197 unsigned long long capac = sdebug_capacity;
1198
1199 for (k = 0; k < 8; ++k, capac >>= 8)
1200 ap[7 - k] = capac & 0xff;
1201 ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff;
1202 ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff;
1203 ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1204 ap[15] = SECT_SIZE_PER(target) & 0xff;
1205 offset += bd_len;
1206 ap = arr + offset;
1207 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001209 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1210 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1212 0);
1213 return check_condition_result;
1214 }
1215 switch (pcode) {
1216 case 0x1: /* Read-Write error recovery page, direct access */
1217 len = resp_err_recov_pg(ap, pcontrol, target);
1218 offset += len;
1219 break;
1220 case 0x2: /* Disconnect-Reconnect page, all devices */
1221 len = resp_disconnect_pg(ap, pcontrol, target);
1222 offset += len;
1223 break;
1224 case 0x3: /* Format device page, direct access */
1225 len = resp_format_pg(ap, pcontrol, target);
1226 offset += len;
1227 break;
1228 case 0x8: /* Caching page, direct access */
1229 len = resp_caching_pg(ap, pcontrol, target);
1230 offset += len;
1231 break;
1232 case 0xa: /* Control Mode page, all devices */
1233 len = resp_ctrl_m_pg(ap, pcontrol, target);
1234 offset += len;
1235 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001236 case 0x19: /* if spc==1 then sas phy, control+discover */
1237 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1238 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1239 INVALID_FIELD_IN_CDB, 0);
1240 return check_condition_result;
1241 }
1242 len = 0;
1243 if ((0x0 == subpcode) || (0xff == subpcode))
1244 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1245 if ((0x1 == subpcode) || (0xff == subpcode))
1246 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1247 target_dev_id);
1248 if ((0x2 == subpcode) || (0xff == subpcode))
1249 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1250 offset += len;
1251 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 case 0x1c: /* Informational Exceptions Mode page, all devices */
1253 len = resp_iec_m_pg(ap, pcontrol, target);
1254 offset += len;
1255 break;
1256 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001257 if ((0 == subpcode) || (0xff == subpcode)) {
1258 len = resp_err_recov_pg(ap, pcontrol, target);
1259 len += resp_disconnect_pg(ap + len, pcontrol, target);
1260 len += resp_format_pg(ap + len, pcontrol, target);
1261 len += resp_caching_pg(ap + len, pcontrol, target);
1262 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1263 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1264 if (0xff == subpcode) {
1265 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1266 target, target_dev_id);
1267 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1268 }
1269 len += resp_iec_m_pg(ap + len, pcontrol, target);
1270 } else {
1271 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1272 INVALID_FIELD_IN_CDB, 0);
1273 return check_condition_result;
1274 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 offset += len;
1276 break;
1277 default:
1278 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1279 0);
1280 return check_condition_result;
1281 }
1282 if (msense_6)
1283 arr[0] = offset - 1;
1284 else {
1285 arr[0] = ((offset - 2) >> 8) & 0xff;
1286 arr[1] = (offset - 2) & 0xff;
1287 }
1288 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1289}
1290
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001291#define SDEBUG_MAX_MSELECT_SZ 512
1292
1293static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1294 struct sdebug_dev_info * devip)
1295{
1296 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1297 int param_len, res, errsts, mpage;
1298 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1299 unsigned char *cmd = (unsigned char *)scp->cmnd;
1300
1301 if ((errsts = check_readiness(scp, 1, devip)))
1302 return errsts;
1303 memset(arr, 0, sizeof(arr));
1304 pf = cmd[1] & 0x10;
1305 sp = cmd[1] & 0x1;
1306 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1307 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1308 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1309 INVALID_FIELD_IN_CDB, 0);
1310 return check_condition_result;
1311 }
1312 res = fetch_to_dev_buffer(scp, arr, param_len);
1313 if (-1 == res)
1314 return (DID_ERROR << 16);
1315 else if ((res < param_len) &&
1316 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1317 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1318 " IO sent=%d bytes\n", param_len, res);
1319 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1320 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001321 if (md_len > 2) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001322 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1323 INVALID_FIELD_IN_PARAM_LIST, 0);
1324 return check_condition_result;
1325 }
1326 off = bd_len + (mselect6 ? 4 : 8);
1327 mpage = arr[off] & 0x3f;
1328 ps = !!(arr[off] & 0x80);
1329 if (ps) {
1330 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1331 INVALID_FIELD_IN_PARAM_LIST, 0);
1332 return check_condition_result;
1333 }
1334 spf = !!(arr[off] & 0x40);
1335 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1336 (arr[off + 1] + 2);
1337 if ((pg_len + off) > param_len) {
1338 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1339 PARAMETER_LIST_LENGTH_ERR, 0);
1340 return check_condition_result;
1341 }
1342 switch (mpage) {
1343 case 0xa: /* Control Mode page */
1344 if (ctrl_m_pg[1] == arr[off + 1]) {
1345 memcpy(ctrl_m_pg + 2, arr + off + 2,
1346 sizeof(ctrl_m_pg) - 2);
1347 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1348 return 0;
1349 }
1350 break;
1351 case 0x1c: /* Informational Exceptions Mode page */
1352 if (iec_m_pg[1] == arr[off + 1]) {
1353 memcpy(iec_m_pg + 2, arr + off + 2,
1354 sizeof(iec_m_pg) - 2);
1355 return 0;
1356 }
1357 break;
1358 default:
1359 break;
1360 }
1361 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1362 INVALID_FIELD_IN_PARAM_LIST, 0);
1363 return check_condition_result;
1364}
1365
1366static int resp_temp_l_pg(unsigned char * arr)
1367{
1368 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1369 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1370 };
1371
1372 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1373 return sizeof(temp_l_pg);
1374}
1375
1376static int resp_ie_l_pg(unsigned char * arr)
1377{
1378 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1379 };
1380
1381 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1382 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1383 arr[4] = THRESHOLD_EXCEEDED;
1384 arr[5] = 0xff;
1385 }
1386 return sizeof(ie_l_pg);
1387}
1388
1389#define SDEBUG_MAX_LSENSE_SZ 512
1390
1391static int resp_log_sense(struct scsi_cmnd * scp,
1392 struct sdebug_dev_info * devip)
1393{
Douglas Gilbert23183912006-09-16 20:30:47 -04001394 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001395 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1396 unsigned char *cmd = (unsigned char *)scp->cmnd;
1397
1398 if ((errsts = check_readiness(scp, 1, devip)))
1399 return errsts;
1400 memset(arr, 0, sizeof(arr));
1401 ppc = cmd[1] & 0x2;
1402 sp = cmd[1] & 0x1;
1403 if (ppc || sp) {
1404 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1405 INVALID_FIELD_IN_CDB, 0);
1406 return check_condition_result;
1407 }
1408 pcontrol = (cmd[2] & 0xc0) >> 6;
1409 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001410 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001411 alloc_len = (cmd[7] << 8) + cmd[8];
1412 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001413 if (0 == subpcode) {
1414 switch (pcode) {
1415 case 0x0: /* Supported log pages log page */
1416 n = 4;
1417 arr[n++] = 0x0; /* this page */
1418 arr[n++] = 0xd; /* Temperature */
1419 arr[n++] = 0x2f; /* Informational exceptions */
1420 arr[3] = n - 4;
1421 break;
1422 case 0xd: /* Temperature log page */
1423 arr[3] = resp_temp_l_pg(arr + 4);
1424 break;
1425 case 0x2f: /* Informational exceptions log page */
1426 arr[3] = resp_ie_l_pg(arr + 4);
1427 break;
1428 default:
1429 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1430 INVALID_FIELD_IN_CDB, 0);
1431 return check_condition_result;
1432 }
1433 } else if (0xff == subpcode) {
1434 arr[0] |= 0x40;
1435 arr[1] = subpcode;
1436 switch (pcode) {
1437 case 0x0: /* Supported log pages and subpages log page */
1438 n = 4;
1439 arr[n++] = 0x0;
1440 arr[n++] = 0x0; /* 0,0 page */
1441 arr[n++] = 0x0;
1442 arr[n++] = 0xff; /* this page */
1443 arr[n++] = 0xd;
1444 arr[n++] = 0x0; /* Temperature */
1445 arr[n++] = 0x2f;
1446 arr[n++] = 0x0; /* Informational exceptions */
1447 arr[3] = n - 4;
1448 break;
1449 case 0xd: /* Temperature subpages */
1450 n = 4;
1451 arr[n++] = 0xd;
1452 arr[n++] = 0x0; /* Temperature */
1453 arr[3] = n - 4;
1454 break;
1455 case 0x2f: /* Informational exceptions subpages */
1456 n = 4;
1457 arr[n++] = 0x2f;
1458 arr[n++] = 0x0; /* Informational exceptions */
1459 arr[3] = n - 4;
1460 break;
1461 default:
1462 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1463 INVALID_FIELD_IN_CDB, 0);
1464 return check_condition_result;
1465 }
1466 } else {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001467 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1468 INVALID_FIELD_IN_CDB, 0);
1469 return check_condition_result;
1470 }
1471 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1472 return fill_from_dev_buffer(scp, arr,
1473 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1474}
1475
1476static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
1477 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478{
1479 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001480 unsigned int block, from_bottom;
1481 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 int ret;
1483
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001484 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1486 0);
1487 return check_condition_result;
1488 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001489 /* transfer length excessive (tie in to block limits VPD page) */
1490 if (num > sdebug_store_sectors) {
1491 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1492 0);
1493 return check_condition_result;
1494 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001496 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1497 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1498 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1500 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001501 /* set info field and valid bit for fixed descriptor */
1502 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1503 devip->sense_buff[0] |= 0x80; /* Valid bit */
1504 ret = OPT_MEDIUM_ERR_ADDR;
1505 devip->sense_buff[3] = (ret >> 24) & 0xff;
1506 devip->sense_buff[4] = (ret >> 16) & 0xff;
1507 devip->sense_buff[5] = (ret >> 8) & 0xff;
1508 devip->sense_buff[6] = ret & 0xff;
1509 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 return check_condition_result;
1511 }
1512 read_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001513 if ((lba + num) <= sdebug_store_sectors)
1514 ret = fill_from_dev_buffer(SCpnt,
1515 fake_storep + (lba * SECT_SIZE),
1516 num * SECT_SIZE);
1517 else {
1518 /* modulo when one arg is 64 bits needs do_div() */
1519 u = lba;
1520 block = do_div(u, sdebug_store_sectors);
1521 from_bottom = 0;
1522 if ((block + num) > sdebug_store_sectors)
1523 from_bottom = (block + num) - sdebug_store_sectors;
1524 ret = fill_from_dev_buffer(SCpnt,
1525 fake_storep + (block * SECT_SIZE),
1526 (num - from_bottom) * SECT_SIZE);
1527 if ((0 == ret) && (from_bottom > 0))
1528 ret = fill_from_dev_buffer(SCpnt, fake_storep,
1529 from_bottom * SECT_SIZE);
1530 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 read_unlock_irqrestore(&atomic_rw, iflags);
1532 return ret;
1533}
1534
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001535static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
1536 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537{
1538 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001539 unsigned int block, to_bottom;
1540 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 int res;
1542
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001543 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1545 0);
1546 return check_condition_result;
1547 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001548 /* transfer length excessive (tie in to block limits VPD page) */
1549 if (num > sdebug_store_sectors) {
1550 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1551 0);
1552 return check_condition_result;
1553 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554
1555 write_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001556 if ((lba + num) <= sdebug_store_sectors)
1557 res = fetch_to_dev_buffer(SCpnt,
1558 fake_storep + (lba * SECT_SIZE),
1559 num * SECT_SIZE);
1560 else {
1561 /* modulo when one arg is 64 bits needs do_div() */
1562 u = lba;
1563 block = do_div(u, sdebug_store_sectors);
1564 to_bottom = 0;
1565 if ((block + num) > sdebug_store_sectors)
1566 to_bottom = (block + num) - sdebug_store_sectors;
1567 res = fetch_to_dev_buffer(SCpnt,
1568 fake_storep + (block * SECT_SIZE),
1569 (num - to_bottom) * SECT_SIZE);
1570 if ((0 == res) && (to_bottom > 0))
1571 res = fetch_to_dev_buffer(SCpnt, fake_storep,
1572 to_bottom * SECT_SIZE);
1573 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 write_unlock_irqrestore(&atomic_rw, iflags);
1575 if (-1 == res)
1576 return (DID_ERROR << 16);
1577 else if ((res < (num * SECT_SIZE)) &&
1578 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001579 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 " IO sent=%d bytes\n", num * SECT_SIZE, res);
1581 return 0;
1582}
1583
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001584#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585
1586static int resp_report_luns(struct scsi_cmnd * scp,
1587 struct sdebug_dev_info * devip)
1588{
1589 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001590 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 unsigned char *cmd = (unsigned char *)scp->cmnd;
1592 int select_report = (int)cmd[2];
1593 struct scsi_lun *one_lun;
1594 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001595 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596
1597 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001598 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1600 0);
1601 return check_condition_result;
1602 }
1603 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
1604 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
1605 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001606 if (1 == select_report)
1607 lun_cnt = 0;
1608 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
1609 --lun_cnt;
1610 wlun = (select_report > 0) ? 1 : 0;
1611 num = lun_cnt + wlun;
1612 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
1613 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
1614 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
1615 sizeof(struct scsi_lun)), num);
1616 if (n < num) {
1617 wlun = 0;
1618 lun_cnt = n;
1619 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001621 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
1622 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
1623 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
1624 i++, lun++) {
1625 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 if (upper)
1627 one_lun[i].scsi_lun[0] =
1628 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001629 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001631 if (wlun) {
1632 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
1633 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
1634 i++;
1635 }
1636 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 return fill_from_dev_buffer(scp, arr,
1638 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
1639}
1640
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001641static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
1642 unsigned int num, struct sdebug_dev_info *devip)
1643{
1644 int i, j, ret = -1;
1645 unsigned char *kaddr, *buf;
1646 unsigned int offset;
1647 struct scatterlist *sg;
1648 struct scsi_data_buffer *sdb = scsi_in(scp);
1649
1650 /* better not to use temporary buffer. */
1651 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
1652 if (!buf)
1653 return ret;
1654
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001655 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001656
1657 offset = 0;
1658 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
1659 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
1660 if (!kaddr)
1661 goto out;
1662
1663 for (j = 0; j < sg->length; j++)
1664 *(kaddr + sg->offset + j) ^= *(buf + offset + j);
1665
1666 offset += sg->length;
1667 kunmap_atomic(kaddr, KM_USER0);
1668 }
1669 ret = 0;
1670out:
1671 kfree(buf);
1672
1673 return ret;
1674}
1675
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676/* When timer goes off this function is called. */
1677static void timer_intr_handler(unsigned long indx)
1678{
1679 struct sdebug_queued_cmd * sqcp;
1680 unsigned long iflags;
1681
1682 if (indx >= SCSI_DEBUG_CANQUEUE) {
1683 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
1684 "large\n");
1685 return;
1686 }
1687 spin_lock_irqsave(&queued_arr_lock, iflags);
1688 sqcp = &queued_arr[(int)indx];
1689 if (! sqcp->in_use) {
1690 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
1691 "interrupt\n");
1692 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1693 return;
1694 }
1695 sqcp->in_use = 0;
1696 if (sqcp->done_funct) {
1697 sqcp->a_cmnd->result = sqcp->scsi_result;
1698 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
1699 }
1700 sqcp->done_funct = NULL;
1701 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1702}
1703
1704static int scsi_debug_slave_alloc(struct scsi_device * sdp)
1705{
1706 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001707 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
1708 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001709 set_bit(QUEUE_FLAG_BIDI, &sdp->request_queue->queue_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 return 0;
1711}
1712
1713static int scsi_debug_slave_configure(struct scsi_device * sdp)
1714{
1715 struct sdebug_dev_info * devip;
1716
1717 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001718 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
1719 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
1721 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
1722 devip = devInfoReg(sdp);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001723 if (NULL == devip)
1724 return 1; /* no resources, will be marked offline */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 sdp->hostdata = devip;
1726 if (sdp->host->cmd_per_lun)
1727 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
1728 sdp->host->cmd_per_lun);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001729 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 return 0;
1731}
1732
1733static void scsi_debug_slave_destroy(struct scsi_device * sdp)
1734{
1735 struct sdebug_dev_info * devip =
1736 (struct sdebug_dev_info *)sdp->hostdata;
1737
1738 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001739 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
1740 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 if (devip) {
1742 /* make this slot avaliable for re-use */
1743 devip->used = 0;
1744 sdp->hostdata = NULL;
1745 }
1746}
1747
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09001748struct sdebug_dev_info *sdebug_device_create(struct sdebug_host_info *sdbg_host,
1749 gfp_t flags)
1750{
1751 struct sdebug_dev_info *devip;
1752
1753 devip = kzalloc(sizeof(*devip), flags);
1754 if (devip) {
1755 devip->sdbg_host = sdbg_host;
1756 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
1757 }
1758 return devip;
1759}
1760
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
1762{
1763 struct sdebug_host_info * sdbg_host;
1764 struct sdebug_dev_info * open_devip = NULL;
1765 struct sdebug_dev_info * devip =
1766 (struct sdebug_dev_info *)sdev->hostdata;
1767
1768 if (devip)
1769 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09001770 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
1771 if (!sdbg_host) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 printk(KERN_ERR "Host info NULL\n");
1773 return NULL;
1774 }
1775 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
1776 if ((devip->used) && (devip->channel == sdev->channel) &&
1777 (devip->target == sdev->id) &&
1778 (devip->lun == sdev->lun))
1779 return devip;
1780 else {
1781 if ((!devip->used) && (!open_devip))
1782 open_devip = devip;
1783 }
1784 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09001785 if (!open_devip) { /* try and make a new one */
1786 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
1787 if (!open_devip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 printk(KERN_ERR "%s: out of memory at line %d\n",
1789 __FUNCTION__, __LINE__);
1790 return NULL;
1791 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09001793
1794 open_devip->channel = sdev->channel;
1795 open_devip->target = sdev->id;
1796 open_devip->lun = sdev->lun;
1797 open_devip->sdbg_host = sdbg_host;
1798 open_devip->reset = 1;
1799 open_devip->used = 1;
1800 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
1801 if (scsi_debug_dsense)
1802 open_devip->sense_buff[0] = 0x72;
1803 else {
1804 open_devip->sense_buff[0] = 0x70;
1805 open_devip->sense_buff[7] = 0xa;
1806 }
1807 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
1808 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
1809
1810 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811}
1812
1813static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
1814 int asc, int asq)
1815{
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09001816 unsigned char *sbuff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817
1818 sbuff = devip->sense_buff;
1819 memset(sbuff, 0, SDEBUG_SENSE_LEN);
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09001820
1821 scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
1822
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1824 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
1825 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
1826}
1827
1828static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
1829{
1830 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1831 printk(KERN_INFO "scsi_debug: abort\n");
1832 ++num_aborts;
1833 stop_queued_cmnd(SCpnt);
1834 return SUCCESS;
1835}
1836
1837static int scsi_debug_biosparam(struct scsi_device *sdev,
1838 struct block_device * bdev, sector_t capacity, int *info)
1839{
1840 int res;
1841 unsigned char *buf;
1842
1843 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1844 printk(KERN_INFO "scsi_debug: biosparam\n");
1845 buf = scsi_bios_ptable(bdev);
1846 if (buf) {
1847 res = scsi_partsize(buf, capacity,
1848 &info[2], &info[0], &info[1]);
1849 kfree(buf);
1850 if (! res)
1851 return res;
1852 }
1853 info[0] = sdebug_heads;
1854 info[1] = sdebug_sectors_per;
1855 info[2] = sdebug_cylinders_per;
1856 return 0;
1857}
1858
1859static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
1860{
1861 struct sdebug_dev_info * devip;
1862
1863 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1864 printk(KERN_INFO "scsi_debug: device_reset\n");
1865 ++num_dev_resets;
1866 if (SCpnt) {
1867 devip = devInfoReg(SCpnt->device);
1868 if (devip)
1869 devip->reset = 1;
1870 }
1871 return SUCCESS;
1872}
1873
1874static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
1875{
1876 struct sdebug_host_info *sdbg_host;
1877 struct sdebug_dev_info * dev_info;
1878 struct scsi_device * sdp;
1879 struct Scsi_Host * hp;
1880
1881 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1882 printk(KERN_INFO "scsi_debug: bus_reset\n");
1883 ++num_bus_resets;
1884 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09001885 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 if (sdbg_host) {
1887 list_for_each_entry(dev_info,
1888 &sdbg_host->dev_info_list,
1889 dev_list)
1890 dev_info->reset = 1;
1891 }
1892 }
1893 return SUCCESS;
1894}
1895
1896static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
1897{
1898 struct sdebug_host_info * sdbg_host;
1899 struct sdebug_dev_info * dev_info;
1900
1901 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1902 printk(KERN_INFO "scsi_debug: host_reset\n");
1903 ++num_host_resets;
1904 spin_lock(&sdebug_host_list_lock);
1905 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
1906 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
1907 dev_list)
1908 dev_info->reset = 1;
1909 }
1910 spin_unlock(&sdebug_host_list_lock);
1911 stop_all_queued();
1912 return SUCCESS;
1913}
1914
1915/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
1916static int stop_queued_cmnd(struct scsi_cmnd * cmnd)
1917{
1918 unsigned long iflags;
1919 int k;
1920 struct sdebug_queued_cmd * sqcp;
1921
1922 spin_lock_irqsave(&queued_arr_lock, iflags);
1923 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1924 sqcp = &queued_arr[k];
1925 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
1926 del_timer_sync(&sqcp->cmnd_timer);
1927 sqcp->in_use = 0;
1928 sqcp->a_cmnd = NULL;
1929 break;
1930 }
1931 }
1932 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1933 return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
1934}
1935
1936/* Deletes (stops) timers of all queued commands */
1937static void stop_all_queued(void)
1938{
1939 unsigned long iflags;
1940 int k;
1941 struct sdebug_queued_cmd * sqcp;
1942
1943 spin_lock_irqsave(&queued_arr_lock, iflags);
1944 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1945 sqcp = &queued_arr[k];
1946 if (sqcp->in_use && sqcp->a_cmnd) {
1947 del_timer_sync(&sqcp->cmnd_timer);
1948 sqcp->in_use = 0;
1949 sqcp->a_cmnd = NULL;
1950 }
1951 }
1952 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1953}
1954
1955/* Initializes timers in queued array */
1956static void __init init_all_queued(void)
1957{
1958 unsigned long iflags;
1959 int k;
1960 struct sdebug_queued_cmd * sqcp;
1961
1962 spin_lock_irqsave(&queued_arr_lock, iflags);
1963 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1964 sqcp = &queued_arr[k];
1965 init_timer(&sqcp->cmnd_timer);
1966 sqcp->in_use = 0;
1967 sqcp->a_cmnd = NULL;
1968 }
1969 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1970}
1971
1972static void __init sdebug_build_parts(unsigned char * ramp)
1973{
1974 struct partition * pp;
1975 int starts[SDEBUG_MAX_PARTS + 2];
1976 int sectors_per_part, num_sectors, k;
1977 int heads_by_sects, start_sec, end_sec;
1978
1979 /* assume partition table already zeroed */
1980 if ((scsi_debug_num_parts < 1) || (sdebug_store_size < 1048576))
1981 return;
1982 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
1983 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
1984 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
1985 "partitions to %d\n", SDEBUG_MAX_PARTS);
1986 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001987 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 sectors_per_part = (num_sectors - sdebug_sectors_per)
1989 / scsi_debug_num_parts;
1990 heads_by_sects = sdebug_heads * sdebug_sectors_per;
1991 starts[0] = sdebug_sectors_per;
1992 for (k = 1; k < scsi_debug_num_parts; ++k)
1993 starts[k] = ((k * sectors_per_part) / heads_by_sects)
1994 * heads_by_sects;
1995 starts[scsi_debug_num_parts] = num_sectors;
1996 starts[scsi_debug_num_parts + 1] = 0;
1997
1998 ramp[510] = 0x55; /* magic partition markings */
1999 ramp[511] = 0xAA;
2000 pp = (struct partition *)(ramp + 0x1be);
2001 for (k = 0; starts[k + 1]; ++k, ++pp) {
2002 start_sec = starts[k];
2003 end_sec = starts[k + 1] - 1;
2004 pp->boot_ind = 0;
2005
2006 pp->cyl = start_sec / heads_by_sects;
2007 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2008 / sdebug_sectors_per;
2009 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2010
2011 pp->end_cyl = end_sec / heads_by_sects;
2012 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2013 / sdebug_sectors_per;
2014 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2015
2016 pp->start_sect = start_sec;
2017 pp->nr_sects = end_sec - start_sec + 1;
2018 pp->sys_ind = 0x83; /* plain Linux partition */
2019 }
2020}
2021
2022static int schedule_resp(struct scsi_cmnd * cmnd,
2023 struct sdebug_dev_info * devip,
2024 done_funct_t done, int scsi_result, int delta_jiff)
2025{
2026 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2027 if (scsi_result) {
2028 struct scsi_device * sdp = cmnd->device;
2029
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002030 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2031 "non-zero result=0x%x\n", sdp->host->host_no,
2032 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 }
2034 }
2035 if (cmnd && devip) {
2036 /* simulate autosense by this driver */
2037 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2038 memcpy(cmnd->sense_buffer, devip->sense_buff,
2039 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2040 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2041 }
2042 if (delta_jiff <= 0) {
2043 if (cmnd)
2044 cmnd->result = scsi_result;
2045 if (done)
2046 done(cmnd);
2047 return 0;
2048 } else {
2049 unsigned long iflags;
2050 int k;
2051 struct sdebug_queued_cmd * sqcp = NULL;
2052
2053 spin_lock_irqsave(&queued_arr_lock, iflags);
2054 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2055 sqcp = &queued_arr[k];
2056 if (! sqcp->in_use)
2057 break;
2058 }
2059 if (k >= SCSI_DEBUG_CANQUEUE) {
2060 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2061 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2062 return 1; /* report busy to mid level */
2063 }
2064 sqcp->in_use = 1;
2065 sqcp->a_cmnd = cmnd;
2066 sqcp->scsi_result = scsi_result;
2067 sqcp->done_funct = done;
2068 sqcp->cmnd_timer.function = timer_intr_handler;
2069 sqcp->cmnd_timer.data = k;
2070 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2071 add_timer(&sqcp->cmnd_timer);
2072 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2073 if (cmnd)
2074 cmnd->result = 0;
2075 return 0;
2076 }
2077}
2078
Douglas Gilbert23183912006-09-16 20:30:47 -04002079/* Note: The following macros create attribute files in the
2080 /sys/module/scsi_debug/parameters directory. Unfortunately this
2081 driver is unaware of a change and cannot trigger auxiliary actions
2082 as it can when the corresponding attribute in the
2083 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2084 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002085module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2086module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2087module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2088module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2089module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002090module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002091module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2092module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2093module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2094module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2095module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2096module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2097module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2098module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002099module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2100 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101
2102MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2103MODULE_DESCRIPTION("SCSI debug adapter driver");
2104MODULE_LICENSE("GPL");
2105MODULE_VERSION(SCSI_DEBUG_VERSION);
2106
2107MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2108MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002109MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2110MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07002111MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002112MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002113MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2114MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002116MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002117MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2119MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002120MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002121MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122
2123
2124static char sdebug_info[256];
2125
2126static const char * scsi_debug_info(struct Scsi_Host * shp)
2127{
2128 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2129 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2130 scsi_debug_version_date, scsi_debug_dev_size_mb,
2131 scsi_debug_opts);
2132 return sdebug_info;
2133}
2134
2135/* scsi_debug_proc_info
2136 * Used if the driver currently has no own support for /proc/scsi
2137 */
2138static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2139 int length, int inout)
2140{
2141 int len, pos, begin;
2142 int orig_length;
2143
2144 orig_length = length;
2145
2146 if (inout == 1) {
2147 char arr[16];
2148 int minLen = length > 15 ? 15 : length;
2149
2150 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2151 return -EACCES;
2152 memcpy(arr, buffer, minLen);
2153 arr[minLen] = '\0';
2154 if (1 != sscanf(arr, "%d", &pos))
2155 return -EINVAL;
2156 scsi_debug_opts = pos;
2157 if (scsi_debug_every_nth != 0)
2158 scsi_debug_cmnd_count = 0;
2159 return length;
2160 }
2161 begin = 0;
2162 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2163 "%s [%s]\n"
2164 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2165 "every_nth=%d(curr:%d)\n"
2166 "delay=%d, max_luns=%d, scsi_level=%d\n"
2167 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2168 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
2169 "host_resets=%d\n",
2170 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2171 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2172 scsi_debug_cmnd_count, scsi_debug_delay,
2173 scsi_debug_max_luns, scsi_debug_scsi_level,
2174 SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
2175 num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
2176 if (pos < offset) {
2177 len = 0;
2178 begin = pos;
2179 }
2180 *start = buffer + (offset - begin); /* Start of wanted data */
2181 len -= (offset - begin);
2182 if (len > length)
2183 len = length;
2184 return len;
2185}
2186
2187static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2188{
2189 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2190}
2191
2192static ssize_t sdebug_delay_store(struct device_driver * ddp,
2193 const char * buf, size_t count)
2194{
2195 int delay;
2196 char work[20];
2197
2198 if (1 == sscanf(buf, "%10s", work)) {
2199 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2200 scsi_debug_delay = delay;
2201 return count;
2202 }
2203 }
2204 return -EINVAL;
2205}
2206DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2207 sdebug_delay_store);
2208
2209static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2210{
2211 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2212}
2213
2214static ssize_t sdebug_opts_store(struct device_driver * ddp,
2215 const char * buf, size_t count)
2216{
2217 int opts;
2218 char work[20];
2219
2220 if (1 == sscanf(buf, "%10s", work)) {
2221 if (0 == strnicmp(work,"0x", 2)) {
2222 if (1 == sscanf(&work[2], "%x", &opts))
2223 goto opts_done;
2224 } else {
2225 if (1 == sscanf(work, "%d", &opts))
2226 goto opts_done;
2227 }
2228 }
2229 return -EINVAL;
2230opts_done:
2231 scsi_debug_opts = opts;
2232 scsi_debug_cmnd_count = 0;
2233 return count;
2234}
2235DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2236 sdebug_opts_store);
2237
2238static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2239{
2240 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2241}
2242static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2243 const char * buf, size_t count)
2244{
2245 int n;
2246
2247 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2248 scsi_debug_ptype = n;
2249 return count;
2250 }
2251 return -EINVAL;
2252}
2253DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2254
2255static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2256{
2257 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2258}
2259static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2260 const char * buf, size_t count)
2261{
2262 int n;
2263
2264 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2265 scsi_debug_dsense = n;
2266 return count;
2267 }
2268 return -EINVAL;
2269}
2270DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2271 sdebug_dsense_store);
2272
Douglas Gilbert23183912006-09-16 20:30:47 -04002273static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2274{
2275 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2276}
2277static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2278 const char * buf, size_t count)
2279{
2280 int n;
2281
2282 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2283 scsi_debug_fake_rw = n;
2284 return count;
2285 }
2286 return -EINVAL;
2287}
2288DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2289 sdebug_fake_rw_store);
2290
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002291static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2292{
2293 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2294}
2295static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2296 const char * buf, size_t count)
2297{
2298 int n;
2299
2300 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2301 scsi_debug_no_lun_0 = n;
2302 return count;
2303 }
2304 return -EINVAL;
2305}
2306DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2307 sdebug_no_lun_0_store);
2308
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2310{
2311 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2312}
2313static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2314 const char * buf, size_t count)
2315{
2316 int n;
2317
2318 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2319 scsi_debug_num_tgts = n;
2320 sdebug_max_tgts_luns();
2321 return count;
2322 }
2323 return -EINVAL;
2324}
2325DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2326 sdebug_num_tgts_store);
2327
2328static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2329{
2330 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2331}
2332DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2333
2334static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2335{
2336 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2337}
2338DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2339
2340static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2341{
2342 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2343}
2344static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2345 const char * buf, size_t count)
2346{
2347 int nth;
2348
2349 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2350 scsi_debug_every_nth = nth;
2351 scsi_debug_cmnd_count = 0;
2352 return count;
2353 }
2354 return -EINVAL;
2355}
2356DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2357 sdebug_every_nth_store);
2358
2359static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2360{
2361 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2362}
2363static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2364 const char * buf, size_t count)
2365{
2366 int n;
2367
2368 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2369 scsi_debug_max_luns = n;
2370 sdebug_max_tgts_luns();
2371 return count;
2372 }
2373 return -EINVAL;
2374}
2375DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2376 sdebug_max_luns_store);
2377
2378static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
2379{
2380 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
2381}
2382DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
2383
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002384static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2385{
2386 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2387}
2388static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2389 const char * buf, size_t count)
2390{
2391 int n;
2392
2393 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2394 scsi_debug_virtual_gb = n;
2395 if (scsi_debug_virtual_gb > 0) {
2396 sdebug_capacity = 2048 * 1024;
2397 sdebug_capacity *= scsi_debug_virtual_gb;
2398 } else
2399 sdebug_capacity = sdebug_store_sectors;
2400 return count;
2401 }
2402 return -EINVAL;
2403}
2404DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2405 sdebug_virtual_gb_store);
2406
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
2408{
2409 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
2410}
2411
2412static ssize_t sdebug_add_host_store(struct device_driver * ddp,
2413 const char * buf, size_t count)
2414{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002415 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002417 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 if (delta_hosts > 0) {
2420 do {
2421 sdebug_add_adapter();
2422 } while (--delta_hosts);
2423 } else if (delta_hosts < 0) {
2424 do {
2425 sdebug_remove_adapter();
2426 } while (++delta_hosts);
2427 }
2428 return count;
2429}
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002430DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 sdebug_add_host_store);
2432
Douglas Gilbert23183912006-09-16 20:30:47 -04002433static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
2434 char * buf)
2435{
2436 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
2437}
2438static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
2439 const char * buf, size_t count)
2440{
2441 int n;
2442
2443 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2444 scsi_debug_vpd_use_hostno = n;
2445 return count;
2446 }
2447 return -EINVAL;
2448}
2449DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
2450 sdebug_vpd_use_hostno_store);
2451
2452/* Note: The following function creates attribute files in the
2453 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
2454 files (over those found in the /sys/module/scsi_debug/parameters
2455 directory) is that auxiliary actions can be triggered when an attribute
2456 is changed. For example see: sdebug_add_host_store() above.
2457 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002458static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002460 int ret;
2461
2462 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2463 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
2464 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2465 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2466 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04002467 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002468 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002469 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002470 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002471 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002472 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
2473 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
2474 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04002475 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
2476 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002477 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478}
2479
2480static void do_remove_driverfs_files(void)
2481{
Douglas Gilbert23183912006-09-16 20:30:47 -04002482 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
2483 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
2485 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
2486 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002488 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
2489 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002491 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
2493 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2494 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2495 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
2496 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2497}
2498
2499static int __init scsi_debug_init(void)
2500{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002501 unsigned int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502 int host_to_add;
2503 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002504 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505
2506 if (scsi_debug_dev_size_mb < 1)
2507 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002508 sdebug_store_size = (unsigned int)scsi_debug_dev_size_mb * 1048576;
2509 sdebug_store_sectors = sdebug_store_size / SECT_SIZE;
2510 if (scsi_debug_virtual_gb > 0) {
2511 sdebug_capacity = 2048 * 1024;
2512 sdebug_capacity *= scsi_debug_virtual_gb;
2513 } else
2514 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515
2516 /* play around with geometry, don't waste too much on track 0 */
2517 sdebug_heads = 8;
2518 sdebug_sectors_per = 32;
2519 if (scsi_debug_dev_size_mb >= 16)
2520 sdebug_heads = 32;
2521 else if (scsi_debug_dev_size_mb >= 256)
2522 sdebug_heads = 64;
2523 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2524 (sdebug_sectors_per * sdebug_heads);
2525 if (sdebug_cylinders_per >= 1024) {
2526 /* other LLDs do this; implies >= 1GB ram disk ... */
2527 sdebug_heads = 255;
2528 sdebug_sectors_per = 63;
2529 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2530 (sdebug_sectors_per * sdebug_heads);
2531 }
2532
2533 sz = sdebug_store_size;
2534 fake_storep = vmalloc(sz);
2535 if (NULL == fake_storep) {
2536 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
2537 return -ENOMEM;
2538 }
2539 memset(fake_storep, 0, sz);
2540 if (scsi_debug_num_parts > 0)
2541 sdebug_build_parts(fake_storep);
2542
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002543 ret = device_register(&pseudo_primary);
2544 if (ret < 0) {
2545 printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
2546 ret);
2547 goto free_vm;
2548 }
2549 ret = bus_register(&pseudo_lld_bus);
2550 if (ret < 0) {
2551 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
2552 ret);
2553 goto dev_unreg;
2554 }
2555 ret = driver_register(&sdebug_driverfs_driver);
2556 if (ret < 0) {
2557 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
2558 ret);
2559 goto bus_unreg;
2560 }
2561 ret = do_create_driverfs_files();
2562 if (ret < 0) {
2563 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
2564 ret);
2565 goto del_files;
2566 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002568 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 host_to_add = scsi_debug_add_host;
2571 scsi_debug_add_host = 0;
2572
2573 for (k = 0; k < host_to_add; k++) {
2574 if (sdebug_add_adapter()) {
2575 printk(KERN_ERR "scsi_debug_init: "
2576 "sdebug_add_adapter failed k=%d\n", k);
2577 break;
2578 }
2579 }
2580
2581 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
2582 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
2583 scsi_debug_add_host);
2584 }
2585 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002586
2587del_files:
2588 do_remove_driverfs_files();
2589 driver_unregister(&sdebug_driverfs_driver);
2590bus_unreg:
2591 bus_unregister(&pseudo_lld_bus);
2592dev_unreg:
2593 device_unregister(&pseudo_primary);
2594free_vm:
2595 vfree(fake_storep);
2596
2597 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598}
2599
2600static void __exit scsi_debug_exit(void)
2601{
2602 int k = scsi_debug_add_host;
2603
2604 stop_all_queued();
2605 for (; k; k--)
2606 sdebug_remove_adapter();
2607 do_remove_driverfs_files();
2608 driver_unregister(&sdebug_driverfs_driver);
2609 bus_unregister(&pseudo_lld_bus);
2610 device_unregister(&pseudo_primary);
2611
2612 vfree(fake_storep);
2613}
2614
2615device_initcall(scsi_debug_init);
2616module_exit(scsi_debug_exit);
2617
Adrian Bunk52c1da32005-06-23 22:05:33 -07002618static void pseudo_0_release(struct device * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619{
2620 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2621 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
2622}
2623
2624static struct device pseudo_primary = {
2625 .bus_id = "pseudo_0",
2626 .release = pseudo_0_release,
2627};
2628
2629static int pseudo_lld_bus_match(struct device *dev,
2630 struct device_driver *dev_driver)
2631{
2632 return 1;
2633}
2634
2635static struct bus_type pseudo_lld_bus = {
2636 .name = "pseudo",
2637 .match = pseudo_lld_bus_match,
Russell Kingbbbe3a42006-01-05 14:44:46 +00002638 .probe = sdebug_driver_probe,
2639 .remove = sdebug_driver_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640};
2641
2642static void sdebug_release_adapter(struct device * dev)
2643{
2644 struct sdebug_host_info *sdbg_host;
2645
2646 sdbg_host = to_sdebug_host(dev);
2647 kfree(sdbg_host);
2648}
2649
2650static int sdebug_add_adapter(void)
2651{
2652 int k, devs_per_host;
2653 int error = 0;
2654 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09002655 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002657 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 if (NULL == sdbg_host) {
2659 printk(KERN_ERR "%s: out of memory at line %d\n",
2660 __FUNCTION__, __LINE__);
2661 return -ENOMEM;
2662 }
2663
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
2665
2666 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
2667 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002668 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
2669 if (!sdbg_devinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 printk(KERN_ERR "%s: out of memory at line %d\n",
2671 __FUNCTION__, __LINE__);
2672 error = -ENOMEM;
2673 goto clean;
2674 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 }
2676
2677 spin_lock(&sdebug_host_list_lock);
2678 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
2679 spin_unlock(&sdebug_host_list_lock);
2680
2681 sdbg_host->dev.bus = &pseudo_lld_bus;
2682 sdbg_host->dev.parent = &pseudo_primary;
2683 sdbg_host->dev.release = &sdebug_release_adapter;
2684 sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host);
2685
2686 error = device_register(&sdbg_host->dev);
2687
2688 if (error)
2689 goto clean;
2690
2691 ++scsi_debug_add_host;
2692 return error;
2693
2694clean:
FUJITA Tomonori8b402282008-03-20 11:09:18 +09002695 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
2696 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 list_del(&sdbg_devinfo->dev_list);
2698 kfree(sdbg_devinfo);
2699 }
2700
2701 kfree(sdbg_host);
2702 return error;
2703}
2704
2705static void sdebug_remove_adapter(void)
2706{
2707 struct sdebug_host_info * sdbg_host = NULL;
2708
2709 spin_lock(&sdebug_host_list_lock);
2710 if (!list_empty(&sdebug_host_list)) {
2711 sdbg_host = list_entry(sdebug_host_list.prev,
2712 struct sdebug_host_info, host_list);
2713 list_del(&sdbg_host->host_list);
2714 }
2715 spin_unlock(&sdebug_host_list_lock);
2716
2717 if (!sdbg_host)
2718 return;
2719
2720 device_unregister(&sdbg_host->dev);
2721 --scsi_debug_add_host;
2722}
2723
FUJITA Tomonori639db472008-03-20 11:09:19 +09002724static
2725int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
2726{
2727 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
2728 int len, k;
2729 unsigned int num;
2730 unsigned long long lba;
2731 int errsts = 0;
2732 int target = SCpnt->device->id;
2733 struct sdebug_dev_info *devip = NULL;
2734 int inj_recovered = 0;
2735 int inj_transport = 0;
2736 int delay_override = 0;
2737
2738 scsi_set_resid(SCpnt, 0);
2739 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
2740 printk(KERN_INFO "scsi_debug: cmd ");
2741 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
2742 printk("%02x ", (int)cmd[k]);
2743 printk("\n");
2744 }
2745
2746 if (target == SCpnt->device->host->hostt->this_id) {
2747 printk(KERN_INFO "scsi_debug: initiator's id used as "
2748 "target!\n");
2749 return schedule_resp(SCpnt, NULL, done,
2750 DID_NO_CONNECT << 16, 0);
2751 }
2752
2753 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
2754 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
2755 return schedule_resp(SCpnt, NULL, done,
2756 DID_NO_CONNECT << 16, 0);
2757 devip = devInfoReg(SCpnt->device);
2758 if (NULL == devip)
2759 return schedule_resp(SCpnt, NULL, done,
2760 DID_NO_CONNECT << 16, 0);
2761
2762 if ((scsi_debug_every_nth != 0) &&
2763 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
2764 scsi_debug_cmnd_count = 0;
2765 if (scsi_debug_every_nth < -1)
2766 scsi_debug_every_nth = -1;
2767 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
2768 return 0; /* ignore command causing timeout */
2769 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
2770 inj_recovered = 1; /* to reads and writes below */
2771 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
2772 inj_transport = 1; /* to reads and writes below */
2773 }
2774
2775 if (devip->wlun) {
2776 switch (*cmd) {
2777 case INQUIRY:
2778 case REQUEST_SENSE:
2779 case TEST_UNIT_READY:
2780 case REPORT_LUNS:
2781 break; /* only allowable wlun commands */
2782 default:
2783 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2784 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
2785 "not supported for wlun\n", *cmd);
2786 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2787 INVALID_OPCODE, 0);
2788 errsts = check_condition_result;
2789 return schedule_resp(SCpnt, devip, done, errsts,
2790 0);
2791 }
2792 }
2793
2794 switch (*cmd) {
2795 case INQUIRY: /* mandatory, ignore unit attention */
2796 delay_override = 1;
2797 errsts = resp_inquiry(SCpnt, target, devip);
2798 break;
2799 case REQUEST_SENSE: /* mandatory, ignore unit attention */
2800 delay_override = 1;
2801 errsts = resp_requests(SCpnt, devip);
2802 break;
2803 case REZERO_UNIT: /* actually this is REWIND for SSC */
2804 case START_STOP:
2805 errsts = resp_start_stop(SCpnt, devip);
2806 break;
2807 case ALLOW_MEDIUM_REMOVAL:
2808 errsts = check_readiness(SCpnt, 1, devip);
2809 if (errsts)
2810 break;
2811 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2812 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
2813 cmd[4] ? "inhibited" : "enabled");
2814 break;
2815 case SEND_DIAGNOSTIC: /* mandatory */
2816 errsts = check_readiness(SCpnt, 1, devip);
2817 break;
2818 case TEST_UNIT_READY: /* mandatory */
2819 delay_override = 1;
2820 errsts = check_readiness(SCpnt, 0, devip);
2821 break;
2822 case RESERVE:
2823 errsts = check_readiness(SCpnt, 1, devip);
2824 break;
2825 case RESERVE_10:
2826 errsts = check_readiness(SCpnt, 1, devip);
2827 break;
2828 case RELEASE:
2829 errsts = check_readiness(SCpnt, 1, devip);
2830 break;
2831 case RELEASE_10:
2832 errsts = check_readiness(SCpnt, 1, devip);
2833 break;
2834 case READ_CAPACITY:
2835 errsts = resp_readcap(SCpnt, devip);
2836 break;
2837 case SERVICE_ACTION_IN:
2838 if (SAI_READ_CAPACITY_16 != cmd[1]) {
2839 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2840 INVALID_OPCODE, 0);
2841 errsts = check_condition_result;
2842 break;
2843 }
2844 errsts = resp_readcap16(SCpnt, devip);
2845 break;
2846 case MAINTENANCE_IN:
2847 if (MI_REPORT_TARGET_PGS != cmd[1]) {
2848 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2849 INVALID_OPCODE, 0);
2850 errsts = check_condition_result;
2851 break;
2852 }
2853 errsts = resp_report_tgtpgs(SCpnt, devip);
2854 break;
2855 case READ_16:
2856 case READ_12:
2857 case READ_10:
2858 case READ_6:
2859 errsts = check_readiness(SCpnt, 0, devip);
2860 if (errsts)
2861 break;
2862 if (scsi_debug_fake_rw)
2863 break;
2864 get_data_transfer_info(cmd, &lba, &num);
2865 errsts = resp_read(SCpnt, lba, num, devip);
2866 if (inj_recovered && (0 == errsts)) {
2867 mk_sense_buffer(devip, RECOVERED_ERROR,
2868 THRESHOLD_EXCEEDED, 0);
2869 errsts = check_condition_result;
2870 } else if (inj_transport && (0 == errsts)) {
2871 mk_sense_buffer(devip, ABORTED_COMMAND,
2872 TRANSPORT_PROBLEM, ACK_NAK_TO);
2873 errsts = check_condition_result;
2874 }
2875 break;
2876 case REPORT_LUNS: /* mandatory, ignore unit attention */
2877 delay_override = 1;
2878 errsts = resp_report_luns(SCpnt, devip);
2879 break;
2880 case VERIFY: /* 10 byte SBC-2 command */
2881 errsts = check_readiness(SCpnt, 0, devip);
2882 break;
2883 case WRITE_16:
2884 case WRITE_12:
2885 case WRITE_10:
2886 case WRITE_6:
2887 errsts = check_readiness(SCpnt, 0, devip);
2888 if (errsts)
2889 break;
2890 if (scsi_debug_fake_rw)
2891 break;
2892 get_data_transfer_info(cmd, &lba, &num);
2893 errsts = resp_write(SCpnt, lba, num, devip);
2894 if (inj_recovered && (0 == errsts)) {
2895 mk_sense_buffer(devip, RECOVERED_ERROR,
2896 THRESHOLD_EXCEEDED, 0);
2897 errsts = check_condition_result;
2898 }
2899 break;
2900 case MODE_SENSE:
2901 case MODE_SENSE_10:
2902 errsts = resp_mode_sense(SCpnt, target, devip);
2903 break;
2904 case MODE_SELECT:
2905 errsts = resp_mode_select(SCpnt, 1, devip);
2906 break;
2907 case MODE_SELECT_10:
2908 errsts = resp_mode_select(SCpnt, 0, devip);
2909 break;
2910 case LOG_SENSE:
2911 errsts = resp_log_sense(SCpnt, devip);
2912 break;
2913 case SYNCHRONIZE_CACHE:
2914 delay_override = 1;
2915 errsts = check_readiness(SCpnt, 0, devip);
2916 break;
2917 case WRITE_BUFFER:
2918 errsts = check_readiness(SCpnt, 1, devip);
2919 break;
2920 case XDWRITEREAD_10:
2921 if (!scsi_bidi_cmnd(SCpnt)) {
2922 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2923 INVALID_FIELD_IN_CDB, 0);
2924 errsts = check_condition_result;
2925 break;
2926 }
2927
2928 errsts = check_readiness(SCpnt, 0, devip);
2929 if (errsts)
2930 break;
2931 if (scsi_debug_fake_rw)
2932 break;
2933 get_data_transfer_info(cmd, &lba, &num);
2934 errsts = resp_read(SCpnt, lba, num, devip);
2935 if (errsts)
2936 break;
2937 errsts = resp_write(SCpnt, lba, num, devip);
2938 if (errsts)
2939 break;
2940 errsts = resp_xdwriteread(SCpnt, lba, num, devip);
2941 break;
2942 default:
2943 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2944 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
2945 "supported\n", *cmd);
2946 errsts = check_readiness(SCpnt, 1, devip);
2947 if (errsts)
2948 break; /* Unit attention takes precedence */
2949 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
2950 errsts = check_condition_result;
2951 break;
2952 }
2953 return schedule_resp(SCpnt, devip, done, errsts,
2954 (delay_override ? 0 : scsi_debug_delay));
2955}
2956
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09002957static struct scsi_host_template sdebug_driver_template = {
2958 .proc_info = scsi_debug_proc_info,
2959 .proc_name = sdebug_proc_name,
2960 .name = "SCSI DEBUG",
2961 .info = scsi_debug_info,
2962 .slave_alloc = scsi_debug_slave_alloc,
2963 .slave_configure = scsi_debug_slave_configure,
2964 .slave_destroy = scsi_debug_slave_destroy,
2965 .ioctl = scsi_debug_ioctl,
2966 .queuecommand = scsi_debug_queuecommand,
2967 .eh_abort_handler = scsi_debug_abort,
2968 .eh_bus_reset_handler = scsi_debug_bus_reset,
2969 .eh_device_reset_handler = scsi_debug_device_reset,
2970 .eh_host_reset_handler = scsi_debug_host_reset,
2971 .bios_param = scsi_debug_biosparam,
2972 .can_queue = SCSI_DEBUG_CANQUEUE,
2973 .this_id = 7,
2974 .sg_tablesize = 256,
2975 .cmd_per_lun = 16,
2976 .max_sectors = 0xffff,
2977 .use_clustering = DISABLE_CLUSTERING,
2978 .module = THIS_MODULE,
2979};
2980
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981static int sdebug_driver_probe(struct device * dev)
2982{
2983 int error = 0;
2984 struct sdebug_host_info *sdbg_host;
2985 struct Scsi_Host *hpnt;
2986
2987 sdbg_host = to_sdebug_host(dev);
2988
2989 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
2990 if (NULL == hpnt) {
2991 printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__);
2992 error = -ENODEV;
2993 return error;
2994 }
2995
2996 sdbg_host->shost = hpnt;
2997 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
2998 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
2999 hpnt->max_id = scsi_debug_num_tgts + 1;
3000 else
3001 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003002 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003
3004 error = scsi_add_host(hpnt, &sdbg_host->dev);
3005 if (error) {
3006 printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
3007 error = -ENODEV;
3008 scsi_host_put(hpnt);
3009 } else
3010 scsi_scan_host(hpnt);
3011
3012
3013 return error;
3014}
3015
3016static int sdebug_driver_remove(struct device * dev)
3017{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09003019 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020
3021 sdbg_host = to_sdebug_host(dev);
3022
3023 if (!sdbg_host) {
3024 printk(KERN_ERR "%s: Unable to locate host info\n",
3025 __FUNCTION__);
3026 return -ENODEV;
3027 }
3028
3029 scsi_remove_host(sdbg_host->shost);
3030
FUJITA Tomonori8b402282008-03-20 11:09:18 +09003031 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
3032 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 list_del(&sdbg_devinfo->dev_list);
3034 kfree(sdbg_devinfo);
3035 }
3036
3037 scsi_host_put(sdbg_host->shost);
3038 return 0;
3039}
3040
3041static void sdebug_max_tgts_luns(void)
3042{
3043 struct sdebug_host_info * sdbg_host;
3044 struct Scsi_Host *hpnt;
3045
3046 spin_lock(&sdebug_host_list_lock);
3047 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3048 hpnt = sdbg_host->shost;
3049 if ((hpnt->this_id >= 0) &&
3050 (scsi_debug_num_tgts > hpnt->this_id))
3051 hpnt->max_id = scsi_debug_num_tgts + 1;
3052 else
3053 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003054 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 }
3056 spin_unlock(&sdebug_host_list_lock);
3057}