blob: 5f348e7b1184fafec03c036046b2ef9c6bfe1301 [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{
255 int i;
256
257 switch (*cmd) {
258 case WRITE_16:
259 case READ_16:
260 for (*lba = 0, i = 0; i < 8; ++i) {
261 if (i > 0)
262 *lba <<= 8;
263 *lba += cmd[2 + i];
264 }
265 *num = cmd[13] + (cmd[12] << 8) +
266 (cmd[11] << 16) + (cmd[10] << 24);
267 break;
268 case WRITE_12:
269 case READ_12:
270 *lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
271 *num = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
272 break;
273 case WRITE_10:
274 case READ_10:
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900275 case XDWRITEREAD_10:
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900276 *lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
277 *num = cmd[8] + (cmd[7] << 8);
278 break;
279 case WRITE_6:
280 case READ_6:
281 *lba = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
282 *num = (0 == cmd[4]) ? 256 : cmd[4];
283 break;
284 default:
285 break;
286 }
287}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
290{
291 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
292 printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
293 }
294 return -EINVAL;
295 /* return -ENOTTY; // correct return but upsets fdisk */
296}
297
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400298static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
299 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300{
301 if (devip->reset) {
302 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
303 printk(KERN_INFO "scsi_debug: Reporting Unit "
304 "attention: power on reset\n");
305 devip->reset = 0;
306 mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
307 return check_condition_result;
308 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400309 if ((0 == reset_only) && devip->stopped) {
310 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
311 printk(KERN_INFO "scsi_debug: Reporting Not "
312 "ready: initializing command required\n");
313 mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
314 0x2);
315 return check_condition_result;
316 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 return 0;
318}
319
320/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900321static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 int arr_len)
323{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900324 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900325 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900327 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900329 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 return (DID_ERROR << 16);
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900331
332 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
333 arr, arr_len);
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900334 if (sdb->resid)
335 sdb->resid -= act_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400336 else
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900337 sdb->resid = scsi_bufflen(scp) - act_len;
338
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 return 0;
340}
341
342/* Returns number of bytes fetched into 'arr' or -1 if error. */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900343static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
344 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900346 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900348 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900350
351 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352}
353
354
355static const char * inq_vendor_id = "Linux ";
356static const char * inq_product_id = "scsi_debug ";
357static const char * inq_product_rev = "0004";
358
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200359static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
360 int target_dev_id, int dev_id_num,
361 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400362 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400364 int num, port_a;
365 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400367 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 /* T10 vendor identifier field format (faked) */
369 arr[0] = 0x2; /* ASCII */
370 arr[1] = 0x1;
371 arr[2] = 0x0;
372 memcpy(&arr[4], inq_vendor_id, 8);
373 memcpy(&arr[12], inq_product_id, 16);
374 memcpy(&arr[28], dev_id_str, dev_id_str_len);
375 num = 8 + 16 + dev_id_str_len;
376 arr[3] = num;
377 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400378 if (dev_id_num >= 0) {
379 /* NAA-5, Logical unit identifier (binary) */
380 arr[num++] = 0x1; /* binary (not necessarily sas) */
381 arr[num++] = 0x3; /* PIV=0, lu, naa */
382 arr[num++] = 0x0;
383 arr[num++] = 0x8;
384 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
385 arr[num++] = 0x33;
386 arr[num++] = 0x33;
387 arr[num++] = 0x30;
388 arr[num++] = (dev_id_num >> 24);
389 arr[num++] = (dev_id_num >> 16) & 0xff;
390 arr[num++] = (dev_id_num >> 8) & 0xff;
391 arr[num++] = dev_id_num & 0xff;
392 /* Target relative port number */
393 arr[num++] = 0x61; /* proto=sas, binary */
394 arr[num++] = 0x94; /* PIV=1, target port, rel port */
395 arr[num++] = 0x0; /* reserved */
396 arr[num++] = 0x4; /* length */
397 arr[num++] = 0x0; /* reserved */
398 arr[num++] = 0x0; /* reserved */
399 arr[num++] = 0x0;
400 arr[num++] = 0x1; /* relative port A */
401 }
402 /* NAA-5, Target port identifier */
403 arr[num++] = 0x61; /* proto=sas, binary */
404 arr[num++] = 0x93; /* piv=1, target port, naa */
405 arr[num++] = 0x0;
406 arr[num++] = 0x8;
407 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
408 arr[num++] = 0x22;
409 arr[num++] = 0x22;
410 arr[num++] = 0x20;
411 arr[num++] = (port_a >> 24);
412 arr[num++] = (port_a >> 16) & 0xff;
413 arr[num++] = (port_a >> 8) & 0xff;
414 arr[num++] = port_a & 0xff;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200415 /* NAA-5, Target port group identifier */
416 arr[num++] = 0x61; /* proto=sas, binary */
417 arr[num++] = 0x95; /* piv=1, target port group id */
418 arr[num++] = 0x0;
419 arr[num++] = 0x4;
420 arr[num++] = 0;
421 arr[num++] = 0;
422 arr[num++] = (port_group_id >> 8) & 0xff;
423 arr[num++] = port_group_id & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400424 /* NAA-5, Target device identifier */
425 arr[num++] = 0x61; /* proto=sas, binary */
426 arr[num++] = 0xa3; /* piv=1, target device, naa */
427 arr[num++] = 0x0;
428 arr[num++] = 0x8;
429 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
430 arr[num++] = 0x22;
431 arr[num++] = 0x22;
432 arr[num++] = 0x20;
433 arr[num++] = (target_dev_id >> 24);
434 arr[num++] = (target_dev_id >> 16) & 0xff;
435 arr[num++] = (target_dev_id >> 8) & 0xff;
436 arr[num++] = target_dev_id & 0xff;
437 /* SCSI name string: Target device identifier */
438 arr[num++] = 0x63; /* proto=sas, UTF-8 */
439 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
440 arr[num++] = 0x0;
441 arr[num++] = 24;
442 memcpy(arr + num, "naa.52222220", 12);
443 num += 12;
444 snprintf(b, sizeof(b), "%08X", target_dev_id);
445 memcpy(arr + num, b, 8);
446 num += 8;
447 memset(arr + num, 0, 4);
448 num += 4;
449 return num;
450}
451
452
453static unsigned char vpd84_data[] = {
454/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
455 0x22,0x22,0x22,0x0,0xbb,0x1,
456 0x22,0x22,0x22,0x0,0xbb,0x2,
457};
458
459static int inquiry_evpd_84(unsigned char * arr)
460{
461 memcpy(arr, vpd84_data, sizeof(vpd84_data));
462 return sizeof(vpd84_data);
463}
464
465static int inquiry_evpd_85(unsigned char * arr)
466{
467 int num = 0;
468 const char * na1 = "https://www.kernel.org/config";
469 const char * na2 = "http://www.kernel.org/log";
470 int plen, olen;
471
472 arr[num++] = 0x1; /* lu, storage config */
473 arr[num++] = 0x0; /* reserved */
474 arr[num++] = 0x0;
475 olen = strlen(na1);
476 plen = olen + 1;
477 if (plen % 4)
478 plen = ((plen / 4) + 1) * 4;
479 arr[num++] = plen; /* length, null termianted, padded */
480 memcpy(arr + num, na1, olen);
481 memset(arr + num + olen, 0, plen - olen);
482 num += plen;
483
484 arr[num++] = 0x4; /* lu, logging */
485 arr[num++] = 0x0; /* reserved */
486 arr[num++] = 0x0;
487 olen = strlen(na2);
488 plen = olen + 1;
489 if (plen % 4)
490 plen = ((plen / 4) + 1) * 4;
491 arr[num++] = plen; /* length, null terminated, padded */
492 memcpy(arr + num, na2, olen);
493 memset(arr + num + olen, 0, plen - olen);
494 num += plen;
495
496 return num;
497}
498
499/* SCSI ports VPD page */
500static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
501{
502 int num = 0;
503 int port_a, port_b;
504
505 port_a = target_dev_id + 1;
506 port_b = port_a + 1;
507 arr[num++] = 0x0; /* reserved */
508 arr[num++] = 0x0; /* reserved */
509 arr[num++] = 0x0;
510 arr[num++] = 0x1; /* relative port 1 (primary) */
511 memset(arr + num, 0, 6);
512 num += 6;
513 arr[num++] = 0x0;
514 arr[num++] = 12; /* length tp descriptor */
515 /* naa-5 target port identifier (A) */
516 arr[num++] = 0x61; /* proto=sas, binary */
517 arr[num++] = 0x93; /* PIV=1, target port, NAA */
518 arr[num++] = 0x0; /* reserved */
519 arr[num++] = 0x8; /* length */
520 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
521 arr[num++] = 0x22;
522 arr[num++] = 0x22;
523 arr[num++] = 0x20;
524 arr[num++] = (port_a >> 24);
525 arr[num++] = (port_a >> 16) & 0xff;
526 arr[num++] = (port_a >> 8) & 0xff;
527 arr[num++] = port_a & 0xff;
528
529 arr[num++] = 0x0; /* reserved */
530 arr[num++] = 0x0; /* reserved */
531 arr[num++] = 0x0;
532 arr[num++] = 0x2; /* relative port 2 (secondary) */
533 memset(arr + num, 0, 6);
534 num += 6;
535 arr[num++] = 0x0;
536 arr[num++] = 12; /* length tp descriptor */
537 /* naa-5 target port identifier (B) */
538 arr[num++] = 0x61; /* proto=sas, binary */
539 arr[num++] = 0x93; /* PIV=1, target port, NAA */
540 arr[num++] = 0x0; /* reserved */
541 arr[num++] = 0x8; /* length */
542 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
543 arr[num++] = 0x22;
544 arr[num++] = 0x22;
545 arr[num++] = 0x20;
546 arr[num++] = (port_b >> 24);
547 arr[num++] = (port_b >> 16) & 0xff;
548 arr[num++] = (port_b >> 8) & 0xff;
549 arr[num++] = port_b & 0xff;
550
551 return num;
552}
553
554
555static unsigned char vpd89_data[] = {
556/* from 4th byte */ 0,0,0,0,
557'l','i','n','u','x',' ',' ',' ',
558'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
559'1','2','3','4',
5600x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
5610xec,0,0,0,
5620x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
5630,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
5640x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
5650x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
5660x53,0x41,
5670x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
5680x20,0x20,
5690x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
5700x10,0x80,
5710,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
5720x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
5730x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
5740,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
5750x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
5760x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
5770,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
5780,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5790,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5800,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5810x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
5820,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
5830xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
5840,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
5850,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5860,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5870,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5880,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5890,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5900,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5910,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5920,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5930,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5940,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5950,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5960,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
597};
598
599static int inquiry_evpd_89(unsigned char * arr)
600{
601 memcpy(arr, vpd89_data, sizeof(vpd89_data));
602 return sizeof(vpd89_data);
603}
604
605
606static unsigned char vpdb0_data[] = {
607 /* from 4th byte */ 0,0,0,4,
608 0,0,0x4,0,
609 0,0,0,64,
610};
611
612static int inquiry_evpd_b0(unsigned char * arr)
613{
614 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
615 if (sdebug_store_sectors > 0x400) {
616 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
617 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
618 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
619 arr[7] = sdebug_store_sectors & 0xff;
620 }
621 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622}
623
624
625#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400626#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627
628static int resp_inquiry(struct scsi_cmnd * scp, int target,
629 struct sdebug_dev_info * devip)
630{
631 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200632 unsigned char * arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 unsigned char *cmd = (unsigned char *)scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200634 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
636 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500637 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
638 if (! arr)
639 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400640 if (devip->wlun)
641 pq_pdt = 0x1e; /* present, wlun */
642 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
643 pq_pdt = 0x7f; /* not present, no device type */
644 else
645 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 arr[0] = pq_pdt;
647 if (0x2 & cmd[1]) { /* CMDDT bit set */
648 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
649 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200650 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 return check_condition_result;
652 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200653 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400654 char lu_id_str[6];
655 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200657 port_group_id = (((host_no + 1) & 0x7f) << 8) +
658 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -0400659 if (0 == scsi_debug_vpd_use_hostno)
660 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400661 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
662 (devip->target * 1000) + devip->lun);
663 target_dev_id = ((host_no + 1) * 2000) +
664 (devip->target * 1000) - 3;
665 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400667 arr[1] = cmd[2]; /*sanity */
668 n = 4;
669 arr[n++] = 0x0; /* this page */
670 arr[n++] = 0x80; /* unit serial number */
671 arr[n++] = 0x83; /* device identification */
672 arr[n++] = 0x84; /* software interface ident. */
673 arr[n++] = 0x85; /* management network addresses */
674 arr[n++] = 0x86; /* extended inquiry */
675 arr[n++] = 0x87; /* mode page policy */
676 arr[n++] = 0x88; /* SCSI ports */
677 arr[n++] = 0x89; /* ATA information */
678 arr[n++] = 0xb0; /* Block limits (SBC) */
679 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400681 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400683 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400685 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200686 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
687 target_dev_id, lu_id_num,
688 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400689 } else if (0x84 == cmd[2]) { /* Software interface ident. */
690 arr[1] = cmd[2]; /*sanity */
691 arr[3] = inquiry_evpd_84(&arr[4]);
692 } else if (0x85 == cmd[2]) { /* Management network addresses */
693 arr[1] = cmd[2]; /*sanity */
694 arr[3] = inquiry_evpd_85(&arr[4]);
695 } else if (0x86 == cmd[2]) { /* extended inquiry */
696 arr[1] = cmd[2]; /*sanity */
697 arr[3] = 0x3c; /* number of following entries */
698 arr[4] = 0x0; /* no protection stuff */
699 arr[5] = 0x7; /* head of q, ordered + simple q's */
700 } else if (0x87 == cmd[2]) { /* mode page policy */
701 arr[1] = cmd[2]; /*sanity */
702 arr[3] = 0x8; /* number of following entries */
703 arr[4] = 0x2; /* disconnect-reconnect mp */
704 arr[6] = 0x80; /* mlus, shared */
705 arr[8] = 0x18; /* protocol specific lu */
706 arr[10] = 0x82; /* mlus, per initiator port */
707 } else if (0x88 == cmd[2]) { /* SCSI Ports */
708 arr[1] = cmd[2]; /*sanity */
709 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
710 } else if (0x89 == cmd[2]) { /* ATA information */
711 arr[1] = cmd[2]; /*sanity */
712 n = inquiry_evpd_89(&arr[4]);
713 arr[2] = (n >> 8);
714 arr[3] = (n & 0xff);
715 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
716 arr[1] = cmd[2]; /*sanity */
717 arr[3] = inquiry_evpd_b0(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 } else {
719 /* Illegal request, invalid field in cdb */
720 mk_sense_buffer(devip, ILLEGAL_REQUEST,
721 INVALID_FIELD_IN_CDB, 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200722 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 return check_condition_result;
724 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400725 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200726 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400727 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200728 kfree(arr);
729 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 }
731 /* drops through here for a standard inquiry */
732 arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
733 arr[2] = scsi_debug_scsi_level;
734 arr[3] = 2; /* response_data_format==2 */
735 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200736 if (0 == scsi_debug_vpd_use_hostno)
737 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400738 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400740 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 memcpy(&arr[8], inq_vendor_id, 8);
742 memcpy(&arr[16], inq_product_id, 16);
743 memcpy(&arr[32], inq_product_rev, 4);
744 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400745 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
746 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
747 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400749 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400751 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400753 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200754 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200756 kfree(arr);
757 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758}
759
760static int resp_requests(struct scsi_cmnd * scp,
761 struct sdebug_dev_info * devip)
762{
763 unsigned char * sbuff;
764 unsigned char *cmd = (unsigned char *)scp->cmnd;
765 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400766 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 int len = 18;
768
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400769 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400771 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
772 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400774 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
775 if (want_dsense) {
776 arr[0] = 0x72;
777 arr[1] = 0x0; /* NO_SENSE in sense_key */
778 arr[2] = THRESHOLD_EXCEEDED;
779 arr[3] = 0xff; /* TEST set and MRIE==6 */
780 } else {
781 arr[0] = 0x70;
782 arr[2] = 0x0; /* NO_SENSE in sense_key */
783 arr[7] = 0xa; /* 18 byte sense buffer */
784 arr[12] = THRESHOLD_EXCEEDED;
785 arr[13] = 0xff; /* TEST set and MRIE==6 */
786 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400787 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400789 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
790 /* DESC bit set and sense_buff in fixed format */
791 memset(arr, 0, sizeof(arr));
792 arr[0] = 0x72;
793 arr[1] = sbuff[2]; /* sense key */
794 arr[2] = sbuff[12]; /* asc */
795 arr[3] = sbuff[13]; /* ascq */
796 len = 8;
797 }
798 }
799 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 return fill_from_dev_buffer(scp, arr, len);
801}
802
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400803static int resp_start_stop(struct scsi_cmnd * scp,
804 struct sdebug_dev_info * devip)
805{
806 unsigned char *cmd = (unsigned char *)scp->cmnd;
807 int power_cond, errsts, start;
808
809 if ((errsts = check_readiness(scp, 1, devip)))
810 return errsts;
811 power_cond = (cmd[4] & 0xf0) >> 4;
812 if (power_cond) {
813 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
814 0);
815 return check_condition_result;
816 }
817 start = cmd[4] & 1;
818 if (start == devip->stopped)
819 devip->stopped = !start;
820 return 0;
821}
822
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823#define SDEBUG_READCAP_ARR_SZ 8
824static int resp_readcap(struct scsi_cmnd * scp,
825 struct sdebug_dev_info * devip)
826{
827 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400828 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 int errsts;
830
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400831 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400833 /* following just in case virtual_gb changed */
834 if (scsi_debug_virtual_gb > 0) {
835 sdebug_capacity = 2048 * 1024;
836 sdebug_capacity *= scsi_debug_virtual_gb;
837 } else
838 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400840 if (sdebug_capacity < 0xffffffff) {
841 capac = (unsigned int)sdebug_capacity - 1;
842 arr[0] = (capac >> 24);
843 arr[1] = (capac >> 16) & 0xff;
844 arr[2] = (capac >> 8) & 0xff;
845 arr[3] = capac & 0xff;
846 } else {
847 arr[0] = 0xff;
848 arr[1] = 0xff;
849 arr[2] = 0xff;
850 arr[3] = 0xff;
851 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
853 arr[7] = SECT_SIZE_PER(target) & 0xff;
854 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
855}
856
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400857#define SDEBUG_READCAP16_ARR_SZ 32
858static int resp_readcap16(struct scsi_cmnd * scp,
859 struct sdebug_dev_info * devip)
860{
861 unsigned char *cmd = (unsigned char *)scp->cmnd;
862 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
863 unsigned long long capac;
864 int errsts, k, alloc_len;
865
866 if ((errsts = check_readiness(scp, 1, devip)))
867 return errsts;
868 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
869 + cmd[13]);
870 /* following just in case virtual_gb changed */
871 if (scsi_debug_virtual_gb > 0) {
872 sdebug_capacity = 2048 * 1024;
873 sdebug_capacity *= scsi_debug_virtual_gb;
874 } else
875 sdebug_capacity = sdebug_store_sectors;
876 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
877 capac = sdebug_capacity - 1;
878 for (k = 0; k < 8; ++k, capac >>= 8)
879 arr[7 - k] = capac & 0xff;
880 arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff;
881 arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff;
882 arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff;
883 arr[11] = SECT_SIZE_PER(target) & 0xff;
884 return fill_from_dev_buffer(scp, arr,
885 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
886}
887
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200888#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
889
890static int resp_report_tgtpgs(struct scsi_cmnd * scp,
891 struct sdebug_dev_info * devip)
892{
893 unsigned char *cmd = (unsigned char *)scp->cmnd;
894 unsigned char * arr;
895 int host_no = devip->sdbg_host->shost->host_no;
896 int n, ret, alen, rlen;
897 int port_group_a, port_group_b, port_a, port_b;
898
899 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
900 + cmd[9]);
901
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500902 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
903 if (! arr)
904 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200905 /*
906 * EVPD page 0x88 states we have two ports, one
907 * real and a fake port with no device connected.
908 * So we create two port groups with one port each
909 * and set the group with port B to unavailable.
910 */
911 port_a = 0x1; /* relative port A */
912 port_b = 0x2; /* relative port B */
913 port_group_a = (((host_no + 1) & 0x7f) << 8) +
914 (devip->channel & 0x7f);
915 port_group_b = (((host_no + 1) & 0x7f) << 8) +
916 (devip->channel & 0x7f) + 0x80;
917
918 /*
919 * The asymmetric access state is cycled according to the host_id.
920 */
921 n = 4;
922 if (0 == scsi_debug_vpd_use_hostno) {
923 arr[n++] = host_no % 3; /* Asymm access state */
924 arr[n++] = 0x0F; /* claim: all states are supported */
925 } else {
926 arr[n++] = 0x0; /* Active/Optimized path */
927 arr[n++] = 0x01; /* claim: only support active/optimized paths */
928 }
929 arr[n++] = (port_group_a >> 8) & 0xff;
930 arr[n++] = port_group_a & 0xff;
931 arr[n++] = 0; /* Reserved */
932 arr[n++] = 0; /* Status code */
933 arr[n++] = 0; /* Vendor unique */
934 arr[n++] = 0x1; /* One port per group */
935 arr[n++] = 0; /* Reserved */
936 arr[n++] = 0; /* Reserved */
937 arr[n++] = (port_a >> 8) & 0xff;
938 arr[n++] = port_a & 0xff;
939 arr[n++] = 3; /* Port unavailable */
940 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
941 arr[n++] = (port_group_b >> 8) & 0xff;
942 arr[n++] = port_group_b & 0xff;
943 arr[n++] = 0; /* Reserved */
944 arr[n++] = 0; /* Status code */
945 arr[n++] = 0; /* Vendor unique */
946 arr[n++] = 0x1; /* One port per group */
947 arr[n++] = 0; /* Reserved */
948 arr[n++] = 0; /* Reserved */
949 arr[n++] = (port_b >> 8) & 0xff;
950 arr[n++] = port_b & 0xff;
951
952 rlen = n - 4;
953 arr[0] = (rlen >> 24) & 0xff;
954 arr[1] = (rlen >> 16) & 0xff;
955 arr[2] = (rlen >> 8) & 0xff;
956 arr[3] = rlen & 0xff;
957
958 /*
959 * Return the smallest value of either
960 * - The allocated length
961 * - The constructed command length
962 * - The maximum array size
963 */
964 rlen = min(alen,n);
965 ret = fill_from_dev_buffer(scp, arr,
966 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
967 kfree(arr);
968 return ret;
969}
970
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971/* <<Following mode page info copied from ST318451LW>> */
972
973static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
974{ /* Read-Write Error Recovery page for mode_sense */
975 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
976 5, 0, 0xff, 0xff};
977
978 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
979 if (1 == pcontrol)
980 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
981 return sizeof(err_recov_pg);
982}
983
984static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
985{ /* Disconnect-Reconnect page for mode_sense */
986 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
987 0, 0, 0, 0, 0, 0, 0, 0};
988
989 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
990 if (1 == pcontrol)
991 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
992 return sizeof(disconnect_pg);
993}
994
995static int resp_format_pg(unsigned char * p, int pcontrol, int target)
996{ /* Format device page for mode_sense */
997 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
998 0, 0, 0, 0, 0, 0, 0, 0,
999 0, 0, 0, 0, 0x40, 0, 0, 0};
1000
1001 memcpy(p, format_pg, sizeof(format_pg));
1002 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1003 p[11] = sdebug_sectors_per & 0xff;
1004 p[12] = (SECT_SIZE >> 8) & 0xff;
1005 p[13] = SECT_SIZE & 0xff;
1006 if (DEV_REMOVEABLE(target))
1007 p[20] |= 0x20; /* should agree with INQUIRY */
1008 if (1 == pcontrol)
1009 memset(p + 2, 0, sizeof(format_pg) - 2);
1010 return sizeof(format_pg);
1011}
1012
1013static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1014{ /* Caching page for mode_sense */
1015 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1016 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1017
1018 memcpy(p, caching_pg, sizeof(caching_pg));
1019 if (1 == pcontrol)
1020 memset(p + 2, 0, sizeof(caching_pg) - 2);
1021 return sizeof(caching_pg);
1022}
1023
1024static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1025{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001026 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1027 0, 0, 0, 0};
1028 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 0, 0, 0x2, 0x4b};
1030
1031 if (scsi_debug_dsense)
1032 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001033 else
1034 ctrl_m_pg[2] &= ~0x4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1036 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001037 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1038 else if (2 == pcontrol)
1039 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 return sizeof(ctrl_m_pg);
1041}
1042
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001043
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1045{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001046 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1047 0, 0, 0x0, 0x0};
1048 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1049 0, 0, 0x0, 0x0};
1050
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1052 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001053 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1054 else if (2 == pcontrol)
1055 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 return sizeof(iec_m_pg);
1057}
1058
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001059static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1060{ /* SAS SSP mode page - short format for mode_sense */
1061 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1062 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1063
1064 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1065 if (1 == pcontrol)
1066 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1067 return sizeof(sas_sf_m_pg);
1068}
1069
1070
1071static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1072 int target_dev_id)
1073{ /* SAS phy control and discover mode page for mode_sense */
1074 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1075 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1076 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1077 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1078 0x2, 0, 0, 0, 0, 0, 0, 0,
1079 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1080 0, 0, 0, 0, 0, 0, 0, 0,
1081 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1082 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1083 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1084 0x3, 0, 0, 0, 0, 0, 0, 0,
1085 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1086 0, 0, 0, 0, 0, 0, 0, 0,
1087 };
1088 int port_a, port_b;
1089
1090 port_a = target_dev_id + 1;
1091 port_b = port_a + 1;
1092 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1093 p[20] = (port_a >> 24);
1094 p[21] = (port_a >> 16) & 0xff;
1095 p[22] = (port_a >> 8) & 0xff;
1096 p[23] = port_a & 0xff;
1097 p[48 + 20] = (port_b >> 24);
1098 p[48 + 21] = (port_b >> 16) & 0xff;
1099 p[48 + 22] = (port_b >> 8) & 0xff;
1100 p[48 + 23] = port_b & 0xff;
1101 if (1 == pcontrol)
1102 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1103 return sizeof(sas_pcd_m_pg);
1104}
1105
1106static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1107{ /* SAS SSP shared protocol specific port mode subpage */
1108 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1109 0, 0, 0, 0, 0, 0, 0, 0,
1110 };
1111
1112 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1113 if (1 == pcontrol)
1114 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1115 return sizeof(sas_sha_m_pg);
1116}
1117
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118#define SDEBUG_MAX_MSENSE_SZ 256
1119
1120static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1121 struct sdebug_dev_info * devip)
1122{
Douglas Gilbert23183912006-09-16 20:30:47 -04001123 unsigned char dbd, llbaa;
1124 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001126 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 unsigned char * ap;
1128 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1129 unsigned char *cmd = (unsigned char *)scp->cmnd;
1130
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001131 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001133 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 pcontrol = (cmd[2] & 0xc0) >> 6;
1135 pcode = cmd[2] & 0x3f;
1136 subpcode = cmd[3];
1137 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001138 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1139 if ((0 == scsi_debug_ptype) && (0 == dbd))
1140 bd_len = llbaa ? 16 : 8;
1141 else
1142 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1144 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1145 if (0x3 == pcontrol) { /* Saving values not supported */
1146 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1147 0);
1148 return check_condition_result;
1149 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001150 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1151 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001152 /* set DPOFUA bit for disks */
1153 if (0 == scsi_debug_ptype)
1154 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1155 else
1156 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 if (msense_6) {
1158 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001159 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 offset = 4;
1161 } else {
1162 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001163 if (16 == bd_len)
1164 arr[4] = 0x1; /* set LONGLBA bit */
1165 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 offset = 8;
1167 }
1168 ap = arr + offset;
Douglas Gilbert23183912006-09-16 20:30:47 -04001169 if ((bd_len > 0) && (0 == sdebug_capacity)) {
1170 if (scsi_debug_virtual_gb > 0) {
1171 sdebug_capacity = 2048 * 1024;
1172 sdebug_capacity *= scsi_debug_virtual_gb;
1173 } else
1174 sdebug_capacity = sdebug_store_sectors;
1175 }
1176 if (8 == bd_len) {
1177 if (sdebug_capacity > 0xfffffffe) {
1178 ap[0] = 0xff;
1179 ap[1] = 0xff;
1180 ap[2] = 0xff;
1181 ap[3] = 0xff;
1182 } else {
1183 ap[0] = (sdebug_capacity >> 24) & 0xff;
1184 ap[1] = (sdebug_capacity >> 16) & 0xff;
1185 ap[2] = (sdebug_capacity >> 8) & 0xff;
1186 ap[3] = sdebug_capacity & 0xff;
1187 }
1188 ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1189 ap[7] = SECT_SIZE_PER(target) & 0xff;
1190 offset += bd_len;
1191 ap = arr + offset;
1192 } else if (16 == bd_len) {
1193 unsigned long long capac = sdebug_capacity;
1194
1195 for (k = 0; k < 8; ++k, capac >>= 8)
1196 ap[7 - k] = capac & 0xff;
1197 ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff;
1198 ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff;
1199 ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1200 ap[15] = SECT_SIZE_PER(target) & 0xff;
1201 offset += bd_len;
1202 ap = arr + offset;
1203 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001205 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1206 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1208 0);
1209 return check_condition_result;
1210 }
1211 switch (pcode) {
1212 case 0x1: /* Read-Write error recovery page, direct access */
1213 len = resp_err_recov_pg(ap, pcontrol, target);
1214 offset += len;
1215 break;
1216 case 0x2: /* Disconnect-Reconnect page, all devices */
1217 len = resp_disconnect_pg(ap, pcontrol, target);
1218 offset += len;
1219 break;
1220 case 0x3: /* Format device page, direct access */
1221 len = resp_format_pg(ap, pcontrol, target);
1222 offset += len;
1223 break;
1224 case 0x8: /* Caching page, direct access */
1225 len = resp_caching_pg(ap, pcontrol, target);
1226 offset += len;
1227 break;
1228 case 0xa: /* Control Mode page, all devices */
1229 len = resp_ctrl_m_pg(ap, pcontrol, target);
1230 offset += len;
1231 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001232 case 0x19: /* if spc==1 then sas phy, control+discover */
1233 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1234 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1235 INVALID_FIELD_IN_CDB, 0);
1236 return check_condition_result;
1237 }
1238 len = 0;
1239 if ((0x0 == subpcode) || (0xff == subpcode))
1240 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1241 if ((0x1 == subpcode) || (0xff == subpcode))
1242 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1243 target_dev_id);
1244 if ((0x2 == subpcode) || (0xff == subpcode))
1245 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1246 offset += len;
1247 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 case 0x1c: /* Informational Exceptions Mode page, all devices */
1249 len = resp_iec_m_pg(ap, pcontrol, target);
1250 offset += len;
1251 break;
1252 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001253 if ((0 == subpcode) || (0xff == subpcode)) {
1254 len = resp_err_recov_pg(ap, pcontrol, target);
1255 len += resp_disconnect_pg(ap + len, pcontrol, target);
1256 len += resp_format_pg(ap + len, pcontrol, target);
1257 len += resp_caching_pg(ap + len, pcontrol, target);
1258 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1259 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1260 if (0xff == subpcode) {
1261 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1262 target, target_dev_id);
1263 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1264 }
1265 len += resp_iec_m_pg(ap + len, pcontrol, target);
1266 } else {
1267 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1268 INVALID_FIELD_IN_CDB, 0);
1269 return check_condition_result;
1270 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 offset += len;
1272 break;
1273 default:
1274 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1275 0);
1276 return check_condition_result;
1277 }
1278 if (msense_6)
1279 arr[0] = offset - 1;
1280 else {
1281 arr[0] = ((offset - 2) >> 8) & 0xff;
1282 arr[1] = (offset - 2) & 0xff;
1283 }
1284 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1285}
1286
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001287#define SDEBUG_MAX_MSELECT_SZ 512
1288
1289static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1290 struct sdebug_dev_info * devip)
1291{
1292 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1293 int param_len, res, errsts, mpage;
1294 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1295 unsigned char *cmd = (unsigned char *)scp->cmnd;
1296
1297 if ((errsts = check_readiness(scp, 1, devip)))
1298 return errsts;
1299 memset(arr, 0, sizeof(arr));
1300 pf = cmd[1] & 0x10;
1301 sp = cmd[1] & 0x1;
1302 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1303 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1304 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1305 INVALID_FIELD_IN_CDB, 0);
1306 return check_condition_result;
1307 }
1308 res = fetch_to_dev_buffer(scp, arr, param_len);
1309 if (-1 == res)
1310 return (DID_ERROR << 16);
1311 else if ((res < param_len) &&
1312 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1313 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1314 " IO sent=%d bytes\n", param_len, res);
1315 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1316 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001317 if (md_len > 2) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001318 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1319 INVALID_FIELD_IN_PARAM_LIST, 0);
1320 return check_condition_result;
1321 }
1322 off = bd_len + (mselect6 ? 4 : 8);
1323 mpage = arr[off] & 0x3f;
1324 ps = !!(arr[off] & 0x80);
1325 if (ps) {
1326 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1327 INVALID_FIELD_IN_PARAM_LIST, 0);
1328 return check_condition_result;
1329 }
1330 spf = !!(arr[off] & 0x40);
1331 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1332 (arr[off + 1] + 2);
1333 if ((pg_len + off) > param_len) {
1334 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1335 PARAMETER_LIST_LENGTH_ERR, 0);
1336 return check_condition_result;
1337 }
1338 switch (mpage) {
1339 case 0xa: /* Control Mode page */
1340 if (ctrl_m_pg[1] == arr[off + 1]) {
1341 memcpy(ctrl_m_pg + 2, arr + off + 2,
1342 sizeof(ctrl_m_pg) - 2);
1343 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1344 return 0;
1345 }
1346 break;
1347 case 0x1c: /* Informational Exceptions Mode page */
1348 if (iec_m_pg[1] == arr[off + 1]) {
1349 memcpy(iec_m_pg + 2, arr + off + 2,
1350 sizeof(iec_m_pg) - 2);
1351 return 0;
1352 }
1353 break;
1354 default:
1355 break;
1356 }
1357 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1358 INVALID_FIELD_IN_PARAM_LIST, 0);
1359 return check_condition_result;
1360}
1361
1362static int resp_temp_l_pg(unsigned char * arr)
1363{
1364 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1365 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1366 };
1367
1368 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1369 return sizeof(temp_l_pg);
1370}
1371
1372static int resp_ie_l_pg(unsigned char * arr)
1373{
1374 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1375 };
1376
1377 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1378 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1379 arr[4] = THRESHOLD_EXCEEDED;
1380 arr[5] = 0xff;
1381 }
1382 return sizeof(ie_l_pg);
1383}
1384
1385#define SDEBUG_MAX_LSENSE_SZ 512
1386
1387static int resp_log_sense(struct scsi_cmnd * scp,
1388 struct sdebug_dev_info * devip)
1389{
Douglas Gilbert23183912006-09-16 20:30:47 -04001390 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001391 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1392 unsigned char *cmd = (unsigned char *)scp->cmnd;
1393
1394 if ((errsts = check_readiness(scp, 1, devip)))
1395 return errsts;
1396 memset(arr, 0, sizeof(arr));
1397 ppc = cmd[1] & 0x2;
1398 sp = cmd[1] & 0x1;
1399 if (ppc || sp) {
1400 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1401 INVALID_FIELD_IN_CDB, 0);
1402 return check_condition_result;
1403 }
1404 pcontrol = (cmd[2] & 0xc0) >> 6;
1405 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001406 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001407 alloc_len = (cmd[7] << 8) + cmd[8];
1408 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001409 if (0 == subpcode) {
1410 switch (pcode) {
1411 case 0x0: /* Supported log pages log page */
1412 n = 4;
1413 arr[n++] = 0x0; /* this page */
1414 arr[n++] = 0xd; /* Temperature */
1415 arr[n++] = 0x2f; /* Informational exceptions */
1416 arr[3] = n - 4;
1417 break;
1418 case 0xd: /* Temperature log page */
1419 arr[3] = resp_temp_l_pg(arr + 4);
1420 break;
1421 case 0x2f: /* Informational exceptions log page */
1422 arr[3] = resp_ie_l_pg(arr + 4);
1423 break;
1424 default:
1425 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1426 INVALID_FIELD_IN_CDB, 0);
1427 return check_condition_result;
1428 }
1429 } else if (0xff == subpcode) {
1430 arr[0] |= 0x40;
1431 arr[1] = subpcode;
1432 switch (pcode) {
1433 case 0x0: /* Supported log pages and subpages log page */
1434 n = 4;
1435 arr[n++] = 0x0;
1436 arr[n++] = 0x0; /* 0,0 page */
1437 arr[n++] = 0x0;
1438 arr[n++] = 0xff; /* this page */
1439 arr[n++] = 0xd;
1440 arr[n++] = 0x0; /* Temperature */
1441 arr[n++] = 0x2f;
1442 arr[n++] = 0x0; /* Informational exceptions */
1443 arr[3] = n - 4;
1444 break;
1445 case 0xd: /* Temperature subpages */
1446 n = 4;
1447 arr[n++] = 0xd;
1448 arr[n++] = 0x0; /* Temperature */
1449 arr[3] = n - 4;
1450 break;
1451 case 0x2f: /* Informational exceptions subpages */
1452 n = 4;
1453 arr[n++] = 0x2f;
1454 arr[n++] = 0x0; /* Informational exceptions */
1455 arr[3] = n - 4;
1456 break;
1457 default:
1458 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1459 INVALID_FIELD_IN_CDB, 0);
1460 return check_condition_result;
1461 }
1462 } else {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001463 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1464 INVALID_FIELD_IN_CDB, 0);
1465 return check_condition_result;
1466 }
1467 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1468 return fill_from_dev_buffer(scp, arr,
1469 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1470}
1471
1472static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
1473 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474{
1475 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001476 unsigned int block, from_bottom;
1477 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 int ret;
1479
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001480 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1482 0);
1483 return check_condition_result;
1484 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001485 /* transfer length excessive (tie in to block limits VPD page) */
1486 if (num > sdebug_store_sectors) {
1487 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1488 0);
1489 return check_condition_result;
1490 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001492 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1493 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1494 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1496 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001497 /* set info field and valid bit for fixed descriptor */
1498 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1499 devip->sense_buff[0] |= 0x80; /* Valid bit */
1500 ret = OPT_MEDIUM_ERR_ADDR;
1501 devip->sense_buff[3] = (ret >> 24) & 0xff;
1502 devip->sense_buff[4] = (ret >> 16) & 0xff;
1503 devip->sense_buff[5] = (ret >> 8) & 0xff;
1504 devip->sense_buff[6] = ret & 0xff;
1505 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 return check_condition_result;
1507 }
1508 read_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001509 if ((lba + num) <= sdebug_store_sectors)
1510 ret = fill_from_dev_buffer(SCpnt,
1511 fake_storep + (lba * SECT_SIZE),
1512 num * SECT_SIZE);
1513 else {
1514 /* modulo when one arg is 64 bits needs do_div() */
1515 u = lba;
1516 block = do_div(u, sdebug_store_sectors);
1517 from_bottom = 0;
1518 if ((block + num) > sdebug_store_sectors)
1519 from_bottom = (block + num) - sdebug_store_sectors;
1520 ret = fill_from_dev_buffer(SCpnt,
1521 fake_storep + (block * SECT_SIZE),
1522 (num - from_bottom) * SECT_SIZE);
1523 if ((0 == ret) && (from_bottom > 0))
1524 ret = fill_from_dev_buffer(SCpnt, fake_storep,
1525 from_bottom * SECT_SIZE);
1526 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 read_unlock_irqrestore(&atomic_rw, iflags);
1528 return ret;
1529}
1530
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001531static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
1532 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533{
1534 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001535 unsigned int block, to_bottom;
1536 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 int res;
1538
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001539 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1541 0);
1542 return check_condition_result;
1543 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001544 /* transfer length excessive (tie in to block limits VPD page) */
1545 if (num > sdebug_store_sectors) {
1546 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1547 0);
1548 return check_condition_result;
1549 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550
1551 write_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001552 if ((lba + num) <= sdebug_store_sectors)
1553 res = fetch_to_dev_buffer(SCpnt,
1554 fake_storep + (lba * SECT_SIZE),
1555 num * SECT_SIZE);
1556 else {
1557 /* modulo when one arg is 64 bits needs do_div() */
1558 u = lba;
1559 block = do_div(u, sdebug_store_sectors);
1560 to_bottom = 0;
1561 if ((block + num) > sdebug_store_sectors)
1562 to_bottom = (block + num) - sdebug_store_sectors;
1563 res = fetch_to_dev_buffer(SCpnt,
1564 fake_storep + (block * SECT_SIZE),
1565 (num - to_bottom) * SECT_SIZE);
1566 if ((0 == res) && (to_bottom > 0))
1567 res = fetch_to_dev_buffer(SCpnt, fake_storep,
1568 to_bottom * SECT_SIZE);
1569 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 write_unlock_irqrestore(&atomic_rw, iflags);
1571 if (-1 == res)
1572 return (DID_ERROR << 16);
1573 else if ((res < (num * SECT_SIZE)) &&
1574 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001575 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 " IO sent=%d bytes\n", num * SECT_SIZE, res);
1577 return 0;
1578}
1579
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001580#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581
1582static int resp_report_luns(struct scsi_cmnd * scp,
1583 struct sdebug_dev_info * devip)
1584{
1585 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001586 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 unsigned char *cmd = (unsigned char *)scp->cmnd;
1588 int select_report = (int)cmd[2];
1589 struct scsi_lun *one_lun;
1590 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001591 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592
1593 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001594 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1596 0);
1597 return check_condition_result;
1598 }
1599 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
1600 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
1601 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001602 if (1 == select_report)
1603 lun_cnt = 0;
1604 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
1605 --lun_cnt;
1606 wlun = (select_report > 0) ? 1 : 0;
1607 num = lun_cnt + wlun;
1608 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
1609 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
1610 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
1611 sizeof(struct scsi_lun)), num);
1612 if (n < num) {
1613 wlun = 0;
1614 lun_cnt = n;
1615 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001617 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
1618 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
1619 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
1620 i++, lun++) {
1621 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 if (upper)
1623 one_lun[i].scsi_lun[0] =
1624 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001625 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001627 if (wlun) {
1628 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
1629 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
1630 i++;
1631 }
1632 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 return fill_from_dev_buffer(scp, arr,
1634 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
1635}
1636
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001637static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
1638 unsigned int num, struct sdebug_dev_info *devip)
1639{
1640 int i, j, ret = -1;
1641 unsigned char *kaddr, *buf;
1642 unsigned int offset;
1643 struct scatterlist *sg;
1644 struct scsi_data_buffer *sdb = scsi_in(scp);
1645
1646 /* better not to use temporary buffer. */
1647 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
1648 if (!buf)
1649 return ret;
1650
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001651 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001652
1653 offset = 0;
1654 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
1655 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
1656 if (!kaddr)
1657 goto out;
1658
1659 for (j = 0; j < sg->length; j++)
1660 *(kaddr + sg->offset + j) ^= *(buf + offset + j);
1661
1662 offset += sg->length;
1663 kunmap_atomic(kaddr, KM_USER0);
1664 }
1665 ret = 0;
1666out:
1667 kfree(buf);
1668
1669 return ret;
1670}
1671
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672/* When timer goes off this function is called. */
1673static void timer_intr_handler(unsigned long indx)
1674{
1675 struct sdebug_queued_cmd * sqcp;
1676 unsigned long iflags;
1677
1678 if (indx >= SCSI_DEBUG_CANQUEUE) {
1679 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
1680 "large\n");
1681 return;
1682 }
1683 spin_lock_irqsave(&queued_arr_lock, iflags);
1684 sqcp = &queued_arr[(int)indx];
1685 if (! sqcp->in_use) {
1686 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
1687 "interrupt\n");
1688 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1689 return;
1690 }
1691 sqcp->in_use = 0;
1692 if (sqcp->done_funct) {
1693 sqcp->a_cmnd->result = sqcp->scsi_result;
1694 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
1695 }
1696 sqcp->done_funct = NULL;
1697 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1698}
1699
1700static int scsi_debug_slave_alloc(struct scsi_device * sdp)
1701{
1702 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001703 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
1704 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001705 set_bit(QUEUE_FLAG_BIDI, &sdp->request_queue->queue_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 return 0;
1707}
1708
1709static int scsi_debug_slave_configure(struct scsi_device * sdp)
1710{
1711 struct sdebug_dev_info * devip;
1712
1713 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001714 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
1715 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
1717 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
1718 devip = devInfoReg(sdp);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001719 if (NULL == devip)
1720 return 1; /* no resources, will be marked offline */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 sdp->hostdata = devip;
1722 if (sdp->host->cmd_per_lun)
1723 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
1724 sdp->host->cmd_per_lun);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001725 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 return 0;
1727}
1728
1729static void scsi_debug_slave_destroy(struct scsi_device * sdp)
1730{
1731 struct sdebug_dev_info * devip =
1732 (struct sdebug_dev_info *)sdp->hostdata;
1733
1734 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001735 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
1736 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 if (devip) {
1738 /* make this slot avaliable for re-use */
1739 devip->used = 0;
1740 sdp->hostdata = NULL;
1741 }
1742}
1743
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09001744struct sdebug_dev_info *sdebug_device_create(struct sdebug_host_info *sdbg_host,
1745 gfp_t flags)
1746{
1747 struct sdebug_dev_info *devip;
1748
1749 devip = kzalloc(sizeof(*devip), flags);
1750 if (devip) {
1751 devip->sdbg_host = sdbg_host;
1752 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
1753 }
1754 return devip;
1755}
1756
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
1758{
1759 struct sdebug_host_info * sdbg_host;
1760 struct sdebug_dev_info * open_devip = NULL;
1761 struct sdebug_dev_info * devip =
1762 (struct sdebug_dev_info *)sdev->hostdata;
1763
1764 if (devip)
1765 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09001766 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
1767 if (!sdbg_host) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 printk(KERN_ERR "Host info NULL\n");
1769 return NULL;
1770 }
1771 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
1772 if ((devip->used) && (devip->channel == sdev->channel) &&
1773 (devip->target == sdev->id) &&
1774 (devip->lun == sdev->lun))
1775 return devip;
1776 else {
1777 if ((!devip->used) && (!open_devip))
1778 open_devip = devip;
1779 }
1780 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09001781 if (!open_devip) { /* try and make a new one */
1782 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
1783 if (!open_devip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 printk(KERN_ERR "%s: out of memory at line %d\n",
1785 __FUNCTION__, __LINE__);
1786 return NULL;
1787 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09001789
1790 open_devip->channel = sdev->channel;
1791 open_devip->target = sdev->id;
1792 open_devip->lun = sdev->lun;
1793 open_devip->sdbg_host = sdbg_host;
1794 open_devip->reset = 1;
1795 open_devip->used = 1;
1796 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
1797 if (scsi_debug_dsense)
1798 open_devip->sense_buff[0] = 0x72;
1799 else {
1800 open_devip->sense_buff[0] = 0x70;
1801 open_devip->sense_buff[7] = 0xa;
1802 }
1803 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
1804 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
1805
1806 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807}
1808
1809static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
1810 int asc, int asq)
1811{
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09001812 unsigned char *sbuff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813
1814 sbuff = devip->sense_buff;
1815 memset(sbuff, 0, SDEBUG_SENSE_LEN);
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09001816
1817 scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
1818
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1820 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
1821 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
1822}
1823
1824static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
1825{
1826 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1827 printk(KERN_INFO "scsi_debug: abort\n");
1828 ++num_aborts;
1829 stop_queued_cmnd(SCpnt);
1830 return SUCCESS;
1831}
1832
1833static int scsi_debug_biosparam(struct scsi_device *sdev,
1834 struct block_device * bdev, sector_t capacity, int *info)
1835{
1836 int res;
1837 unsigned char *buf;
1838
1839 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1840 printk(KERN_INFO "scsi_debug: biosparam\n");
1841 buf = scsi_bios_ptable(bdev);
1842 if (buf) {
1843 res = scsi_partsize(buf, capacity,
1844 &info[2], &info[0], &info[1]);
1845 kfree(buf);
1846 if (! res)
1847 return res;
1848 }
1849 info[0] = sdebug_heads;
1850 info[1] = sdebug_sectors_per;
1851 info[2] = sdebug_cylinders_per;
1852 return 0;
1853}
1854
1855static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
1856{
1857 struct sdebug_dev_info * devip;
1858
1859 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1860 printk(KERN_INFO "scsi_debug: device_reset\n");
1861 ++num_dev_resets;
1862 if (SCpnt) {
1863 devip = devInfoReg(SCpnt->device);
1864 if (devip)
1865 devip->reset = 1;
1866 }
1867 return SUCCESS;
1868}
1869
1870static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
1871{
1872 struct sdebug_host_info *sdbg_host;
1873 struct sdebug_dev_info * dev_info;
1874 struct scsi_device * sdp;
1875 struct Scsi_Host * hp;
1876
1877 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1878 printk(KERN_INFO "scsi_debug: bus_reset\n");
1879 ++num_bus_resets;
1880 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09001881 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 if (sdbg_host) {
1883 list_for_each_entry(dev_info,
1884 &sdbg_host->dev_info_list,
1885 dev_list)
1886 dev_info->reset = 1;
1887 }
1888 }
1889 return SUCCESS;
1890}
1891
1892static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
1893{
1894 struct sdebug_host_info * sdbg_host;
1895 struct sdebug_dev_info * dev_info;
1896
1897 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1898 printk(KERN_INFO "scsi_debug: host_reset\n");
1899 ++num_host_resets;
1900 spin_lock(&sdebug_host_list_lock);
1901 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
1902 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
1903 dev_list)
1904 dev_info->reset = 1;
1905 }
1906 spin_unlock(&sdebug_host_list_lock);
1907 stop_all_queued();
1908 return SUCCESS;
1909}
1910
1911/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
1912static int stop_queued_cmnd(struct scsi_cmnd * cmnd)
1913{
1914 unsigned long iflags;
1915 int k;
1916 struct sdebug_queued_cmd * sqcp;
1917
1918 spin_lock_irqsave(&queued_arr_lock, iflags);
1919 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1920 sqcp = &queued_arr[k];
1921 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
1922 del_timer_sync(&sqcp->cmnd_timer);
1923 sqcp->in_use = 0;
1924 sqcp->a_cmnd = NULL;
1925 break;
1926 }
1927 }
1928 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1929 return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
1930}
1931
1932/* Deletes (stops) timers of all queued commands */
1933static void stop_all_queued(void)
1934{
1935 unsigned long iflags;
1936 int k;
1937 struct sdebug_queued_cmd * sqcp;
1938
1939 spin_lock_irqsave(&queued_arr_lock, iflags);
1940 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1941 sqcp = &queued_arr[k];
1942 if (sqcp->in_use && sqcp->a_cmnd) {
1943 del_timer_sync(&sqcp->cmnd_timer);
1944 sqcp->in_use = 0;
1945 sqcp->a_cmnd = NULL;
1946 }
1947 }
1948 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1949}
1950
1951/* Initializes timers in queued array */
1952static void __init init_all_queued(void)
1953{
1954 unsigned long iflags;
1955 int k;
1956 struct sdebug_queued_cmd * sqcp;
1957
1958 spin_lock_irqsave(&queued_arr_lock, iflags);
1959 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1960 sqcp = &queued_arr[k];
1961 init_timer(&sqcp->cmnd_timer);
1962 sqcp->in_use = 0;
1963 sqcp->a_cmnd = NULL;
1964 }
1965 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1966}
1967
1968static void __init sdebug_build_parts(unsigned char * ramp)
1969{
1970 struct partition * pp;
1971 int starts[SDEBUG_MAX_PARTS + 2];
1972 int sectors_per_part, num_sectors, k;
1973 int heads_by_sects, start_sec, end_sec;
1974
1975 /* assume partition table already zeroed */
1976 if ((scsi_debug_num_parts < 1) || (sdebug_store_size < 1048576))
1977 return;
1978 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
1979 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
1980 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
1981 "partitions to %d\n", SDEBUG_MAX_PARTS);
1982 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001983 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 sectors_per_part = (num_sectors - sdebug_sectors_per)
1985 / scsi_debug_num_parts;
1986 heads_by_sects = sdebug_heads * sdebug_sectors_per;
1987 starts[0] = sdebug_sectors_per;
1988 for (k = 1; k < scsi_debug_num_parts; ++k)
1989 starts[k] = ((k * sectors_per_part) / heads_by_sects)
1990 * heads_by_sects;
1991 starts[scsi_debug_num_parts] = num_sectors;
1992 starts[scsi_debug_num_parts + 1] = 0;
1993
1994 ramp[510] = 0x55; /* magic partition markings */
1995 ramp[511] = 0xAA;
1996 pp = (struct partition *)(ramp + 0x1be);
1997 for (k = 0; starts[k + 1]; ++k, ++pp) {
1998 start_sec = starts[k];
1999 end_sec = starts[k + 1] - 1;
2000 pp->boot_ind = 0;
2001
2002 pp->cyl = start_sec / heads_by_sects;
2003 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2004 / sdebug_sectors_per;
2005 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2006
2007 pp->end_cyl = end_sec / heads_by_sects;
2008 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2009 / sdebug_sectors_per;
2010 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2011
2012 pp->start_sect = start_sec;
2013 pp->nr_sects = end_sec - start_sec + 1;
2014 pp->sys_ind = 0x83; /* plain Linux partition */
2015 }
2016}
2017
2018static int schedule_resp(struct scsi_cmnd * cmnd,
2019 struct sdebug_dev_info * devip,
2020 done_funct_t done, int scsi_result, int delta_jiff)
2021{
2022 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2023 if (scsi_result) {
2024 struct scsi_device * sdp = cmnd->device;
2025
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002026 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2027 "non-zero result=0x%x\n", sdp->host->host_no,
2028 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 }
2030 }
2031 if (cmnd && devip) {
2032 /* simulate autosense by this driver */
2033 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2034 memcpy(cmnd->sense_buffer, devip->sense_buff,
2035 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2036 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2037 }
2038 if (delta_jiff <= 0) {
2039 if (cmnd)
2040 cmnd->result = scsi_result;
2041 if (done)
2042 done(cmnd);
2043 return 0;
2044 } else {
2045 unsigned long iflags;
2046 int k;
2047 struct sdebug_queued_cmd * sqcp = NULL;
2048
2049 spin_lock_irqsave(&queued_arr_lock, iflags);
2050 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2051 sqcp = &queued_arr[k];
2052 if (! sqcp->in_use)
2053 break;
2054 }
2055 if (k >= SCSI_DEBUG_CANQUEUE) {
2056 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2057 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2058 return 1; /* report busy to mid level */
2059 }
2060 sqcp->in_use = 1;
2061 sqcp->a_cmnd = cmnd;
2062 sqcp->scsi_result = scsi_result;
2063 sqcp->done_funct = done;
2064 sqcp->cmnd_timer.function = timer_intr_handler;
2065 sqcp->cmnd_timer.data = k;
2066 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2067 add_timer(&sqcp->cmnd_timer);
2068 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2069 if (cmnd)
2070 cmnd->result = 0;
2071 return 0;
2072 }
2073}
2074
Douglas Gilbert23183912006-09-16 20:30:47 -04002075/* Note: The following macros create attribute files in the
2076 /sys/module/scsi_debug/parameters directory. Unfortunately this
2077 driver is unaware of a change and cannot trigger auxiliary actions
2078 as it can when the corresponding attribute in the
2079 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2080 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002081module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2082module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2083module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2084module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2085module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002086module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002087module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2088module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2089module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2090module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2091module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2092module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2093module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2094module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002095module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2096 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097
2098MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2099MODULE_DESCRIPTION("SCSI debug adapter driver");
2100MODULE_LICENSE("GPL");
2101MODULE_VERSION(SCSI_DEBUG_VERSION);
2102
2103MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2104MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002105MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2106MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07002107MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002108MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002109MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2110MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002112MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002113MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2115MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002116MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002117MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118
2119
2120static char sdebug_info[256];
2121
2122static const char * scsi_debug_info(struct Scsi_Host * shp)
2123{
2124 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2125 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2126 scsi_debug_version_date, scsi_debug_dev_size_mb,
2127 scsi_debug_opts);
2128 return sdebug_info;
2129}
2130
2131/* scsi_debug_proc_info
2132 * Used if the driver currently has no own support for /proc/scsi
2133 */
2134static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2135 int length, int inout)
2136{
2137 int len, pos, begin;
2138 int orig_length;
2139
2140 orig_length = length;
2141
2142 if (inout == 1) {
2143 char arr[16];
2144 int minLen = length > 15 ? 15 : length;
2145
2146 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2147 return -EACCES;
2148 memcpy(arr, buffer, minLen);
2149 arr[minLen] = '\0';
2150 if (1 != sscanf(arr, "%d", &pos))
2151 return -EINVAL;
2152 scsi_debug_opts = pos;
2153 if (scsi_debug_every_nth != 0)
2154 scsi_debug_cmnd_count = 0;
2155 return length;
2156 }
2157 begin = 0;
2158 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2159 "%s [%s]\n"
2160 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2161 "every_nth=%d(curr:%d)\n"
2162 "delay=%d, max_luns=%d, scsi_level=%d\n"
2163 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2164 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
2165 "host_resets=%d\n",
2166 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2167 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2168 scsi_debug_cmnd_count, scsi_debug_delay,
2169 scsi_debug_max_luns, scsi_debug_scsi_level,
2170 SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
2171 num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
2172 if (pos < offset) {
2173 len = 0;
2174 begin = pos;
2175 }
2176 *start = buffer + (offset - begin); /* Start of wanted data */
2177 len -= (offset - begin);
2178 if (len > length)
2179 len = length;
2180 return len;
2181}
2182
2183static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2184{
2185 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2186}
2187
2188static ssize_t sdebug_delay_store(struct device_driver * ddp,
2189 const char * buf, size_t count)
2190{
2191 int delay;
2192 char work[20];
2193
2194 if (1 == sscanf(buf, "%10s", work)) {
2195 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2196 scsi_debug_delay = delay;
2197 return count;
2198 }
2199 }
2200 return -EINVAL;
2201}
2202DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2203 sdebug_delay_store);
2204
2205static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2206{
2207 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2208}
2209
2210static ssize_t sdebug_opts_store(struct device_driver * ddp,
2211 const char * buf, size_t count)
2212{
2213 int opts;
2214 char work[20];
2215
2216 if (1 == sscanf(buf, "%10s", work)) {
2217 if (0 == strnicmp(work,"0x", 2)) {
2218 if (1 == sscanf(&work[2], "%x", &opts))
2219 goto opts_done;
2220 } else {
2221 if (1 == sscanf(work, "%d", &opts))
2222 goto opts_done;
2223 }
2224 }
2225 return -EINVAL;
2226opts_done:
2227 scsi_debug_opts = opts;
2228 scsi_debug_cmnd_count = 0;
2229 return count;
2230}
2231DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2232 sdebug_opts_store);
2233
2234static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2235{
2236 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2237}
2238static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2239 const char * buf, size_t count)
2240{
2241 int n;
2242
2243 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2244 scsi_debug_ptype = n;
2245 return count;
2246 }
2247 return -EINVAL;
2248}
2249DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2250
2251static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2252{
2253 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2254}
2255static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2256 const char * buf, size_t count)
2257{
2258 int n;
2259
2260 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2261 scsi_debug_dsense = n;
2262 return count;
2263 }
2264 return -EINVAL;
2265}
2266DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2267 sdebug_dsense_store);
2268
Douglas Gilbert23183912006-09-16 20:30:47 -04002269static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2270{
2271 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2272}
2273static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2274 const char * buf, size_t count)
2275{
2276 int n;
2277
2278 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2279 scsi_debug_fake_rw = n;
2280 return count;
2281 }
2282 return -EINVAL;
2283}
2284DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2285 sdebug_fake_rw_store);
2286
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002287static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2288{
2289 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2290}
2291static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2292 const char * buf, size_t count)
2293{
2294 int n;
2295
2296 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2297 scsi_debug_no_lun_0 = n;
2298 return count;
2299 }
2300 return -EINVAL;
2301}
2302DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2303 sdebug_no_lun_0_store);
2304
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2306{
2307 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2308}
2309static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2310 const char * buf, size_t count)
2311{
2312 int n;
2313
2314 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2315 scsi_debug_num_tgts = n;
2316 sdebug_max_tgts_luns();
2317 return count;
2318 }
2319 return -EINVAL;
2320}
2321DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2322 sdebug_num_tgts_store);
2323
2324static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2325{
2326 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2327}
2328DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2329
2330static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2331{
2332 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2333}
2334DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2335
2336static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2337{
2338 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2339}
2340static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2341 const char * buf, size_t count)
2342{
2343 int nth;
2344
2345 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2346 scsi_debug_every_nth = nth;
2347 scsi_debug_cmnd_count = 0;
2348 return count;
2349 }
2350 return -EINVAL;
2351}
2352DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2353 sdebug_every_nth_store);
2354
2355static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2356{
2357 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2358}
2359static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2360 const char * buf, size_t count)
2361{
2362 int n;
2363
2364 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2365 scsi_debug_max_luns = n;
2366 sdebug_max_tgts_luns();
2367 return count;
2368 }
2369 return -EINVAL;
2370}
2371DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2372 sdebug_max_luns_store);
2373
2374static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
2375{
2376 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
2377}
2378DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
2379
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002380static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2381{
2382 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2383}
2384static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2385 const char * buf, size_t count)
2386{
2387 int n;
2388
2389 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2390 scsi_debug_virtual_gb = n;
2391 if (scsi_debug_virtual_gb > 0) {
2392 sdebug_capacity = 2048 * 1024;
2393 sdebug_capacity *= scsi_debug_virtual_gb;
2394 } else
2395 sdebug_capacity = sdebug_store_sectors;
2396 return count;
2397 }
2398 return -EINVAL;
2399}
2400DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2401 sdebug_virtual_gb_store);
2402
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
2404{
2405 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
2406}
2407
2408static ssize_t sdebug_add_host_store(struct device_driver * ddp,
2409 const char * buf, size_t count)
2410{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002411 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002413 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 if (delta_hosts > 0) {
2416 do {
2417 sdebug_add_adapter();
2418 } while (--delta_hosts);
2419 } else if (delta_hosts < 0) {
2420 do {
2421 sdebug_remove_adapter();
2422 } while (++delta_hosts);
2423 }
2424 return count;
2425}
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002426DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 sdebug_add_host_store);
2428
Douglas Gilbert23183912006-09-16 20:30:47 -04002429static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
2430 char * buf)
2431{
2432 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
2433}
2434static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
2435 const char * buf, size_t count)
2436{
2437 int n;
2438
2439 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2440 scsi_debug_vpd_use_hostno = n;
2441 return count;
2442 }
2443 return -EINVAL;
2444}
2445DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
2446 sdebug_vpd_use_hostno_store);
2447
2448/* Note: The following function creates attribute files in the
2449 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
2450 files (over those found in the /sys/module/scsi_debug/parameters
2451 directory) is that auxiliary actions can be triggered when an attribute
2452 is changed. For example see: sdebug_add_host_store() above.
2453 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002454static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002456 int ret;
2457
2458 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2459 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
2460 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2461 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2462 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04002463 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002464 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002465 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002466 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002467 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002468 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
2469 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
2470 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04002471 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
2472 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002473 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474}
2475
2476static void do_remove_driverfs_files(void)
2477{
Douglas Gilbert23183912006-09-16 20:30:47 -04002478 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
2479 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
2481 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
2482 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002484 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
2485 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002487 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
2489 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2490 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2491 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
2492 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2493}
2494
2495static int __init scsi_debug_init(void)
2496{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002497 unsigned int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498 int host_to_add;
2499 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002500 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501
2502 if (scsi_debug_dev_size_mb < 1)
2503 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002504 sdebug_store_size = (unsigned int)scsi_debug_dev_size_mb * 1048576;
2505 sdebug_store_sectors = sdebug_store_size / SECT_SIZE;
2506 if (scsi_debug_virtual_gb > 0) {
2507 sdebug_capacity = 2048 * 1024;
2508 sdebug_capacity *= scsi_debug_virtual_gb;
2509 } else
2510 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511
2512 /* play around with geometry, don't waste too much on track 0 */
2513 sdebug_heads = 8;
2514 sdebug_sectors_per = 32;
2515 if (scsi_debug_dev_size_mb >= 16)
2516 sdebug_heads = 32;
2517 else if (scsi_debug_dev_size_mb >= 256)
2518 sdebug_heads = 64;
2519 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2520 (sdebug_sectors_per * sdebug_heads);
2521 if (sdebug_cylinders_per >= 1024) {
2522 /* other LLDs do this; implies >= 1GB ram disk ... */
2523 sdebug_heads = 255;
2524 sdebug_sectors_per = 63;
2525 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2526 (sdebug_sectors_per * sdebug_heads);
2527 }
2528
2529 sz = sdebug_store_size;
2530 fake_storep = vmalloc(sz);
2531 if (NULL == fake_storep) {
2532 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
2533 return -ENOMEM;
2534 }
2535 memset(fake_storep, 0, sz);
2536 if (scsi_debug_num_parts > 0)
2537 sdebug_build_parts(fake_storep);
2538
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002539 ret = device_register(&pseudo_primary);
2540 if (ret < 0) {
2541 printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
2542 ret);
2543 goto free_vm;
2544 }
2545 ret = bus_register(&pseudo_lld_bus);
2546 if (ret < 0) {
2547 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
2548 ret);
2549 goto dev_unreg;
2550 }
2551 ret = driver_register(&sdebug_driverfs_driver);
2552 if (ret < 0) {
2553 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
2554 ret);
2555 goto bus_unreg;
2556 }
2557 ret = do_create_driverfs_files();
2558 if (ret < 0) {
2559 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
2560 ret);
2561 goto del_files;
2562 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002564 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 host_to_add = scsi_debug_add_host;
2567 scsi_debug_add_host = 0;
2568
2569 for (k = 0; k < host_to_add; k++) {
2570 if (sdebug_add_adapter()) {
2571 printk(KERN_ERR "scsi_debug_init: "
2572 "sdebug_add_adapter failed k=%d\n", k);
2573 break;
2574 }
2575 }
2576
2577 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
2578 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
2579 scsi_debug_add_host);
2580 }
2581 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002582
2583del_files:
2584 do_remove_driverfs_files();
2585 driver_unregister(&sdebug_driverfs_driver);
2586bus_unreg:
2587 bus_unregister(&pseudo_lld_bus);
2588dev_unreg:
2589 device_unregister(&pseudo_primary);
2590free_vm:
2591 vfree(fake_storep);
2592
2593 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594}
2595
2596static void __exit scsi_debug_exit(void)
2597{
2598 int k = scsi_debug_add_host;
2599
2600 stop_all_queued();
2601 for (; k; k--)
2602 sdebug_remove_adapter();
2603 do_remove_driverfs_files();
2604 driver_unregister(&sdebug_driverfs_driver);
2605 bus_unregister(&pseudo_lld_bus);
2606 device_unregister(&pseudo_primary);
2607
2608 vfree(fake_storep);
2609}
2610
2611device_initcall(scsi_debug_init);
2612module_exit(scsi_debug_exit);
2613
Adrian Bunk52c1da32005-06-23 22:05:33 -07002614static void pseudo_0_release(struct device * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615{
2616 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2617 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
2618}
2619
2620static struct device pseudo_primary = {
2621 .bus_id = "pseudo_0",
2622 .release = pseudo_0_release,
2623};
2624
2625static int pseudo_lld_bus_match(struct device *dev,
2626 struct device_driver *dev_driver)
2627{
2628 return 1;
2629}
2630
2631static struct bus_type pseudo_lld_bus = {
2632 .name = "pseudo",
2633 .match = pseudo_lld_bus_match,
Russell Kingbbbe3a42006-01-05 14:44:46 +00002634 .probe = sdebug_driver_probe,
2635 .remove = sdebug_driver_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636};
2637
2638static void sdebug_release_adapter(struct device * dev)
2639{
2640 struct sdebug_host_info *sdbg_host;
2641
2642 sdbg_host = to_sdebug_host(dev);
2643 kfree(sdbg_host);
2644}
2645
2646static int sdebug_add_adapter(void)
2647{
2648 int k, devs_per_host;
2649 int error = 0;
2650 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09002651 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002653 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 if (NULL == sdbg_host) {
2655 printk(KERN_ERR "%s: out of memory at line %d\n",
2656 __FUNCTION__, __LINE__);
2657 return -ENOMEM;
2658 }
2659
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
2661
2662 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
2663 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002664 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
2665 if (!sdbg_devinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 printk(KERN_ERR "%s: out of memory at line %d\n",
2667 __FUNCTION__, __LINE__);
2668 error = -ENOMEM;
2669 goto clean;
2670 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 }
2672
2673 spin_lock(&sdebug_host_list_lock);
2674 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
2675 spin_unlock(&sdebug_host_list_lock);
2676
2677 sdbg_host->dev.bus = &pseudo_lld_bus;
2678 sdbg_host->dev.parent = &pseudo_primary;
2679 sdbg_host->dev.release = &sdebug_release_adapter;
2680 sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host);
2681
2682 error = device_register(&sdbg_host->dev);
2683
2684 if (error)
2685 goto clean;
2686
2687 ++scsi_debug_add_host;
2688 return error;
2689
2690clean:
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09002691 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
2692 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 list_del(&sdbg_devinfo->dev_list);
2694 kfree(sdbg_devinfo);
2695 }
2696
2697 kfree(sdbg_host);
2698 return error;
2699}
2700
2701static void sdebug_remove_adapter(void)
2702{
2703 struct sdebug_host_info * sdbg_host = NULL;
2704
2705 spin_lock(&sdebug_host_list_lock);
2706 if (!list_empty(&sdebug_host_list)) {
2707 sdbg_host = list_entry(sdebug_host_list.prev,
2708 struct sdebug_host_info, host_list);
2709 list_del(&sdbg_host->host_list);
2710 }
2711 spin_unlock(&sdebug_host_list_lock);
2712
2713 if (!sdbg_host)
2714 return;
2715
2716 device_unregister(&sdbg_host->dev);
2717 --scsi_debug_add_host;
2718}
2719
FUJITA Tomonori639db472008-03-20 11:09:19 +09002720static
2721int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
2722{
2723 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
2724 int len, k;
2725 unsigned int num;
2726 unsigned long long lba;
2727 int errsts = 0;
2728 int target = SCpnt->device->id;
2729 struct sdebug_dev_info *devip = NULL;
2730 int inj_recovered = 0;
2731 int inj_transport = 0;
2732 int delay_override = 0;
2733
2734 scsi_set_resid(SCpnt, 0);
2735 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
2736 printk(KERN_INFO "scsi_debug: cmd ");
2737 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
2738 printk("%02x ", (int)cmd[k]);
2739 printk("\n");
2740 }
2741
2742 if (target == SCpnt->device->host->hostt->this_id) {
2743 printk(KERN_INFO "scsi_debug: initiator's id used as "
2744 "target!\n");
2745 return schedule_resp(SCpnt, NULL, done,
2746 DID_NO_CONNECT << 16, 0);
2747 }
2748
2749 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
2750 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
2751 return schedule_resp(SCpnt, NULL, done,
2752 DID_NO_CONNECT << 16, 0);
2753 devip = devInfoReg(SCpnt->device);
2754 if (NULL == devip)
2755 return schedule_resp(SCpnt, NULL, done,
2756 DID_NO_CONNECT << 16, 0);
2757
2758 if ((scsi_debug_every_nth != 0) &&
2759 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
2760 scsi_debug_cmnd_count = 0;
2761 if (scsi_debug_every_nth < -1)
2762 scsi_debug_every_nth = -1;
2763 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
2764 return 0; /* ignore command causing timeout */
2765 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
2766 inj_recovered = 1; /* to reads and writes below */
2767 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
2768 inj_transport = 1; /* to reads and writes below */
2769 }
2770
2771 if (devip->wlun) {
2772 switch (*cmd) {
2773 case INQUIRY:
2774 case REQUEST_SENSE:
2775 case TEST_UNIT_READY:
2776 case REPORT_LUNS:
2777 break; /* only allowable wlun commands */
2778 default:
2779 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2780 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
2781 "not supported for wlun\n", *cmd);
2782 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2783 INVALID_OPCODE, 0);
2784 errsts = check_condition_result;
2785 return schedule_resp(SCpnt, devip, done, errsts,
2786 0);
2787 }
2788 }
2789
2790 switch (*cmd) {
2791 case INQUIRY: /* mandatory, ignore unit attention */
2792 delay_override = 1;
2793 errsts = resp_inquiry(SCpnt, target, devip);
2794 break;
2795 case REQUEST_SENSE: /* mandatory, ignore unit attention */
2796 delay_override = 1;
2797 errsts = resp_requests(SCpnt, devip);
2798 break;
2799 case REZERO_UNIT: /* actually this is REWIND for SSC */
2800 case START_STOP:
2801 errsts = resp_start_stop(SCpnt, devip);
2802 break;
2803 case ALLOW_MEDIUM_REMOVAL:
2804 errsts = check_readiness(SCpnt, 1, devip);
2805 if (errsts)
2806 break;
2807 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2808 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
2809 cmd[4] ? "inhibited" : "enabled");
2810 break;
2811 case SEND_DIAGNOSTIC: /* mandatory */
2812 errsts = check_readiness(SCpnt, 1, devip);
2813 break;
2814 case TEST_UNIT_READY: /* mandatory */
2815 delay_override = 1;
2816 errsts = check_readiness(SCpnt, 0, devip);
2817 break;
2818 case RESERVE:
2819 errsts = check_readiness(SCpnt, 1, devip);
2820 break;
2821 case RESERVE_10:
2822 errsts = check_readiness(SCpnt, 1, devip);
2823 break;
2824 case RELEASE:
2825 errsts = check_readiness(SCpnt, 1, devip);
2826 break;
2827 case RELEASE_10:
2828 errsts = check_readiness(SCpnt, 1, devip);
2829 break;
2830 case READ_CAPACITY:
2831 errsts = resp_readcap(SCpnt, devip);
2832 break;
2833 case SERVICE_ACTION_IN:
2834 if (SAI_READ_CAPACITY_16 != cmd[1]) {
2835 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2836 INVALID_OPCODE, 0);
2837 errsts = check_condition_result;
2838 break;
2839 }
2840 errsts = resp_readcap16(SCpnt, devip);
2841 break;
2842 case MAINTENANCE_IN:
2843 if (MI_REPORT_TARGET_PGS != cmd[1]) {
2844 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2845 INVALID_OPCODE, 0);
2846 errsts = check_condition_result;
2847 break;
2848 }
2849 errsts = resp_report_tgtpgs(SCpnt, devip);
2850 break;
2851 case READ_16:
2852 case READ_12:
2853 case READ_10:
2854 case READ_6:
2855 errsts = check_readiness(SCpnt, 0, devip);
2856 if (errsts)
2857 break;
2858 if (scsi_debug_fake_rw)
2859 break;
2860 get_data_transfer_info(cmd, &lba, &num);
2861 errsts = resp_read(SCpnt, lba, num, devip);
2862 if (inj_recovered && (0 == errsts)) {
2863 mk_sense_buffer(devip, RECOVERED_ERROR,
2864 THRESHOLD_EXCEEDED, 0);
2865 errsts = check_condition_result;
2866 } else if (inj_transport && (0 == errsts)) {
2867 mk_sense_buffer(devip, ABORTED_COMMAND,
2868 TRANSPORT_PROBLEM, ACK_NAK_TO);
2869 errsts = check_condition_result;
2870 }
2871 break;
2872 case REPORT_LUNS: /* mandatory, ignore unit attention */
2873 delay_override = 1;
2874 errsts = resp_report_luns(SCpnt, devip);
2875 break;
2876 case VERIFY: /* 10 byte SBC-2 command */
2877 errsts = check_readiness(SCpnt, 0, devip);
2878 break;
2879 case WRITE_16:
2880 case WRITE_12:
2881 case WRITE_10:
2882 case WRITE_6:
2883 errsts = check_readiness(SCpnt, 0, devip);
2884 if (errsts)
2885 break;
2886 if (scsi_debug_fake_rw)
2887 break;
2888 get_data_transfer_info(cmd, &lba, &num);
2889 errsts = resp_write(SCpnt, lba, num, devip);
2890 if (inj_recovered && (0 == errsts)) {
2891 mk_sense_buffer(devip, RECOVERED_ERROR,
2892 THRESHOLD_EXCEEDED, 0);
2893 errsts = check_condition_result;
2894 }
2895 break;
2896 case MODE_SENSE:
2897 case MODE_SENSE_10:
2898 errsts = resp_mode_sense(SCpnt, target, devip);
2899 break;
2900 case MODE_SELECT:
2901 errsts = resp_mode_select(SCpnt, 1, devip);
2902 break;
2903 case MODE_SELECT_10:
2904 errsts = resp_mode_select(SCpnt, 0, devip);
2905 break;
2906 case LOG_SENSE:
2907 errsts = resp_log_sense(SCpnt, devip);
2908 break;
2909 case SYNCHRONIZE_CACHE:
2910 delay_override = 1;
2911 errsts = check_readiness(SCpnt, 0, devip);
2912 break;
2913 case WRITE_BUFFER:
2914 errsts = check_readiness(SCpnt, 1, devip);
2915 break;
2916 case XDWRITEREAD_10:
2917 if (!scsi_bidi_cmnd(SCpnt)) {
2918 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2919 INVALID_FIELD_IN_CDB, 0);
2920 errsts = check_condition_result;
2921 break;
2922 }
2923
2924 errsts = check_readiness(SCpnt, 0, devip);
2925 if (errsts)
2926 break;
2927 if (scsi_debug_fake_rw)
2928 break;
2929 get_data_transfer_info(cmd, &lba, &num);
2930 errsts = resp_read(SCpnt, lba, num, devip);
2931 if (errsts)
2932 break;
2933 errsts = resp_write(SCpnt, lba, num, devip);
2934 if (errsts)
2935 break;
2936 errsts = resp_xdwriteread(SCpnt, lba, num, devip);
2937 break;
2938 default:
2939 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2940 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
2941 "supported\n", *cmd);
2942 errsts = check_readiness(SCpnt, 1, devip);
2943 if (errsts)
2944 break; /* Unit attention takes precedence */
2945 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
2946 errsts = check_condition_result;
2947 break;
2948 }
2949 return schedule_resp(SCpnt, devip, done, errsts,
2950 (delay_override ? 0 : scsi_debug_delay));
2951}
2952
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09002953static struct scsi_host_template sdebug_driver_template = {
2954 .proc_info = scsi_debug_proc_info,
2955 .proc_name = sdebug_proc_name,
2956 .name = "SCSI DEBUG",
2957 .info = scsi_debug_info,
2958 .slave_alloc = scsi_debug_slave_alloc,
2959 .slave_configure = scsi_debug_slave_configure,
2960 .slave_destroy = scsi_debug_slave_destroy,
2961 .ioctl = scsi_debug_ioctl,
2962 .queuecommand = scsi_debug_queuecommand,
2963 .eh_abort_handler = scsi_debug_abort,
2964 .eh_bus_reset_handler = scsi_debug_bus_reset,
2965 .eh_device_reset_handler = scsi_debug_device_reset,
2966 .eh_host_reset_handler = scsi_debug_host_reset,
2967 .bios_param = scsi_debug_biosparam,
2968 .can_queue = SCSI_DEBUG_CANQUEUE,
2969 .this_id = 7,
2970 .sg_tablesize = 256,
2971 .cmd_per_lun = 16,
2972 .max_sectors = 0xffff,
2973 .use_clustering = DISABLE_CLUSTERING,
2974 .module = THIS_MODULE,
2975};
2976
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977static int sdebug_driver_probe(struct device * dev)
2978{
2979 int error = 0;
2980 struct sdebug_host_info *sdbg_host;
2981 struct Scsi_Host *hpnt;
2982
2983 sdbg_host = to_sdebug_host(dev);
2984
2985 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
2986 if (NULL == hpnt) {
2987 printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__);
2988 error = -ENODEV;
2989 return error;
2990 }
2991
2992 sdbg_host->shost = hpnt;
2993 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
2994 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
2995 hpnt->max_id = scsi_debug_num_tgts + 1;
2996 else
2997 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002998 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999
3000 error = scsi_add_host(hpnt, &sdbg_host->dev);
3001 if (error) {
3002 printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
3003 error = -ENODEV;
3004 scsi_host_put(hpnt);
3005 } else
3006 scsi_scan_host(hpnt);
3007
3008
3009 return error;
3010}
3011
3012static int sdebug_driver_remove(struct device * dev)
3013{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003015 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016
3017 sdbg_host = to_sdebug_host(dev);
3018
3019 if (!sdbg_host) {
3020 printk(KERN_ERR "%s: Unable to locate host info\n",
3021 __FUNCTION__);
3022 return -ENODEV;
3023 }
3024
3025 scsi_remove_host(sdbg_host->shost);
3026
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003027 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
3028 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 list_del(&sdbg_devinfo->dev_list);
3030 kfree(sdbg_devinfo);
3031 }
3032
3033 scsi_host_put(sdbg_host->shost);
3034 return 0;
3035}
3036
3037static void sdebug_max_tgts_luns(void)
3038{
3039 struct sdebug_host_info * sdbg_host;
3040 struct Scsi_Host *hpnt;
3041
3042 spin_lock(&sdebug_host_list_lock);
3043 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3044 hpnt = sdbg_host->shost;
3045 if ((hpnt->this_id >= 0) &&
3046 (scsi_debug_num_tgts > hpnt->this_id))
3047 hpnt->max_id = scsi_debug_num_tgts + 1;
3048 else
3049 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003050 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 }
3052 spin_unlock(&sdebug_host_list_lock);
3053}