blob: 4e93b69207c454ac1a2aeffc39f3a8ef2b78456c [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_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152static sector_t sdebug_capacity; /* in sectors */
153
154/* old BIOS stuff, kernel may get rid of them but some mode sense pages
155 may still need them */
156static int sdebug_heads; /* heads per disk */
157static int sdebug_cylinders_per; /* cylinders per surface */
158static int sdebug_sectors_per; /* sectors per cylinder */
159
160/* default sector size is 512 bytes, 2**9 bytes */
161#define POW2_SECT_SIZE 9
162#define SECT_SIZE (1 << POW2_SECT_SIZE)
163#define SECT_SIZE_PER(TGT) SECT_SIZE
164
165#define SDEBUG_MAX_PARTS 4
166
167#define SDEBUG_SENSE_LEN 32
168
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +0900169#define SCSI_DEBUG_CANQUEUE 255
170#define SCSI_DEBUG_MAX_CMD_LEN 16
171
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172struct sdebug_dev_info {
173 struct list_head dev_list;
174 unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */
175 unsigned int channel;
176 unsigned int target;
177 unsigned int lun;
178 struct sdebug_host_info *sdbg_host;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400179 unsigned int wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 char reset;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400181 char stopped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 char used;
183};
184
185struct sdebug_host_info {
186 struct list_head host_list;
187 struct Scsi_Host *shost;
188 struct device dev;
189 struct list_head dev_info_list;
190};
191
192#define to_sdebug_host(d) \
193 container_of(d, struct sdebug_host_info, dev)
194
195static LIST_HEAD(sdebug_host_list);
196static DEFINE_SPINLOCK(sdebug_host_list_lock);
197
198typedef void (* done_funct_t) (struct scsi_cmnd *);
199
200struct sdebug_queued_cmd {
201 int in_use;
202 struct timer_list cmnd_timer;
203 done_funct_t done_funct;
204 struct scsi_cmnd * a_cmnd;
205 int scsi_result;
206};
207static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
208
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209static unsigned char * fake_storep; /* ramdisk storage */
210
211static int num_aborts = 0;
212static int num_dev_resets = 0;
213static int num_bus_resets = 0;
214static int num_host_resets = 0;
215
216static DEFINE_SPINLOCK(queued_arr_lock);
217static DEFINE_RWLOCK(atomic_rw);
218
219static char sdebug_proc_name[] = "scsi_debug";
220
221static int sdebug_driver_probe(struct device *);
222static int sdebug_driver_remove(struct device *);
223static struct bus_type pseudo_lld_bus;
224
225static struct device_driver sdebug_driverfs_driver = {
226 .name = sdebug_proc_name,
227 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228};
229
230static const int check_condition_result =
231 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
232
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400233static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
234 0, 0, 0x2, 0x4b};
235static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
236 0, 0, 0x0, 0x0};
237
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev);
239static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
240 int asc, int asq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241static void stop_all_queued(void);
242static int stop_queued_cmnd(struct scsi_cmnd * cmnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
244static int sdebug_add_adapter(void);
245static void sdebug_remove_adapter(void);
246static void sdebug_max_tgts_luns(void);
247
248static struct device pseudo_primary;
249static struct bus_type pseudo_lld_bus;
250
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900251static void get_data_transfer_info(unsigned char *cmd,
252 unsigned long long *lba, unsigned int *num)
253{
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900254 switch (*cmd) {
255 case WRITE_16:
256 case READ_16:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900257 *lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
258 (u64)cmd[7] << 16 | (u64)cmd[6] << 24 |
259 (u64)cmd[5] << 32 | (u64)cmd[4] << 40 |
260 (u64)cmd[3] << 48 | (u64)cmd[2] << 56;
261
262 *num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 |
263 (u32)cmd[10] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900264 break;
265 case WRITE_12:
266 case READ_12:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900267 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
268 (u32)cmd[2] << 24;
269
270 *num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |
271 (u32)cmd[6] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900272 break;
273 case WRITE_10:
274 case READ_10:
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900275 case XDWRITEREAD_10:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900276 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
277 (u32)cmd[2] << 24;
278
279 *num = (u32)cmd[8] | (u32)cmd[7] << 8;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900280 break;
281 case WRITE_6:
282 case READ_6:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900283 *lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
284 (u32)(cmd[1] & 0x1f) << 16;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900285 *num = (0 == cmd[4]) ? 256 : cmd[4];
286 break;
287 default:
288 break;
289 }
290}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
293{
294 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
295 printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
296 }
297 return -EINVAL;
298 /* return -ENOTTY; // correct return but upsets fdisk */
299}
300
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400301static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
302 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303{
304 if (devip->reset) {
305 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
306 printk(KERN_INFO "scsi_debug: Reporting Unit "
307 "attention: power on reset\n");
308 devip->reset = 0;
309 mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
310 return check_condition_result;
311 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400312 if ((0 == reset_only) && devip->stopped) {
313 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
314 printk(KERN_INFO "scsi_debug: Reporting Not "
315 "ready: initializing command required\n");
316 mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
317 0x2);
318 return check_condition_result;
319 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 return 0;
321}
322
323/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900324static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 int arr_len)
326{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900327 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900328 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900330 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900332 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 return (DID_ERROR << 16);
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900334
335 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
336 arr, arr_len);
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900337 if (sdb->resid)
338 sdb->resid -= act_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400339 else
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900340 sdb->resid = scsi_bufflen(scp) - act_len;
341
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 return 0;
343}
344
345/* Returns number of bytes fetched into 'arr' or -1 if error. */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900346static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
347 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900349 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900351 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900353
354 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355}
356
357
358static const char * inq_vendor_id = "Linux ";
359static const char * inq_product_id = "scsi_debug ";
360static const char * inq_product_rev = "0004";
361
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200362static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
363 int target_dev_id, int dev_id_num,
364 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400365 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400367 int num, port_a;
368 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400370 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 /* T10 vendor identifier field format (faked) */
372 arr[0] = 0x2; /* ASCII */
373 arr[1] = 0x1;
374 arr[2] = 0x0;
375 memcpy(&arr[4], inq_vendor_id, 8);
376 memcpy(&arr[12], inq_product_id, 16);
377 memcpy(&arr[28], dev_id_str, dev_id_str_len);
378 num = 8 + 16 + dev_id_str_len;
379 arr[3] = num;
380 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400381 if (dev_id_num >= 0) {
382 /* NAA-5, Logical unit identifier (binary) */
383 arr[num++] = 0x1; /* binary (not necessarily sas) */
384 arr[num++] = 0x3; /* PIV=0, lu, naa */
385 arr[num++] = 0x0;
386 arr[num++] = 0x8;
387 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
388 arr[num++] = 0x33;
389 arr[num++] = 0x33;
390 arr[num++] = 0x30;
391 arr[num++] = (dev_id_num >> 24);
392 arr[num++] = (dev_id_num >> 16) & 0xff;
393 arr[num++] = (dev_id_num >> 8) & 0xff;
394 arr[num++] = dev_id_num & 0xff;
395 /* Target relative port number */
396 arr[num++] = 0x61; /* proto=sas, binary */
397 arr[num++] = 0x94; /* PIV=1, target port, rel port */
398 arr[num++] = 0x0; /* reserved */
399 arr[num++] = 0x4; /* length */
400 arr[num++] = 0x0; /* reserved */
401 arr[num++] = 0x0; /* reserved */
402 arr[num++] = 0x0;
403 arr[num++] = 0x1; /* relative port A */
404 }
405 /* NAA-5, Target port identifier */
406 arr[num++] = 0x61; /* proto=sas, binary */
407 arr[num++] = 0x93; /* piv=1, target port, naa */
408 arr[num++] = 0x0;
409 arr[num++] = 0x8;
410 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
411 arr[num++] = 0x22;
412 arr[num++] = 0x22;
413 arr[num++] = 0x20;
414 arr[num++] = (port_a >> 24);
415 arr[num++] = (port_a >> 16) & 0xff;
416 arr[num++] = (port_a >> 8) & 0xff;
417 arr[num++] = port_a & 0xff;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200418 /* NAA-5, Target port group identifier */
419 arr[num++] = 0x61; /* proto=sas, binary */
420 arr[num++] = 0x95; /* piv=1, target port group id */
421 arr[num++] = 0x0;
422 arr[num++] = 0x4;
423 arr[num++] = 0;
424 arr[num++] = 0;
425 arr[num++] = (port_group_id >> 8) & 0xff;
426 arr[num++] = port_group_id & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400427 /* NAA-5, Target device identifier */
428 arr[num++] = 0x61; /* proto=sas, binary */
429 arr[num++] = 0xa3; /* piv=1, target device, naa */
430 arr[num++] = 0x0;
431 arr[num++] = 0x8;
432 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
433 arr[num++] = 0x22;
434 arr[num++] = 0x22;
435 arr[num++] = 0x20;
436 arr[num++] = (target_dev_id >> 24);
437 arr[num++] = (target_dev_id >> 16) & 0xff;
438 arr[num++] = (target_dev_id >> 8) & 0xff;
439 arr[num++] = target_dev_id & 0xff;
440 /* SCSI name string: Target device identifier */
441 arr[num++] = 0x63; /* proto=sas, UTF-8 */
442 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
443 arr[num++] = 0x0;
444 arr[num++] = 24;
445 memcpy(arr + num, "naa.52222220", 12);
446 num += 12;
447 snprintf(b, sizeof(b), "%08X", target_dev_id);
448 memcpy(arr + num, b, 8);
449 num += 8;
450 memset(arr + num, 0, 4);
451 num += 4;
452 return num;
453}
454
455
456static unsigned char vpd84_data[] = {
457/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
458 0x22,0x22,0x22,0x0,0xbb,0x1,
459 0x22,0x22,0x22,0x0,0xbb,0x2,
460};
461
462static int inquiry_evpd_84(unsigned char * arr)
463{
464 memcpy(arr, vpd84_data, sizeof(vpd84_data));
465 return sizeof(vpd84_data);
466}
467
468static int inquiry_evpd_85(unsigned char * arr)
469{
470 int num = 0;
471 const char * na1 = "https://www.kernel.org/config";
472 const char * na2 = "http://www.kernel.org/log";
473 int plen, olen;
474
475 arr[num++] = 0x1; /* lu, storage config */
476 arr[num++] = 0x0; /* reserved */
477 arr[num++] = 0x0;
478 olen = strlen(na1);
479 plen = olen + 1;
480 if (plen % 4)
481 plen = ((plen / 4) + 1) * 4;
482 arr[num++] = plen; /* length, null termianted, padded */
483 memcpy(arr + num, na1, olen);
484 memset(arr + num + olen, 0, plen - olen);
485 num += plen;
486
487 arr[num++] = 0x4; /* lu, logging */
488 arr[num++] = 0x0; /* reserved */
489 arr[num++] = 0x0;
490 olen = strlen(na2);
491 plen = olen + 1;
492 if (plen % 4)
493 plen = ((plen / 4) + 1) * 4;
494 arr[num++] = plen; /* length, null terminated, padded */
495 memcpy(arr + num, na2, olen);
496 memset(arr + num + olen, 0, plen - olen);
497 num += plen;
498
499 return num;
500}
501
502/* SCSI ports VPD page */
503static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
504{
505 int num = 0;
506 int port_a, port_b;
507
508 port_a = target_dev_id + 1;
509 port_b = port_a + 1;
510 arr[num++] = 0x0; /* reserved */
511 arr[num++] = 0x0; /* reserved */
512 arr[num++] = 0x0;
513 arr[num++] = 0x1; /* relative port 1 (primary) */
514 memset(arr + num, 0, 6);
515 num += 6;
516 arr[num++] = 0x0;
517 arr[num++] = 12; /* length tp descriptor */
518 /* naa-5 target port identifier (A) */
519 arr[num++] = 0x61; /* proto=sas, binary */
520 arr[num++] = 0x93; /* PIV=1, target port, NAA */
521 arr[num++] = 0x0; /* reserved */
522 arr[num++] = 0x8; /* length */
523 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
524 arr[num++] = 0x22;
525 arr[num++] = 0x22;
526 arr[num++] = 0x20;
527 arr[num++] = (port_a >> 24);
528 arr[num++] = (port_a >> 16) & 0xff;
529 arr[num++] = (port_a >> 8) & 0xff;
530 arr[num++] = port_a & 0xff;
531
532 arr[num++] = 0x0; /* reserved */
533 arr[num++] = 0x0; /* reserved */
534 arr[num++] = 0x0;
535 arr[num++] = 0x2; /* relative port 2 (secondary) */
536 memset(arr + num, 0, 6);
537 num += 6;
538 arr[num++] = 0x0;
539 arr[num++] = 12; /* length tp descriptor */
540 /* naa-5 target port identifier (B) */
541 arr[num++] = 0x61; /* proto=sas, binary */
542 arr[num++] = 0x93; /* PIV=1, target port, NAA */
543 arr[num++] = 0x0; /* reserved */
544 arr[num++] = 0x8; /* length */
545 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
546 arr[num++] = 0x22;
547 arr[num++] = 0x22;
548 arr[num++] = 0x20;
549 arr[num++] = (port_b >> 24);
550 arr[num++] = (port_b >> 16) & 0xff;
551 arr[num++] = (port_b >> 8) & 0xff;
552 arr[num++] = port_b & 0xff;
553
554 return num;
555}
556
557
558static unsigned char vpd89_data[] = {
559/* from 4th byte */ 0,0,0,0,
560'l','i','n','u','x',' ',' ',' ',
561'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
562'1','2','3','4',
5630x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
5640xec,0,0,0,
5650x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
5660,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
5670x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
5680x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
5690x53,0x41,
5700x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
5710x20,0x20,
5720x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
5730x10,0x80,
5740,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
5750x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
5760x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
5770,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
5780x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
5790x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
5800,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
5810,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5820,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5830,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5840x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
5850,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
5860xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
5870,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,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,0,0,
5970,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5980,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
5990,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
600};
601
602static int inquiry_evpd_89(unsigned char * arr)
603{
604 memcpy(arr, vpd89_data, sizeof(vpd89_data));
605 return sizeof(vpd89_data);
606}
607
608
609static unsigned char vpdb0_data[] = {
610 /* from 4th byte */ 0,0,0,4,
611 0,0,0x4,0,
612 0,0,0,64,
613};
614
615static int inquiry_evpd_b0(unsigned char * arr)
616{
617 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
618 if (sdebug_store_sectors > 0x400) {
619 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
620 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
621 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
622 arr[7] = sdebug_store_sectors & 0xff;
623 }
624 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625}
626
627
628#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400629#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630
631static int resp_inquiry(struct scsi_cmnd * scp, int target,
632 struct sdebug_dev_info * devip)
633{
634 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200635 unsigned char * arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 unsigned char *cmd = (unsigned char *)scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200637 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
639 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500640 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
641 if (! arr)
642 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400643 if (devip->wlun)
644 pq_pdt = 0x1e; /* present, wlun */
645 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
646 pq_pdt = 0x7f; /* not present, no device type */
647 else
648 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 arr[0] = pq_pdt;
650 if (0x2 & cmd[1]) { /* CMDDT bit set */
651 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
652 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200653 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 return check_condition_result;
655 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200656 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400657 char lu_id_str[6];
658 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200660 port_group_id = (((host_no + 1) & 0x7f) << 8) +
661 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -0400662 if (0 == scsi_debug_vpd_use_hostno)
663 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400664 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
665 (devip->target * 1000) + devip->lun);
666 target_dev_id = ((host_no + 1) * 2000) +
667 (devip->target * 1000) - 3;
668 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400670 arr[1] = cmd[2]; /*sanity */
671 n = 4;
672 arr[n++] = 0x0; /* this page */
673 arr[n++] = 0x80; /* unit serial number */
674 arr[n++] = 0x83; /* device identification */
675 arr[n++] = 0x84; /* software interface ident. */
676 arr[n++] = 0x85; /* management network addresses */
677 arr[n++] = 0x86; /* extended inquiry */
678 arr[n++] = 0x87; /* mode page policy */
679 arr[n++] = 0x88; /* SCSI ports */
680 arr[n++] = 0x89; /* ATA information */
681 arr[n++] = 0xb0; /* Block limits (SBC) */
682 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400684 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400686 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400688 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200689 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
690 target_dev_id, lu_id_num,
691 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400692 } else if (0x84 == cmd[2]) { /* Software interface ident. */
693 arr[1] = cmd[2]; /*sanity */
694 arr[3] = inquiry_evpd_84(&arr[4]);
695 } else if (0x85 == cmd[2]) { /* Management network addresses */
696 arr[1] = cmd[2]; /*sanity */
697 arr[3] = inquiry_evpd_85(&arr[4]);
698 } else if (0x86 == cmd[2]) { /* extended inquiry */
699 arr[1] = cmd[2]; /*sanity */
700 arr[3] = 0x3c; /* number of following entries */
701 arr[4] = 0x0; /* no protection stuff */
702 arr[5] = 0x7; /* head of q, ordered + simple q's */
703 } else if (0x87 == cmd[2]) { /* mode page policy */
704 arr[1] = cmd[2]; /*sanity */
705 arr[3] = 0x8; /* number of following entries */
706 arr[4] = 0x2; /* disconnect-reconnect mp */
707 arr[6] = 0x80; /* mlus, shared */
708 arr[8] = 0x18; /* protocol specific lu */
709 arr[10] = 0x82; /* mlus, per initiator port */
710 } else if (0x88 == cmd[2]) { /* SCSI Ports */
711 arr[1] = cmd[2]; /*sanity */
712 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
713 } else if (0x89 == cmd[2]) { /* ATA information */
714 arr[1] = cmd[2]; /*sanity */
715 n = inquiry_evpd_89(&arr[4]);
716 arr[2] = (n >> 8);
717 arr[3] = (n & 0xff);
718 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
719 arr[1] = cmd[2]; /*sanity */
720 arr[3] = inquiry_evpd_b0(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 } else {
722 /* Illegal request, invalid field in cdb */
723 mk_sense_buffer(devip, ILLEGAL_REQUEST,
724 INVALID_FIELD_IN_CDB, 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200725 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 return check_condition_result;
727 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400728 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200729 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400730 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200731 kfree(arr);
732 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 }
734 /* drops through here for a standard inquiry */
735 arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
736 arr[2] = scsi_debug_scsi_level;
737 arr[3] = 2; /* response_data_format==2 */
738 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200739 if (0 == scsi_debug_vpd_use_hostno)
740 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400741 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400743 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 memcpy(&arr[8], inq_vendor_id, 8);
745 memcpy(&arr[16], inq_product_id, 16);
746 memcpy(&arr[32], inq_product_rev, 4);
747 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400748 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
749 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
750 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400752 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400754 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400756 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200757 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200759 kfree(arr);
760 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761}
762
763static int resp_requests(struct scsi_cmnd * scp,
764 struct sdebug_dev_info * devip)
765{
766 unsigned char * sbuff;
767 unsigned char *cmd = (unsigned char *)scp->cmnd;
768 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400769 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 int len = 18;
771
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400772 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400774 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
775 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400777 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
778 if (want_dsense) {
779 arr[0] = 0x72;
780 arr[1] = 0x0; /* NO_SENSE in sense_key */
781 arr[2] = THRESHOLD_EXCEEDED;
782 arr[3] = 0xff; /* TEST set and MRIE==6 */
783 } else {
784 arr[0] = 0x70;
785 arr[2] = 0x0; /* NO_SENSE in sense_key */
786 arr[7] = 0xa; /* 18 byte sense buffer */
787 arr[12] = THRESHOLD_EXCEEDED;
788 arr[13] = 0xff; /* TEST set and MRIE==6 */
789 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400790 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400792 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
793 /* DESC bit set and sense_buff in fixed format */
794 memset(arr, 0, sizeof(arr));
795 arr[0] = 0x72;
796 arr[1] = sbuff[2]; /* sense key */
797 arr[2] = sbuff[12]; /* asc */
798 arr[3] = sbuff[13]; /* ascq */
799 len = 8;
800 }
801 }
802 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 return fill_from_dev_buffer(scp, arr, len);
804}
805
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400806static int resp_start_stop(struct scsi_cmnd * scp,
807 struct sdebug_dev_info * devip)
808{
809 unsigned char *cmd = (unsigned char *)scp->cmnd;
810 int power_cond, errsts, start;
811
812 if ((errsts = check_readiness(scp, 1, devip)))
813 return errsts;
814 power_cond = (cmd[4] & 0xf0) >> 4;
815 if (power_cond) {
816 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
817 0);
818 return check_condition_result;
819 }
820 start = cmd[4] & 1;
821 if (start == devip->stopped)
822 devip->stopped = !start;
823 return 0;
824}
825
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826#define SDEBUG_READCAP_ARR_SZ 8
827static int resp_readcap(struct scsi_cmnd * scp,
828 struct sdebug_dev_info * devip)
829{
830 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400831 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 int errsts;
833
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400834 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400836 /* following just in case virtual_gb changed */
837 if (scsi_debug_virtual_gb > 0) {
838 sdebug_capacity = 2048 * 1024;
839 sdebug_capacity *= scsi_debug_virtual_gb;
840 } else
841 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400843 if (sdebug_capacity < 0xffffffff) {
844 capac = (unsigned int)sdebug_capacity - 1;
845 arr[0] = (capac >> 24);
846 arr[1] = (capac >> 16) & 0xff;
847 arr[2] = (capac >> 8) & 0xff;
848 arr[3] = capac & 0xff;
849 } else {
850 arr[0] = 0xff;
851 arr[1] = 0xff;
852 arr[2] = 0xff;
853 arr[3] = 0xff;
854 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
856 arr[7] = SECT_SIZE_PER(target) & 0xff;
857 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
858}
859
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400860#define SDEBUG_READCAP16_ARR_SZ 32
861static int resp_readcap16(struct scsi_cmnd * scp,
862 struct sdebug_dev_info * devip)
863{
864 unsigned char *cmd = (unsigned char *)scp->cmnd;
865 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
866 unsigned long long capac;
867 int errsts, k, alloc_len;
868
869 if ((errsts = check_readiness(scp, 1, devip)))
870 return errsts;
871 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
872 + cmd[13]);
873 /* following just in case virtual_gb changed */
874 if (scsi_debug_virtual_gb > 0) {
875 sdebug_capacity = 2048 * 1024;
876 sdebug_capacity *= scsi_debug_virtual_gb;
877 } else
878 sdebug_capacity = sdebug_store_sectors;
879 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
880 capac = sdebug_capacity - 1;
881 for (k = 0; k < 8; ++k, capac >>= 8)
882 arr[7 - k] = capac & 0xff;
883 arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff;
884 arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff;
885 arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff;
886 arr[11] = SECT_SIZE_PER(target) & 0xff;
887 return fill_from_dev_buffer(scp, arr,
888 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
889}
890
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200891#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
892
893static int resp_report_tgtpgs(struct scsi_cmnd * scp,
894 struct sdebug_dev_info * devip)
895{
896 unsigned char *cmd = (unsigned char *)scp->cmnd;
897 unsigned char * arr;
898 int host_no = devip->sdbg_host->shost->host_no;
899 int n, ret, alen, rlen;
900 int port_group_a, port_group_b, port_a, port_b;
901
902 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
903 + cmd[9]);
904
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500905 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
906 if (! arr)
907 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200908 /*
909 * EVPD page 0x88 states we have two ports, one
910 * real and a fake port with no device connected.
911 * So we create two port groups with one port each
912 * and set the group with port B to unavailable.
913 */
914 port_a = 0x1; /* relative port A */
915 port_b = 0x2; /* relative port B */
916 port_group_a = (((host_no + 1) & 0x7f) << 8) +
917 (devip->channel & 0x7f);
918 port_group_b = (((host_no + 1) & 0x7f) << 8) +
919 (devip->channel & 0x7f) + 0x80;
920
921 /*
922 * The asymmetric access state is cycled according to the host_id.
923 */
924 n = 4;
925 if (0 == scsi_debug_vpd_use_hostno) {
926 arr[n++] = host_no % 3; /* Asymm access state */
927 arr[n++] = 0x0F; /* claim: all states are supported */
928 } else {
929 arr[n++] = 0x0; /* Active/Optimized path */
930 arr[n++] = 0x01; /* claim: only support active/optimized paths */
931 }
932 arr[n++] = (port_group_a >> 8) & 0xff;
933 arr[n++] = port_group_a & 0xff;
934 arr[n++] = 0; /* Reserved */
935 arr[n++] = 0; /* Status code */
936 arr[n++] = 0; /* Vendor unique */
937 arr[n++] = 0x1; /* One port per group */
938 arr[n++] = 0; /* Reserved */
939 arr[n++] = 0; /* Reserved */
940 arr[n++] = (port_a >> 8) & 0xff;
941 arr[n++] = port_a & 0xff;
942 arr[n++] = 3; /* Port unavailable */
943 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
944 arr[n++] = (port_group_b >> 8) & 0xff;
945 arr[n++] = port_group_b & 0xff;
946 arr[n++] = 0; /* Reserved */
947 arr[n++] = 0; /* Status code */
948 arr[n++] = 0; /* Vendor unique */
949 arr[n++] = 0x1; /* One port per group */
950 arr[n++] = 0; /* Reserved */
951 arr[n++] = 0; /* Reserved */
952 arr[n++] = (port_b >> 8) & 0xff;
953 arr[n++] = port_b & 0xff;
954
955 rlen = n - 4;
956 arr[0] = (rlen >> 24) & 0xff;
957 arr[1] = (rlen >> 16) & 0xff;
958 arr[2] = (rlen >> 8) & 0xff;
959 arr[3] = rlen & 0xff;
960
961 /*
962 * Return the smallest value of either
963 * - The allocated length
964 * - The constructed command length
965 * - The maximum array size
966 */
967 rlen = min(alen,n);
968 ret = fill_from_dev_buffer(scp, arr,
969 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
970 kfree(arr);
971 return ret;
972}
973
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974/* <<Following mode page info copied from ST318451LW>> */
975
976static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
977{ /* Read-Write Error Recovery page for mode_sense */
978 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
979 5, 0, 0xff, 0xff};
980
981 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
982 if (1 == pcontrol)
983 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
984 return sizeof(err_recov_pg);
985}
986
987static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
988{ /* Disconnect-Reconnect page for mode_sense */
989 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
990 0, 0, 0, 0, 0, 0, 0, 0};
991
992 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
993 if (1 == pcontrol)
994 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
995 return sizeof(disconnect_pg);
996}
997
998static int resp_format_pg(unsigned char * p, int pcontrol, int target)
999{ /* Format device page for mode_sense */
1000 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1001 0, 0, 0, 0, 0, 0, 0, 0,
1002 0, 0, 0, 0, 0x40, 0, 0, 0};
1003
1004 memcpy(p, format_pg, sizeof(format_pg));
1005 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1006 p[11] = sdebug_sectors_per & 0xff;
1007 p[12] = (SECT_SIZE >> 8) & 0xff;
1008 p[13] = SECT_SIZE & 0xff;
1009 if (DEV_REMOVEABLE(target))
1010 p[20] |= 0x20; /* should agree with INQUIRY */
1011 if (1 == pcontrol)
1012 memset(p + 2, 0, sizeof(format_pg) - 2);
1013 return sizeof(format_pg);
1014}
1015
1016static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1017{ /* Caching page for mode_sense */
1018 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1019 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1020
1021 memcpy(p, caching_pg, sizeof(caching_pg));
1022 if (1 == pcontrol)
1023 memset(p + 2, 0, sizeof(caching_pg) - 2);
1024 return sizeof(caching_pg);
1025}
1026
1027static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1028{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001029 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1030 0, 0, 0, 0};
1031 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 0, 0, 0x2, 0x4b};
1033
1034 if (scsi_debug_dsense)
1035 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001036 else
1037 ctrl_m_pg[2] &= ~0x4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1039 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001040 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1041 else if (2 == pcontrol)
1042 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 return sizeof(ctrl_m_pg);
1044}
1045
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001046
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1048{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001049 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1050 0, 0, 0x0, 0x0};
1051 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1052 0, 0, 0x0, 0x0};
1053
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1055 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001056 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1057 else if (2 == pcontrol)
1058 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 return sizeof(iec_m_pg);
1060}
1061
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001062static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1063{ /* SAS SSP mode page - short format for mode_sense */
1064 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1065 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1066
1067 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1068 if (1 == pcontrol)
1069 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1070 return sizeof(sas_sf_m_pg);
1071}
1072
1073
1074static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1075 int target_dev_id)
1076{ /* SAS phy control and discover mode page for mode_sense */
1077 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1078 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1079 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1080 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1081 0x2, 0, 0, 0, 0, 0, 0, 0,
1082 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1083 0, 0, 0, 0, 0, 0, 0, 0,
1084 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1085 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1086 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1087 0x3, 0, 0, 0, 0, 0, 0, 0,
1088 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1089 0, 0, 0, 0, 0, 0, 0, 0,
1090 };
1091 int port_a, port_b;
1092
1093 port_a = target_dev_id + 1;
1094 port_b = port_a + 1;
1095 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1096 p[20] = (port_a >> 24);
1097 p[21] = (port_a >> 16) & 0xff;
1098 p[22] = (port_a >> 8) & 0xff;
1099 p[23] = port_a & 0xff;
1100 p[48 + 20] = (port_b >> 24);
1101 p[48 + 21] = (port_b >> 16) & 0xff;
1102 p[48 + 22] = (port_b >> 8) & 0xff;
1103 p[48 + 23] = port_b & 0xff;
1104 if (1 == pcontrol)
1105 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1106 return sizeof(sas_pcd_m_pg);
1107}
1108
1109static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1110{ /* SAS SSP shared protocol specific port mode subpage */
1111 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1112 0, 0, 0, 0, 0, 0, 0, 0,
1113 };
1114
1115 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1116 if (1 == pcontrol)
1117 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1118 return sizeof(sas_sha_m_pg);
1119}
1120
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121#define SDEBUG_MAX_MSENSE_SZ 256
1122
1123static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1124 struct sdebug_dev_info * devip)
1125{
Douglas Gilbert23183912006-09-16 20:30:47 -04001126 unsigned char dbd, llbaa;
1127 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001129 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 unsigned char * ap;
1131 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1132 unsigned char *cmd = (unsigned char *)scp->cmnd;
1133
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001134 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001136 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 pcontrol = (cmd[2] & 0xc0) >> 6;
1138 pcode = cmd[2] & 0x3f;
1139 subpcode = cmd[3];
1140 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001141 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1142 if ((0 == scsi_debug_ptype) && (0 == dbd))
1143 bd_len = llbaa ? 16 : 8;
1144 else
1145 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1147 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1148 if (0x3 == pcontrol) { /* Saving values not supported */
1149 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1150 0);
1151 return check_condition_result;
1152 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001153 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1154 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001155 /* set DPOFUA bit for disks */
1156 if (0 == scsi_debug_ptype)
1157 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1158 else
1159 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 if (msense_6) {
1161 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001162 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 offset = 4;
1164 } else {
1165 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001166 if (16 == bd_len)
1167 arr[4] = 0x1; /* set LONGLBA bit */
1168 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 offset = 8;
1170 }
1171 ap = arr + offset;
Douglas Gilbert23183912006-09-16 20:30:47 -04001172 if ((bd_len > 0) && (0 == sdebug_capacity)) {
1173 if (scsi_debug_virtual_gb > 0) {
1174 sdebug_capacity = 2048 * 1024;
1175 sdebug_capacity *= scsi_debug_virtual_gb;
1176 } else
1177 sdebug_capacity = sdebug_store_sectors;
1178 }
1179 if (8 == bd_len) {
1180 if (sdebug_capacity > 0xfffffffe) {
1181 ap[0] = 0xff;
1182 ap[1] = 0xff;
1183 ap[2] = 0xff;
1184 ap[3] = 0xff;
1185 } else {
1186 ap[0] = (sdebug_capacity >> 24) & 0xff;
1187 ap[1] = (sdebug_capacity >> 16) & 0xff;
1188 ap[2] = (sdebug_capacity >> 8) & 0xff;
1189 ap[3] = sdebug_capacity & 0xff;
1190 }
1191 ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1192 ap[7] = SECT_SIZE_PER(target) & 0xff;
1193 offset += bd_len;
1194 ap = arr + offset;
1195 } else if (16 == bd_len) {
1196 unsigned long long capac = sdebug_capacity;
1197
1198 for (k = 0; k < 8; ++k, capac >>= 8)
1199 ap[7 - k] = capac & 0xff;
1200 ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff;
1201 ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff;
1202 ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1203 ap[15] = SECT_SIZE_PER(target) & 0xff;
1204 offset += bd_len;
1205 ap = arr + offset;
1206 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001208 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1209 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1211 0);
1212 return check_condition_result;
1213 }
1214 switch (pcode) {
1215 case 0x1: /* Read-Write error recovery page, direct access */
1216 len = resp_err_recov_pg(ap, pcontrol, target);
1217 offset += len;
1218 break;
1219 case 0x2: /* Disconnect-Reconnect page, all devices */
1220 len = resp_disconnect_pg(ap, pcontrol, target);
1221 offset += len;
1222 break;
1223 case 0x3: /* Format device page, direct access */
1224 len = resp_format_pg(ap, pcontrol, target);
1225 offset += len;
1226 break;
1227 case 0x8: /* Caching page, direct access */
1228 len = resp_caching_pg(ap, pcontrol, target);
1229 offset += len;
1230 break;
1231 case 0xa: /* Control Mode page, all devices */
1232 len = resp_ctrl_m_pg(ap, pcontrol, target);
1233 offset += len;
1234 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001235 case 0x19: /* if spc==1 then sas phy, control+discover */
1236 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1237 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1238 INVALID_FIELD_IN_CDB, 0);
1239 return check_condition_result;
1240 }
1241 len = 0;
1242 if ((0x0 == subpcode) || (0xff == subpcode))
1243 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1244 if ((0x1 == subpcode) || (0xff == subpcode))
1245 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1246 target_dev_id);
1247 if ((0x2 == subpcode) || (0xff == subpcode))
1248 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1249 offset += len;
1250 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 case 0x1c: /* Informational Exceptions Mode page, all devices */
1252 len = resp_iec_m_pg(ap, pcontrol, target);
1253 offset += len;
1254 break;
1255 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001256 if ((0 == subpcode) || (0xff == subpcode)) {
1257 len = resp_err_recov_pg(ap, pcontrol, target);
1258 len += resp_disconnect_pg(ap + len, pcontrol, target);
1259 len += resp_format_pg(ap + len, pcontrol, target);
1260 len += resp_caching_pg(ap + len, pcontrol, target);
1261 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1262 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1263 if (0xff == subpcode) {
1264 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1265 target, target_dev_id);
1266 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1267 }
1268 len += resp_iec_m_pg(ap + len, pcontrol, target);
1269 } else {
1270 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1271 INVALID_FIELD_IN_CDB, 0);
1272 return check_condition_result;
1273 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 offset += len;
1275 break;
1276 default:
1277 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1278 0);
1279 return check_condition_result;
1280 }
1281 if (msense_6)
1282 arr[0] = offset - 1;
1283 else {
1284 arr[0] = ((offset - 2) >> 8) & 0xff;
1285 arr[1] = (offset - 2) & 0xff;
1286 }
1287 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1288}
1289
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001290#define SDEBUG_MAX_MSELECT_SZ 512
1291
1292static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1293 struct sdebug_dev_info * devip)
1294{
1295 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1296 int param_len, res, errsts, mpage;
1297 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1298 unsigned char *cmd = (unsigned char *)scp->cmnd;
1299
1300 if ((errsts = check_readiness(scp, 1, devip)))
1301 return errsts;
1302 memset(arr, 0, sizeof(arr));
1303 pf = cmd[1] & 0x10;
1304 sp = cmd[1] & 0x1;
1305 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1306 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1307 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1308 INVALID_FIELD_IN_CDB, 0);
1309 return check_condition_result;
1310 }
1311 res = fetch_to_dev_buffer(scp, arr, param_len);
1312 if (-1 == res)
1313 return (DID_ERROR << 16);
1314 else if ((res < param_len) &&
1315 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1316 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1317 " IO sent=%d bytes\n", param_len, res);
1318 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1319 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001320 if (md_len > 2) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001321 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1322 INVALID_FIELD_IN_PARAM_LIST, 0);
1323 return check_condition_result;
1324 }
1325 off = bd_len + (mselect6 ? 4 : 8);
1326 mpage = arr[off] & 0x3f;
1327 ps = !!(arr[off] & 0x80);
1328 if (ps) {
1329 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1330 INVALID_FIELD_IN_PARAM_LIST, 0);
1331 return check_condition_result;
1332 }
1333 spf = !!(arr[off] & 0x40);
1334 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1335 (arr[off + 1] + 2);
1336 if ((pg_len + off) > param_len) {
1337 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1338 PARAMETER_LIST_LENGTH_ERR, 0);
1339 return check_condition_result;
1340 }
1341 switch (mpage) {
1342 case 0xa: /* Control Mode page */
1343 if (ctrl_m_pg[1] == arr[off + 1]) {
1344 memcpy(ctrl_m_pg + 2, arr + off + 2,
1345 sizeof(ctrl_m_pg) - 2);
1346 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1347 return 0;
1348 }
1349 break;
1350 case 0x1c: /* Informational Exceptions Mode page */
1351 if (iec_m_pg[1] == arr[off + 1]) {
1352 memcpy(iec_m_pg + 2, arr + off + 2,
1353 sizeof(iec_m_pg) - 2);
1354 return 0;
1355 }
1356 break;
1357 default:
1358 break;
1359 }
1360 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1361 INVALID_FIELD_IN_PARAM_LIST, 0);
1362 return check_condition_result;
1363}
1364
1365static int resp_temp_l_pg(unsigned char * arr)
1366{
1367 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1368 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1369 };
1370
1371 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1372 return sizeof(temp_l_pg);
1373}
1374
1375static int resp_ie_l_pg(unsigned char * arr)
1376{
1377 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1378 };
1379
1380 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1381 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1382 arr[4] = THRESHOLD_EXCEEDED;
1383 arr[5] = 0xff;
1384 }
1385 return sizeof(ie_l_pg);
1386}
1387
1388#define SDEBUG_MAX_LSENSE_SZ 512
1389
1390static int resp_log_sense(struct scsi_cmnd * scp,
1391 struct sdebug_dev_info * devip)
1392{
Douglas Gilbert23183912006-09-16 20:30:47 -04001393 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001394 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1395 unsigned char *cmd = (unsigned char *)scp->cmnd;
1396
1397 if ((errsts = check_readiness(scp, 1, devip)))
1398 return errsts;
1399 memset(arr, 0, sizeof(arr));
1400 ppc = cmd[1] & 0x2;
1401 sp = cmd[1] & 0x1;
1402 if (ppc || sp) {
1403 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1404 INVALID_FIELD_IN_CDB, 0);
1405 return check_condition_result;
1406 }
1407 pcontrol = (cmd[2] & 0xc0) >> 6;
1408 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001409 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001410 alloc_len = (cmd[7] << 8) + cmd[8];
1411 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001412 if (0 == subpcode) {
1413 switch (pcode) {
1414 case 0x0: /* Supported log pages log page */
1415 n = 4;
1416 arr[n++] = 0x0; /* this page */
1417 arr[n++] = 0xd; /* Temperature */
1418 arr[n++] = 0x2f; /* Informational exceptions */
1419 arr[3] = n - 4;
1420 break;
1421 case 0xd: /* Temperature log page */
1422 arr[3] = resp_temp_l_pg(arr + 4);
1423 break;
1424 case 0x2f: /* Informational exceptions log page */
1425 arr[3] = resp_ie_l_pg(arr + 4);
1426 break;
1427 default:
1428 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1429 INVALID_FIELD_IN_CDB, 0);
1430 return check_condition_result;
1431 }
1432 } else if (0xff == subpcode) {
1433 arr[0] |= 0x40;
1434 arr[1] = subpcode;
1435 switch (pcode) {
1436 case 0x0: /* Supported log pages and subpages log page */
1437 n = 4;
1438 arr[n++] = 0x0;
1439 arr[n++] = 0x0; /* 0,0 page */
1440 arr[n++] = 0x0;
1441 arr[n++] = 0xff; /* this page */
1442 arr[n++] = 0xd;
1443 arr[n++] = 0x0; /* Temperature */
1444 arr[n++] = 0x2f;
1445 arr[n++] = 0x0; /* Informational exceptions */
1446 arr[3] = n - 4;
1447 break;
1448 case 0xd: /* Temperature subpages */
1449 n = 4;
1450 arr[n++] = 0xd;
1451 arr[n++] = 0x0; /* Temperature */
1452 arr[3] = n - 4;
1453 break;
1454 case 0x2f: /* Informational exceptions subpages */
1455 n = 4;
1456 arr[n++] = 0x2f;
1457 arr[n++] = 0x0; /* Informational exceptions */
1458 arr[3] = n - 4;
1459 break;
1460 default:
1461 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1462 INVALID_FIELD_IN_CDB, 0);
1463 return check_condition_result;
1464 }
1465 } else {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001466 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1467 INVALID_FIELD_IN_CDB, 0);
1468 return check_condition_result;
1469 }
1470 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1471 return fill_from_dev_buffer(scp, arr,
1472 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1473}
1474
1475static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
1476 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477{
1478 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001479 unsigned int block, from_bottom;
1480 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 int ret;
1482
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001483 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1485 0);
1486 return check_condition_result;
1487 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001488 /* transfer length excessive (tie in to block limits VPD page) */
1489 if (num > sdebug_store_sectors) {
1490 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1491 0);
1492 return check_condition_result;
1493 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001495 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1496 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1497 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1499 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001500 /* set info field and valid bit for fixed descriptor */
1501 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1502 devip->sense_buff[0] |= 0x80; /* Valid bit */
1503 ret = OPT_MEDIUM_ERR_ADDR;
1504 devip->sense_buff[3] = (ret >> 24) & 0xff;
1505 devip->sense_buff[4] = (ret >> 16) & 0xff;
1506 devip->sense_buff[5] = (ret >> 8) & 0xff;
1507 devip->sense_buff[6] = ret & 0xff;
1508 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 return check_condition_result;
1510 }
1511 read_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001512 if ((lba + num) <= sdebug_store_sectors)
1513 ret = fill_from_dev_buffer(SCpnt,
1514 fake_storep + (lba * SECT_SIZE),
1515 num * SECT_SIZE);
1516 else {
1517 /* modulo when one arg is 64 bits needs do_div() */
1518 u = lba;
1519 block = do_div(u, sdebug_store_sectors);
1520 from_bottom = 0;
1521 if ((block + num) > sdebug_store_sectors)
1522 from_bottom = (block + num) - sdebug_store_sectors;
1523 ret = fill_from_dev_buffer(SCpnt,
1524 fake_storep + (block * SECT_SIZE),
1525 (num - from_bottom) * SECT_SIZE);
1526 if ((0 == ret) && (from_bottom > 0))
1527 ret = fill_from_dev_buffer(SCpnt, fake_storep,
1528 from_bottom * SECT_SIZE);
1529 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 read_unlock_irqrestore(&atomic_rw, iflags);
1531 return ret;
1532}
1533
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001534static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
1535 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536{
1537 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001538 unsigned int block, to_bottom;
1539 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 int res;
1541
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001542 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1544 0);
1545 return check_condition_result;
1546 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001547 /* transfer length excessive (tie in to block limits VPD page) */
1548 if (num > sdebug_store_sectors) {
1549 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1550 0);
1551 return check_condition_result;
1552 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553
1554 write_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001555 if ((lba + num) <= sdebug_store_sectors)
1556 res = fetch_to_dev_buffer(SCpnt,
1557 fake_storep + (lba * SECT_SIZE),
1558 num * SECT_SIZE);
1559 else {
1560 /* modulo when one arg is 64 bits needs do_div() */
1561 u = lba;
1562 block = do_div(u, sdebug_store_sectors);
1563 to_bottom = 0;
1564 if ((block + num) > sdebug_store_sectors)
1565 to_bottom = (block + num) - sdebug_store_sectors;
1566 res = fetch_to_dev_buffer(SCpnt,
1567 fake_storep + (block * SECT_SIZE),
1568 (num - to_bottom) * SECT_SIZE);
1569 if ((0 == res) && (to_bottom > 0))
1570 res = fetch_to_dev_buffer(SCpnt, fake_storep,
1571 to_bottom * SECT_SIZE);
1572 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 write_unlock_irqrestore(&atomic_rw, iflags);
1574 if (-1 == res)
1575 return (DID_ERROR << 16);
1576 else if ((res < (num * SECT_SIZE)) &&
1577 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001578 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 " IO sent=%d bytes\n", num * SECT_SIZE, res);
1580 return 0;
1581}
1582
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001583#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584
1585static int resp_report_luns(struct scsi_cmnd * scp,
1586 struct sdebug_dev_info * devip)
1587{
1588 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001589 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 unsigned char *cmd = (unsigned char *)scp->cmnd;
1591 int select_report = (int)cmd[2];
1592 struct scsi_lun *one_lun;
1593 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001594 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595
1596 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001597 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1599 0);
1600 return check_condition_result;
1601 }
1602 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
1603 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
1604 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001605 if (1 == select_report)
1606 lun_cnt = 0;
1607 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
1608 --lun_cnt;
1609 wlun = (select_report > 0) ? 1 : 0;
1610 num = lun_cnt + wlun;
1611 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
1612 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
1613 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
1614 sizeof(struct scsi_lun)), num);
1615 if (n < num) {
1616 wlun = 0;
1617 lun_cnt = n;
1618 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001620 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
1621 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
1622 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
1623 i++, lun++) {
1624 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 if (upper)
1626 one_lun[i].scsi_lun[0] =
1627 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001628 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001630 if (wlun) {
1631 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
1632 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
1633 i++;
1634 }
1635 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 return fill_from_dev_buffer(scp, arr,
1637 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
1638}
1639
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001640static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
1641 unsigned int num, struct sdebug_dev_info *devip)
1642{
1643 int i, j, ret = -1;
1644 unsigned char *kaddr, *buf;
1645 unsigned int offset;
1646 struct scatterlist *sg;
1647 struct scsi_data_buffer *sdb = scsi_in(scp);
1648
1649 /* better not to use temporary buffer. */
1650 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
1651 if (!buf)
1652 return ret;
1653
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001654 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001655
1656 offset = 0;
1657 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
1658 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
1659 if (!kaddr)
1660 goto out;
1661
1662 for (j = 0; j < sg->length; j++)
1663 *(kaddr + sg->offset + j) ^= *(buf + offset + j);
1664
1665 offset += sg->length;
1666 kunmap_atomic(kaddr, KM_USER0);
1667 }
1668 ret = 0;
1669out:
1670 kfree(buf);
1671
1672 return ret;
1673}
1674
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675/* When timer goes off this function is called. */
1676static void timer_intr_handler(unsigned long indx)
1677{
1678 struct sdebug_queued_cmd * sqcp;
1679 unsigned long iflags;
1680
1681 if (indx >= SCSI_DEBUG_CANQUEUE) {
1682 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
1683 "large\n");
1684 return;
1685 }
1686 spin_lock_irqsave(&queued_arr_lock, iflags);
1687 sqcp = &queued_arr[(int)indx];
1688 if (! sqcp->in_use) {
1689 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
1690 "interrupt\n");
1691 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1692 return;
1693 }
1694 sqcp->in_use = 0;
1695 if (sqcp->done_funct) {
1696 sqcp->a_cmnd->result = sqcp->scsi_result;
1697 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
1698 }
1699 sqcp->done_funct = NULL;
1700 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1701}
1702
1703static int scsi_debug_slave_alloc(struct scsi_device * sdp)
1704{
1705 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001706 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
1707 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001708 set_bit(QUEUE_FLAG_BIDI, &sdp->request_queue->queue_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 return 0;
1710}
1711
1712static int scsi_debug_slave_configure(struct scsi_device * sdp)
1713{
1714 struct sdebug_dev_info * devip;
1715
1716 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001717 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
1718 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
1720 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
1721 devip = devInfoReg(sdp);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001722 if (NULL == devip)
1723 return 1; /* no resources, will be marked offline */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 sdp->hostdata = devip;
1725 if (sdp->host->cmd_per_lun)
1726 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
1727 sdp->host->cmd_per_lun);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001728 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 return 0;
1730}
1731
1732static void scsi_debug_slave_destroy(struct scsi_device * sdp)
1733{
1734 struct sdebug_dev_info * devip =
1735 (struct sdebug_dev_info *)sdp->hostdata;
1736
1737 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001738 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
1739 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 if (devip) {
1741 /* make this slot avaliable for re-use */
1742 devip->used = 0;
1743 sdp->hostdata = NULL;
1744 }
1745}
1746
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09001747struct sdebug_dev_info *sdebug_device_create(struct sdebug_host_info *sdbg_host,
1748 gfp_t flags)
1749{
1750 struct sdebug_dev_info *devip;
1751
1752 devip = kzalloc(sizeof(*devip), flags);
1753 if (devip) {
1754 devip->sdbg_host = sdbg_host;
1755 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
1756 }
1757 return devip;
1758}
1759
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
1761{
1762 struct sdebug_host_info * sdbg_host;
1763 struct sdebug_dev_info * open_devip = NULL;
1764 struct sdebug_dev_info * devip =
1765 (struct sdebug_dev_info *)sdev->hostdata;
1766
1767 if (devip)
1768 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09001769 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
1770 if (!sdbg_host) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 printk(KERN_ERR "Host info NULL\n");
1772 return NULL;
1773 }
1774 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
1775 if ((devip->used) && (devip->channel == sdev->channel) &&
1776 (devip->target == sdev->id) &&
1777 (devip->lun == sdev->lun))
1778 return devip;
1779 else {
1780 if ((!devip->used) && (!open_devip))
1781 open_devip = devip;
1782 }
1783 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09001784 if (!open_devip) { /* try and make a new one */
1785 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
1786 if (!open_devip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 printk(KERN_ERR "%s: out of memory at line %d\n",
1788 __FUNCTION__, __LINE__);
1789 return NULL;
1790 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09001792
1793 open_devip->channel = sdev->channel;
1794 open_devip->target = sdev->id;
1795 open_devip->lun = sdev->lun;
1796 open_devip->sdbg_host = sdbg_host;
1797 open_devip->reset = 1;
1798 open_devip->used = 1;
1799 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
1800 if (scsi_debug_dsense)
1801 open_devip->sense_buff[0] = 0x72;
1802 else {
1803 open_devip->sense_buff[0] = 0x70;
1804 open_devip->sense_buff[7] = 0xa;
1805 }
1806 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
1807 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
1808
1809 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810}
1811
1812static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
1813 int asc, int asq)
1814{
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09001815 unsigned char *sbuff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816
1817 sbuff = devip->sense_buff;
1818 memset(sbuff, 0, SDEBUG_SENSE_LEN);
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09001819
1820 scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
1821
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1823 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
1824 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
1825}
1826
1827static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
1828{
1829 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1830 printk(KERN_INFO "scsi_debug: abort\n");
1831 ++num_aborts;
1832 stop_queued_cmnd(SCpnt);
1833 return SUCCESS;
1834}
1835
1836static int scsi_debug_biosparam(struct scsi_device *sdev,
1837 struct block_device * bdev, sector_t capacity, int *info)
1838{
1839 int res;
1840 unsigned char *buf;
1841
1842 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1843 printk(KERN_INFO "scsi_debug: biosparam\n");
1844 buf = scsi_bios_ptable(bdev);
1845 if (buf) {
1846 res = scsi_partsize(buf, capacity,
1847 &info[2], &info[0], &info[1]);
1848 kfree(buf);
1849 if (! res)
1850 return res;
1851 }
1852 info[0] = sdebug_heads;
1853 info[1] = sdebug_sectors_per;
1854 info[2] = sdebug_cylinders_per;
1855 return 0;
1856}
1857
1858static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
1859{
1860 struct sdebug_dev_info * devip;
1861
1862 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1863 printk(KERN_INFO "scsi_debug: device_reset\n");
1864 ++num_dev_resets;
1865 if (SCpnt) {
1866 devip = devInfoReg(SCpnt->device);
1867 if (devip)
1868 devip->reset = 1;
1869 }
1870 return SUCCESS;
1871}
1872
1873static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
1874{
1875 struct sdebug_host_info *sdbg_host;
1876 struct sdebug_dev_info * dev_info;
1877 struct scsi_device * sdp;
1878 struct Scsi_Host * hp;
1879
1880 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1881 printk(KERN_INFO "scsi_debug: bus_reset\n");
1882 ++num_bus_resets;
1883 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09001884 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 if (sdbg_host) {
1886 list_for_each_entry(dev_info,
1887 &sdbg_host->dev_info_list,
1888 dev_list)
1889 dev_info->reset = 1;
1890 }
1891 }
1892 return SUCCESS;
1893}
1894
1895static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
1896{
1897 struct sdebug_host_info * sdbg_host;
1898 struct sdebug_dev_info * dev_info;
1899
1900 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1901 printk(KERN_INFO "scsi_debug: host_reset\n");
1902 ++num_host_resets;
1903 spin_lock(&sdebug_host_list_lock);
1904 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
1905 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
1906 dev_list)
1907 dev_info->reset = 1;
1908 }
1909 spin_unlock(&sdebug_host_list_lock);
1910 stop_all_queued();
1911 return SUCCESS;
1912}
1913
1914/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
1915static int stop_queued_cmnd(struct scsi_cmnd * cmnd)
1916{
1917 unsigned long iflags;
1918 int k;
1919 struct sdebug_queued_cmd * sqcp;
1920
1921 spin_lock_irqsave(&queued_arr_lock, iflags);
1922 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1923 sqcp = &queued_arr[k];
1924 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
1925 del_timer_sync(&sqcp->cmnd_timer);
1926 sqcp->in_use = 0;
1927 sqcp->a_cmnd = NULL;
1928 break;
1929 }
1930 }
1931 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1932 return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
1933}
1934
1935/* Deletes (stops) timers of all queued commands */
1936static void stop_all_queued(void)
1937{
1938 unsigned long iflags;
1939 int k;
1940 struct sdebug_queued_cmd * sqcp;
1941
1942 spin_lock_irqsave(&queued_arr_lock, iflags);
1943 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1944 sqcp = &queued_arr[k];
1945 if (sqcp->in_use && sqcp->a_cmnd) {
1946 del_timer_sync(&sqcp->cmnd_timer);
1947 sqcp->in_use = 0;
1948 sqcp->a_cmnd = NULL;
1949 }
1950 }
1951 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1952}
1953
1954/* Initializes timers in queued array */
1955static void __init init_all_queued(void)
1956{
1957 unsigned long iflags;
1958 int k;
1959 struct sdebug_queued_cmd * sqcp;
1960
1961 spin_lock_irqsave(&queued_arr_lock, iflags);
1962 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1963 sqcp = &queued_arr[k];
1964 init_timer(&sqcp->cmnd_timer);
1965 sqcp->in_use = 0;
1966 sqcp->a_cmnd = NULL;
1967 }
1968 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1969}
1970
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09001971static void __init sdebug_build_parts(unsigned char *ramp,
1972 unsigned int store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973{
1974 struct partition * pp;
1975 int starts[SDEBUG_MAX_PARTS + 2];
1976 int sectors_per_part, num_sectors, k;
1977 int heads_by_sects, start_sec, end_sec;
1978
1979 /* assume partition table already zeroed */
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09001980 if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 return;
1982 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
1983 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
1984 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
1985 "partitions to %d\n", SDEBUG_MAX_PARTS);
1986 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001987 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 sectors_per_part = (num_sectors - sdebug_sectors_per)
1989 / scsi_debug_num_parts;
1990 heads_by_sects = sdebug_heads * sdebug_sectors_per;
1991 starts[0] = sdebug_sectors_per;
1992 for (k = 1; k < scsi_debug_num_parts; ++k)
1993 starts[k] = ((k * sectors_per_part) / heads_by_sects)
1994 * heads_by_sects;
1995 starts[scsi_debug_num_parts] = num_sectors;
1996 starts[scsi_debug_num_parts + 1] = 0;
1997
1998 ramp[510] = 0x55; /* magic partition markings */
1999 ramp[511] = 0xAA;
2000 pp = (struct partition *)(ramp + 0x1be);
2001 for (k = 0; starts[k + 1]; ++k, ++pp) {
2002 start_sec = starts[k];
2003 end_sec = starts[k + 1] - 1;
2004 pp->boot_ind = 0;
2005
2006 pp->cyl = start_sec / heads_by_sects;
2007 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2008 / sdebug_sectors_per;
2009 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2010
2011 pp->end_cyl = end_sec / heads_by_sects;
2012 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2013 / sdebug_sectors_per;
2014 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2015
2016 pp->start_sect = start_sec;
2017 pp->nr_sects = end_sec - start_sec + 1;
2018 pp->sys_ind = 0x83; /* plain Linux partition */
2019 }
2020}
2021
2022static int schedule_resp(struct scsi_cmnd * cmnd,
2023 struct sdebug_dev_info * devip,
2024 done_funct_t done, int scsi_result, int delta_jiff)
2025{
2026 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2027 if (scsi_result) {
2028 struct scsi_device * sdp = cmnd->device;
2029
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002030 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2031 "non-zero result=0x%x\n", sdp->host->host_no,
2032 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 }
2034 }
2035 if (cmnd && devip) {
2036 /* simulate autosense by this driver */
2037 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2038 memcpy(cmnd->sense_buffer, devip->sense_buff,
2039 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2040 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2041 }
2042 if (delta_jiff <= 0) {
2043 if (cmnd)
2044 cmnd->result = scsi_result;
2045 if (done)
2046 done(cmnd);
2047 return 0;
2048 } else {
2049 unsigned long iflags;
2050 int k;
2051 struct sdebug_queued_cmd * sqcp = NULL;
2052
2053 spin_lock_irqsave(&queued_arr_lock, iflags);
2054 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2055 sqcp = &queued_arr[k];
2056 if (! sqcp->in_use)
2057 break;
2058 }
2059 if (k >= SCSI_DEBUG_CANQUEUE) {
2060 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2061 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2062 return 1; /* report busy to mid level */
2063 }
2064 sqcp->in_use = 1;
2065 sqcp->a_cmnd = cmnd;
2066 sqcp->scsi_result = scsi_result;
2067 sqcp->done_funct = done;
2068 sqcp->cmnd_timer.function = timer_intr_handler;
2069 sqcp->cmnd_timer.data = k;
2070 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2071 add_timer(&sqcp->cmnd_timer);
2072 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2073 if (cmnd)
2074 cmnd->result = 0;
2075 return 0;
2076 }
2077}
2078
Douglas Gilbert23183912006-09-16 20:30:47 -04002079/* Note: The following macros create attribute files in the
2080 /sys/module/scsi_debug/parameters directory. Unfortunately this
2081 driver is unaware of a change and cannot trigger auxiliary actions
2082 as it can when the corresponding attribute in the
2083 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2084 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002085module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2086module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2087module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2088module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2089module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002090module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002091module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2092module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2093module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2094module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2095module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2096module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2097module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2098module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002099module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2100 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101
2102MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2103MODULE_DESCRIPTION("SCSI debug adapter driver");
2104MODULE_LICENSE("GPL");
2105MODULE_VERSION(SCSI_DEBUG_VERSION);
2106
2107MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2108MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002109MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2110MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07002111MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002112MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002113MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2114MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002116MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002117MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2119MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002120MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002121MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122
2123
2124static char sdebug_info[256];
2125
2126static const char * scsi_debug_info(struct Scsi_Host * shp)
2127{
2128 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2129 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2130 scsi_debug_version_date, scsi_debug_dev_size_mb,
2131 scsi_debug_opts);
2132 return sdebug_info;
2133}
2134
2135/* scsi_debug_proc_info
2136 * Used if the driver currently has no own support for /proc/scsi
2137 */
2138static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2139 int length, int inout)
2140{
2141 int len, pos, begin;
2142 int orig_length;
2143
2144 orig_length = length;
2145
2146 if (inout == 1) {
2147 char arr[16];
2148 int minLen = length > 15 ? 15 : length;
2149
2150 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2151 return -EACCES;
2152 memcpy(arr, buffer, minLen);
2153 arr[minLen] = '\0';
2154 if (1 != sscanf(arr, "%d", &pos))
2155 return -EINVAL;
2156 scsi_debug_opts = pos;
2157 if (scsi_debug_every_nth != 0)
2158 scsi_debug_cmnd_count = 0;
2159 return length;
2160 }
2161 begin = 0;
2162 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2163 "%s [%s]\n"
2164 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2165 "every_nth=%d(curr:%d)\n"
2166 "delay=%d, max_luns=%d, scsi_level=%d\n"
2167 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2168 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
2169 "host_resets=%d\n",
2170 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2171 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2172 scsi_debug_cmnd_count, scsi_debug_delay,
2173 scsi_debug_max_luns, scsi_debug_scsi_level,
2174 SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
2175 num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
2176 if (pos < offset) {
2177 len = 0;
2178 begin = pos;
2179 }
2180 *start = buffer + (offset - begin); /* Start of wanted data */
2181 len -= (offset - begin);
2182 if (len > length)
2183 len = length;
2184 return len;
2185}
2186
2187static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2188{
2189 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2190}
2191
2192static ssize_t sdebug_delay_store(struct device_driver * ddp,
2193 const char * buf, size_t count)
2194{
2195 int delay;
2196 char work[20];
2197
2198 if (1 == sscanf(buf, "%10s", work)) {
2199 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2200 scsi_debug_delay = delay;
2201 return count;
2202 }
2203 }
2204 return -EINVAL;
2205}
2206DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2207 sdebug_delay_store);
2208
2209static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2210{
2211 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2212}
2213
2214static ssize_t sdebug_opts_store(struct device_driver * ddp,
2215 const char * buf, size_t count)
2216{
2217 int opts;
2218 char work[20];
2219
2220 if (1 == sscanf(buf, "%10s", work)) {
2221 if (0 == strnicmp(work,"0x", 2)) {
2222 if (1 == sscanf(&work[2], "%x", &opts))
2223 goto opts_done;
2224 } else {
2225 if (1 == sscanf(work, "%d", &opts))
2226 goto opts_done;
2227 }
2228 }
2229 return -EINVAL;
2230opts_done:
2231 scsi_debug_opts = opts;
2232 scsi_debug_cmnd_count = 0;
2233 return count;
2234}
2235DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2236 sdebug_opts_store);
2237
2238static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2239{
2240 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2241}
2242static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2243 const char * buf, size_t count)
2244{
2245 int n;
2246
2247 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2248 scsi_debug_ptype = n;
2249 return count;
2250 }
2251 return -EINVAL;
2252}
2253DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2254
2255static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2256{
2257 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2258}
2259static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2260 const char * buf, size_t count)
2261{
2262 int n;
2263
2264 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2265 scsi_debug_dsense = n;
2266 return count;
2267 }
2268 return -EINVAL;
2269}
2270DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2271 sdebug_dsense_store);
2272
Douglas Gilbert23183912006-09-16 20:30:47 -04002273static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2274{
2275 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2276}
2277static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2278 const char * buf, size_t count)
2279{
2280 int n;
2281
2282 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2283 scsi_debug_fake_rw = n;
2284 return count;
2285 }
2286 return -EINVAL;
2287}
2288DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2289 sdebug_fake_rw_store);
2290
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002291static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2292{
2293 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2294}
2295static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2296 const char * buf, size_t count)
2297{
2298 int n;
2299
2300 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2301 scsi_debug_no_lun_0 = n;
2302 return count;
2303 }
2304 return -EINVAL;
2305}
2306DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2307 sdebug_no_lun_0_store);
2308
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2310{
2311 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2312}
2313static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2314 const char * buf, size_t count)
2315{
2316 int n;
2317
2318 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2319 scsi_debug_num_tgts = n;
2320 sdebug_max_tgts_luns();
2321 return count;
2322 }
2323 return -EINVAL;
2324}
2325DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2326 sdebug_num_tgts_store);
2327
2328static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2329{
2330 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2331}
2332DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2333
2334static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2335{
2336 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2337}
2338DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2339
2340static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2341{
2342 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2343}
2344static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2345 const char * buf, size_t count)
2346{
2347 int nth;
2348
2349 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2350 scsi_debug_every_nth = nth;
2351 scsi_debug_cmnd_count = 0;
2352 return count;
2353 }
2354 return -EINVAL;
2355}
2356DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2357 sdebug_every_nth_store);
2358
2359static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2360{
2361 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2362}
2363static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2364 const char * buf, size_t count)
2365{
2366 int n;
2367
2368 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2369 scsi_debug_max_luns = n;
2370 sdebug_max_tgts_luns();
2371 return count;
2372 }
2373 return -EINVAL;
2374}
2375DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2376 sdebug_max_luns_store);
2377
2378static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
2379{
2380 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
2381}
2382DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
2383
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002384static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2385{
2386 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2387}
2388static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2389 const char * buf, size_t count)
2390{
2391 int n;
2392
2393 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2394 scsi_debug_virtual_gb = n;
2395 if (scsi_debug_virtual_gb > 0) {
2396 sdebug_capacity = 2048 * 1024;
2397 sdebug_capacity *= scsi_debug_virtual_gb;
2398 } else
2399 sdebug_capacity = sdebug_store_sectors;
2400 return count;
2401 }
2402 return -EINVAL;
2403}
2404DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2405 sdebug_virtual_gb_store);
2406
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
2408{
2409 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
2410}
2411
2412static ssize_t sdebug_add_host_store(struct device_driver * ddp,
2413 const char * buf, size_t count)
2414{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002415 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002417 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 if (delta_hosts > 0) {
2420 do {
2421 sdebug_add_adapter();
2422 } while (--delta_hosts);
2423 } else if (delta_hosts < 0) {
2424 do {
2425 sdebug_remove_adapter();
2426 } while (++delta_hosts);
2427 }
2428 return count;
2429}
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002430DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 sdebug_add_host_store);
2432
Douglas Gilbert23183912006-09-16 20:30:47 -04002433static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
2434 char * buf)
2435{
2436 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
2437}
2438static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
2439 const char * buf, size_t count)
2440{
2441 int n;
2442
2443 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2444 scsi_debug_vpd_use_hostno = n;
2445 return count;
2446 }
2447 return -EINVAL;
2448}
2449DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
2450 sdebug_vpd_use_hostno_store);
2451
2452/* Note: The following function creates attribute files in the
2453 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
2454 files (over those found in the /sys/module/scsi_debug/parameters
2455 directory) is that auxiliary actions can be triggered when an attribute
2456 is changed. For example see: sdebug_add_host_store() above.
2457 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002458static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002460 int ret;
2461
2462 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2463 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
2464 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2465 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2466 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04002467 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002468 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002469 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002470 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002471 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002472 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
2473 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
2474 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04002475 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
2476 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002477 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478}
2479
2480static void do_remove_driverfs_files(void)
2481{
Douglas Gilbert23183912006-09-16 20:30:47 -04002482 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
2483 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
2485 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
2486 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002488 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
2489 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002491 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
2493 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2494 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2495 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
2496 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2497}
2498
2499static int __init scsi_debug_init(void)
2500{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002501 unsigned int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502 int host_to_add;
2503 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002504 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505
2506 if (scsi_debug_dev_size_mb < 1)
2507 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002508 sz = (unsigned int)scsi_debug_dev_size_mb * 1048576;
2509 sdebug_store_sectors = sz / SECT_SIZE;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002510 if (scsi_debug_virtual_gb > 0) {
2511 sdebug_capacity = 2048 * 1024;
2512 sdebug_capacity *= scsi_debug_virtual_gb;
2513 } else
2514 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515
2516 /* play around with geometry, don't waste too much on track 0 */
2517 sdebug_heads = 8;
2518 sdebug_sectors_per = 32;
2519 if (scsi_debug_dev_size_mb >= 16)
2520 sdebug_heads = 32;
2521 else if (scsi_debug_dev_size_mb >= 256)
2522 sdebug_heads = 64;
2523 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2524 (sdebug_sectors_per * sdebug_heads);
2525 if (sdebug_cylinders_per >= 1024) {
2526 /* other LLDs do this; implies >= 1GB ram disk ... */
2527 sdebug_heads = 255;
2528 sdebug_sectors_per = 63;
2529 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2530 (sdebug_sectors_per * sdebug_heads);
2531 }
2532
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533 fake_storep = vmalloc(sz);
2534 if (NULL == fake_storep) {
2535 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
2536 return -ENOMEM;
2537 }
2538 memset(fake_storep, 0, sz);
2539 if (scsi_debug_num_parts > 0)
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002540 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002542 ret = device_register(&pseudo_primary);
2543 if (ret < 0) {
2544 printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
2545 ret);
2546 goto free_vm;
2547 }
2548 ret = bus_register(&pseudo_lld_bus);
2549 if (ret < 0) {
2550 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
2551 ret);
2552 goto dev_unreg;
2553 }
2554 ret = driver_register(&sdebug_driverfs_driver);
2555 if (ret < 0) {
2556 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
2557 ret);
2558 goto bus_unreg;
2559 }
2560 ret = do_create_driverfs_files();
2561 if (ret < 0) {
2562 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
2563 ret);
2564 goto del_files;
2565 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002567 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 host_to_add = scsi_debug_add_host;
2570 scsi_debug_add_host = 0;
2571
2572 for (k = 0; k < host_to_add; k++) {
2573 if (sdebug_add_adapter()) {
2574 printk(KERN_ERR "scsi_debug_init: "
2575 "sdebug_add_adapter failed k=%d\n", k);
2576 break;
2577 }
2578 }
2579
2580 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
2581 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
2582 scsi_debug_add_host);
2583 }
2584 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002585
2586del_files:
2587 do_remove_driverfs_files();
2588 driver_unregister(&sdebug_driverfs_driver);
2589bus_unreg:
2590 bus_unregister(&pseudo_lld_bus);
2591dev_unreg:
2592 device_unregister(&pseudo_primary);
2593free_vm:
2594 vfree(fake_storep);
2595
2596 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597}
2598
2599static void __exit scsi_debug_exit(void)
2600{
2601 int k = scsi_debug_add_host;
2602
2603 stop_all_queued();
2604 for (; k; k--)
2605 sdebug_remove_adapter();
2606 do_remove_driverfs_files();
2607 driver_unregister(&sdebug_driverfs_driver);
2608 bus_unregister(&pseudo_lld_bus);
2609 device_unregister(&pseudo_primary);
2610
2611 vfree(fake_storep);
2612}
2613
2614device_initcall(scsi_debug_init);
2615module_exit(scsi_debug_exit);
2616
Adrian Bunk52c1da32005-06-23 22:05:33 -07002617static void pseudo_0_release(struct device * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618{
2619 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2620 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
2621}
2622
2623static struct device pseudo_primary = {
2624 .bus_id = "pseudo_0",
2625 .release = pseudo_0_release,
2626};
2627
2628static int pseudo_lld_bus_match(struct device *dev,
2629 struct device_driver *dev_driver)
2630{
2631 return 1;
2632}
2633
2634static struct bus_type pseudo_lld_bus = {
2635 .name = "pseudo",
2636 .match = pseudo_lld_bus_match,
Russell Kingbbbe3a42006-01-05 14:44:46 +00002637 .probe = sdebug_driver_probe,
2638 .remove = sdebug_driver_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639};
2640
2641static void sdebug_release_adapter(struct device * dev)
2642{
2643 struct sdebug_host_info *sdbg_host;
2644
2645 sdbg_host = to_sdebug_host(dev);
2646 kfree(sdbg_host);
2647}
2648
2649static int sdebug_add_adapter(void)
2650{
2651 int k, devs_per_host;
2652 int error = 0;
2653 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09002654 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002656 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 if (NULL == sdbg_host) {
2658 printk(KERN_ERR "%s: out of memory at line %d\n",
2659 __FUNCTION__, __LINE__);
2660 return -ENOMEM;
2661 }
2662
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
2664
2665 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
2666 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002667 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
2668 if (!sdbg_devinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 printk(KERN_ERR "%s: out of memory at line %d\n",
2670 __FUNCTION__, __LINE__);
2671 error = -ENOMEM;
2672 goto clean;
2673 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 }
2675
2676 spin_lock(&sdebug_host_list_lock);
2677 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
2678 spin_unlock(&sdebug_host_list_lock);
2679
2680 sdbg_host->dev.bus = &pseudo_lld_bus;
2681 sdbg_host->dev.parent = &pseudo_primary;
2682 sdbg_host->dev.release = &sdebug_release_adapter;
2683 sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host);
2684
2685 error = device_register(&sdbg_host->dev);
2686
2687 if (error)
2688 goto clean;
2689
2690 ++scsi_debug_add_host;
2691 return error;
2692
2693clean:
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09002694 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
2695 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 list_del(&sdbg_devinfo->dev_list);
2697 kfree(sdbg_devinfo);
2698 }
2699
2700 kfree(sdbg_host);
2701 return error;
2702}
2703
2704static void sdebug_remove_adapter(void)
2705{
2706 struct sdebug_host_info * sdbg_host = NULL;
2707
2708 spin_lock(&sdebug_host_list_lock);
2709 if (!list_empty(&sdebug_host_list)) {
2710 sdbg_host = list_entry(sdebug_host_list.prev,
2711 struct sdebug_host_info, host_list);
2712 list_del(&sdbg_host->host_list);
2713 }
2714 spin_unlock(&sdebug_host_list_lock);
2715
2716 if (!sdbg_host)
2717 return;
2718
2719 device_unregister(&sdbg_host->dev);
2720 --scsi_debug_add_host;
2721}
2722
FUJITA Tomonori639db472008-03-20 11:09:19 +09002723static
2724int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
2725{
2726 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
2727 int len, k;
2728 unsigned int num;
2729 unsigned long long lba;
2730 int errsts = 0;
2731 int target = SCpnt->device->id;
2732 struct sdebug_dev_info *devip = NULL;
2733 int inj_recovered = 0;
2734 int inj_transport = 0;
2735 int delay_override = 0;
2736
2737 scsi_set_resid(SCpnt, 0);
2738 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
2739 printk(KERN_INFO "scsi_debug: cmd ");
2740 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
2741 printk("%02x ", (int)cmd[k]);
2742 printk("\n");
2743 }
2744
2745 if (target == SCpnt->device->host->hostt->this_id) {
2746 printk(KERN_INFO "scsi_debug: initiator's id used as "
2747 "target!\n");
2748 return schedule_resp(SCpnt, NULL, done,
2749 DID_NO_CONNECT << 16, 0);
2750 }
2751
2752 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
2753 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
2754 return schedule_resp(SCpnt, NULL, done,
2755 DID_NO_CONNECT << 16, 0);
2756 devip = devInfoReg(SCpnt->device);
2757 if (NULL == devip)
2758 return schedule_resp(SCpnt, NULL, done,
2759 DID_NO_CONNECT << 16, 0);
2760
2761 if ((scsi_debug_every_nth != 0) &&
2762 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
2763 scsi_debug_cmnd_count = 0;
2764 if (scsi_debug_every_nth < -1)
2765 scsi_debug_every_nth = -1;
2766 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
2767 return 0; /* ignore command causing timeout */
2768 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
2769 inj_recovered = 1; /* to reads and writes below */
2770 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
2771 inj_transport = 1; /* to reads and writes below */
2772 }
2773
2774 if (devip->wlun) {
2775 switch (*cmd) {
2776 case INQUIRY:
2777 case REQUEST_SENSE:
2778 case TEST_UNIT_READY:
2779 case REPORT_LUNS:
2780 break; /* only allowable wlun commands */
2781 default:
2782 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2783 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
2784 "not supported for wlun\n", *cmd);
2785 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2786 INVALID_OPCODE, 0);
2787 errsts = check_condition_result;
2788 return schedule_resp(SCpnt, devip, done, errsts,
2789 0);
2790 }
2791 }
2792
2793 switch (*cmd) {
2794 case INQUIRY: /* mandatory, ignore unit attention */
2795 delay_override = 1;
2796 errsts = resp_inquiry(SCpnt, target, devip);
2797 break;
2798 case REQUEST_SENSE: /* mandatory, ignore unit attention */
2799 delay_override = 1;
2800 errsts = resp_requests(SCpnt, devip);
2801 break;
2802 case REZERO_UNIT: /* actually this is REWIND for SSC */
2803 case START_STOP:
2804 errsts = resp_start_stop(SCpnt, devip);
2805 break;
2806 case ALLOW_MEDIUM_REMOVAL:
2807 errsts = check_readiness(SCpnt, 1, devip);
2808 if (errsts)
2809 break;
2810 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2811 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
2812 cmd[4] ? "inhibited" : "enabled");
2813 break;
2814 case SEND_DIAGNOSTIC: /* mandatory */
2815 errsts = check_readiness(SCpnt, 1, devip);
2816 break;
2817 case TEST_UNIT_READY: /* mandatory */
2818 delay_override = 1;
2819 errsts = check_readiness(SCpnt, 0, devip);
2820 break;
2821 case RESERVE:
2822 errsts = check_readiness(SCpnt, 1, devip);
2823 break;
2824 case RESERVE_10:
2825 errsts = check_readiness(SCpnt, 1, devip);
2826 break;
2827 case RELEASE:
2828 errsts = check_readiness(SCpnt, 1, devip);
2829 break;
2830 case RELEASE_10:
2831 errsts = check_readiness(SCpnt, 1, devip);
2832 break;
2833 case READ_CAPACITY:
2834 errsts = resp_readcap(SCpnt, devip);
2835 break;
2836 case SERVICE_ACTION_IN:
2837 if (SAI_READ_CAPACITY_16 != cmd[1]) {
2838 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2839 INVALID_OPCODE, 0);
2840 errsts = check_condition_result;
2841 break;
2842 }
2843 errsts = resp_readcap16(SCpnt, devip);
2844 break;
2845 case MAINTENANCE_IN:
2846 if (MI_REPORT_TARGET_PGS != cmd[1]) {
2847 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2848 INVALID_OPCODE, 0);
2849 errsts = check_condition_result;
2850 break;
2851 }
2852 errsts = resp_report_tgtpgs(SCpnt, devip);
2853 break;
2854 case READ_16:
2855 case READ_12:
2856 case READ_10:
2857 case READ_6:
2858 errsts = check_readiness(SCpnt, 0, devip);
2859 if (errsts)
2860 break;
2861 if (scsi_debug_fake_rw)
2862 break;
2863 get_data_transfer_info(cmd, &lba, &num);
2864 errsts = resp_read(SCpnt, lba, num, devip);
2865 if (inj_recovered && (0 == errsts)) {
2866 mk_sense_buffer(devip, RECOVERED_ERROR,
2867 THRESHOLD_EXCEEDED, 0);
2868 errsts = check_condition_result;
2869 } else if (inj_transport && (0 == errsts)) {
2870 mk_sense_buffer(devip, ABORTED_COMMAND,
2871 TRANSPORT_PROBLEM, ACK_NAK_TO);
2872 errsts = check_condition_result;
2873 }
2874 break;
2875 case REPORT_LUNS: /* mandatory, ignore unit attention */
2876 delay_override = 1;
2877 errsts = resp_report_luns(SCpnt, devip);
2878 break;
2879 case VERIFY: /* 10 byte SBC-2 command */
2880 errsts = check_readiness(SCpnt, 0, devip);
2881 break;
2882 case WRITE_16:
2883 case WRITE_12:
2884 case WRITE_10:
2885 case WRITE_6:
2886 errsts = check_readiness(SCpnt, 0, devip);
2887 if (errsts)
2888 break;
2889 if (scsi_debug_fake_rw)
2890 break;
2891 get_data_transfer_info(cmd, &lba, &num);
2892 errsts = resp_write(SCpnt, lba, num, devip);
2893 if (inj_recovered && (0 == errsts)) {
2894 mk_sense_buffer(devip, RECOVERED_ERROR,
2895 THRESHOLD_EXCEEDED, 0);
2896 errsts = check_condition_result;
2897 }
2898 break;
2899 case MODE_SENSE:
2900 case MODE_SENSE_10:
2901 errsts = resp_mode_sense(SCpnt, target, devip);
2902 break;
2903 case MODE_SELECT:
2904 errsts = resp_mode_select(SCpnt, 1, devip);
2905 break;
2906 case MODE_SELECT_10:
2907 errsts = resp_mode_select(SCpnt, 0, devip);
2908 break;
2909 case LOG_SENSE:
2910 errsts = resp_log_sense(SCpnt, devip);
2911 break;
2912 case SYNCHRONIZE_CACHE:
2913 delay_override = 1;
2914 errsts = check_readiness(SCpnt, 0, devip);
2915 break;
2916 case WRITE_BUFFER:
2917 errsts = check_readiness(SCpnt, 1, devip);
2918 break;
2919 case XDWRITEREAD_10:
2920 if (!scsi_bidi_cmnd(SCpnt)) {
2921 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2922 INVALID_FIELD_IN_CDB, 0);
2923 errsts = check_condition_result;
2924 break;
2925 }
2926
2927 errsts = check_readiness(SCpnt, 0, devip);
2928 if (errsts)
2929 break;
2930 if (scsi_debug_fake_rw)
2931 break;
2932 get_data_transfer_info(cmd, &lba, &num);
2933 errsts = resp_read(SCpnt, lba, num, devip);
2934 if (errsts)
2935 break;
2936 errsts = resp_write(SCpnt, lba, num, devip);
2937 if (errsts)
2938 break;
2939 errsts = resp_xdwriteread(SCpnt, lba, num, devip);
2940 break;
2941 default:
2942 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2943 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
2944 "supported\n", *cmd);
2945 errsts = check_readiness(SCpnt, 1, devip);
2946 if (errsts)
2947 break; /* Unit attention takes precedence */
2948 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
2949 errsts = check_condition_result;
2950 break;
2951 }
2952 return schedule_resp(SCpnt, devip, done, errsts,
2953 (delay_override ? 0 : scsi_debug_delay));
2954}
2955
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09002956static struct scsi_host_template sdebug_driver_template = {
2957 .proc_info = scsi_debug_proc_info,
2958 .proc_name = sdebug_proc_name,
2959 .name = "SCSI DEBUG",
2960 .info = scsi_debug_info,
2961 .slave_alloc = scsi_debug_slave_alloc,
2962 .slave_configure = scsi_debug_slave_configure,
2963 .slave_destroy = scsi_debug_slave_destroy,
2964 .ioctl = scsi_debug_ioctl,
2965 .queuecommand = scsi_debug_queuecommand,
2966 .eh_abort_handler = scsi_debug_abort,
2967 .eh_bus_reset_handler = scsi_debug_bus_reset,
2968 .eh_device_reset_handler = scsi_debug_device_reset,
2969 .eh_host_reset_handler = scsi_debug_host_reset,
2970 .bios_param = scsi_debug_biosparam,
2971 .can_queue = SCSI_DEBUG_CANQUEUE,
2972 .this_id = 7,
2973 .sg_tablesize = 256,
2974 .cmd_per_lun = 16,
2975 .max_sectors = 0xffff,
2976 .use_clustering = DISABLE_CLUSTERING,
2977 .module = THIS_MODULE,
2978};
2979
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980static int sdebug_driver_probe(struct device * dev)
2981{
2982 int error = 0;
2983 struct sdebug_host_info *sdbg_host;
2984 struct Scsi_Host *hpnt;
2985
2986 sdbg_host = to_sdebug_host(dev);
2987
2988 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
2989 if (NULL == hpnt) {
2990 printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__);
2991 error = -ENODEV;
2992 return error;
2993 }
2994
2995 sdbg_host->shost = hpnt;
2996 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
2997 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
2998 hpnt->max_id = scsi_debug_num_tgts + 1;
2999 else
3000 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003001 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002
3003 error = scsi_add_host(hpnt, &sdbg_host->dev);
3004 if (error) {
3005 printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
3006 error = -ENODEV;
3007 scsi_host_put(hpnt);
3008 } else
3009 scsi_scan_host(hpnt);
3010
3011
3012 return error;
3013}
3014
3015static int sdebug_driver_remove(struct device * dev)
3016{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003018 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019
3020 sdbg_host = to_sdebug_host(dev);
3021
3022 if (!sdbg_host) {
3023 printk(KERN_ERR "%s: Unable to locate host info\n",
3024 __FUNCTION__);
3025 return -ENODEV;
3026 }
3027
3028 scsi_remove_host(sdbg_host->shost);
3029
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003030 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
3031 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032 list_del(&sdbg_devinfo->dev_list);
3033 kfree(sdbg_devinfo);
3034 }
3035
3036 scsi_host_put(sdbg_host->shost);
3037 return 0;
3038}
3039
3040static void sdebug_max_tgts_luns(void)
3041{
3042 struct sdebug_host_info * sdbg_host;
3043 struct Scsi_Host *hpnt;
3044
3045 spin_lock(&sdebug_host_list_lock);
3046 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3047 hpnt = sdbg_host->shost;
3048 if ((hpnt->this_id >= 0) &&
3049 (scsi_debug_num_tgts > hpnt->this_id))
3050 hpnt->max_id = scsi_debug_num_tgts + 1;
3051 else
3052 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003053 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 }
3055 spin_unlock(&sdebug_host_list_lock);
3056}