blob: 1b6a6d8e5d27ad3f9d11fc84c18f8f4e9ab81aac [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
FUJITA Tomonori28898872008-03-30 00:59:55 +0900826static sector_t get_sdebug_capacity(void)
827{
828 if (scsi_debug_virtual_gb > 0)
829 return 2048 * 1024 * scsi_debug_virtual_gb;
830 else
831 return sdebug_store_sectors;
832}
833
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834#define SDEBUG_READCAP_ARR_SZ 8
835static int resp_readcap(struct scsi_cmnd * scp,
836 struct sdebug_dev_info * devip)
837{
838 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400839 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 int errsts;
841
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400842 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400844 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +0900845 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400847 if (sdebug_capacity < 0xffffffff) {
848 capac = (unsigned int)sdebug_capacity - 1;
849 arr[0] = (capac >> 24);
850 arr[1] = (capac >> 16) & 0xff;
851 arr[2] = (capac >> 8) & 0xff;
852 arr[3] = capac & 0xff;
853 } else {
854 arr[0] = 0xff;
855 arr[1] = 0xff;
856 arr[2] = 0xff;
857 arr[3] = 0xff;
858 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
860 arr[7] = SECT_SIZE_PER(target) & 0xff;
861 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
862}
863
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400864#define SDEBUG_READCAP16_ARR_SZ 32
865static int resp_readcap16(struct scsi_cmnd * scp,
866 struct sdebug_dev_info * devip)
867{
868 unsigned char *cmd = (unsigned char *)scp->cmnd;
869 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
870 unsigned long long capac;
871 int errsts, k, alloc_len;
872
873 if ((errsts = check_readiness(scp, 1, devip)))
874 return errsts;
875 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
876 + cmd[13]);
877 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +0900878 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400879 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;
FUJITA Tomonori28898872008-03-30 00:59:55 +09001172 if ((bd_len > 0) && (!sdebug_capacity))
1173 sdebug_capacity = get_sdebug_capacity();
1174
Douglas Gilbert23183912006-09-16 20:30:47 -04001175 if (8 == bd_len) {
1176 if (sdebug_capacity > 0xfffffffe) {
1177 ap[0] = 0xff;
1178 ap[1] = 0xff;
1179 ap[2] = 0xff;
1180 ap[3] = 0xff;
1181 } else {
1182 ap[0] = (sdebug_capacity >> 24) & 0xff;
1183 ap[1] = (sdebug_capacity >> 16) & 0xff;
1184 ap[2] = (sdebug_capacity >> 8) & 0xff;
1185 ap[3] = sdebug_capacity & 0xff;
1186 }
1187 ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1188 ap[7] = SECT_SIZE_PER(target) & 0xff;
1189 offset += bd_len;
1190 ap = arr + offset;
1191 } else if (16 == bd_len) {
1192 unsigned long long capac = sdebug_capacity;
1193
1194 for (k = 0; k < 8; ++k, capac >>= 8)
1195 ap[7 - k] = capac & 0xff;
1196 ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff;
1197 ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff;
1198 ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1199 ap[15] = SECT_SIZE_PER(target) & 0xff;
1200 offset += bd_len;
1201 ap = arr + offset;
1202 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001204 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1205 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1207 0);
1208 return check_condition_result;
1209 }
1210 switch (pcode) {
1211 case 0x1: /* Read-Write error recovery page, direct access */
1212 len = resp_err_recov_pg(ap, pcontrol, target);
1213 offset += len;
1214 break;
1215 case 0x2: /* Disconnect-Reconnect page, all devices */
1216 len = resp_disconnect_pg(ap, pcontrol, target);
1217 offset += len;
1218 break;
1219 case 0x3: /* Format device page, direct access */
1220 len = resp_format_pg(ap, pcontrol, target);
1221 offset += len;
1222 break;
1223 case 0x8: /* Caching page, direct access */
1224 len = resp_caching_pg(ap, pcontrol, target);
1225 offset += len;
1226 break;
1227 case 0xa: /* Control Mode page, all devices */
1228 len = resp_ctrl_m_pg(ap, pcontrol, target);
1229 offset += len;
1230 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001231 case 0x19: /* if spc==1 then sas phy, control+discover */
1232 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1233 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1234 INVALID_FIELD_IN_CDB, 0);
1235 return check_condition_result;
1236 }
1237 len = 0;
1238 if ((0x0 == subpcode) || (0xff == subpcode))
1239 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1240 if ((0x1 == subpcode) || (0xff == subpcode))
1241 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1242 target_dev_id);
1243 if ((0x2 == subpcode) || (0xff == subpcode))
1244 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1245 offset += len;
1246 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 case 0x1c: /* Informational Exceptions Mode page, all devices */
1248 len = resp_iec_m_pg(ap, pcontrol, target);
1249 offset += len;
1250 break;
1251 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001252 if ((0 == subpcode) || (0xff == subpcode)) {
1253 len = resp_err_recov_pg(ap, pcontrol, target);
1254 len += resp_disconnect_pg(ap + len, pcontrol, target);
1255 len += resp_format_pg(ap + len, pcontrol, target);
1256 len += resp_caching_pg(ap + len, pcontrol, target);
1257 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1258 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1259 if (0xff == subpcode) {
1260 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1261 target, target_dev_id);
1262 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1263 }
1264 len += resp_iec_m_pg(ap + len, pcontrol, target);
1265 } else {
1266 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1267 INVALID_FIELD_IN_CDB, 0);
1268 return check_condition_result;
1269 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 offset += len;
1271 break;
1272 default:
1273 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1274 0);
1275 return check_condition_result;
1276 }
1277 if (msense_6)
1278 arr[0] = offset - 1;
1279 else {
1280 arr[0] = ((offset - 2) >> 8) & 0xff;
1281 arr[1] = (offset - 2) & 0xff;
1282 }
1283 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1284}
1285
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001286#define SDEBUG_MAX_MSELECT_SZ 512
1287
1288static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1289 struct sdebug_dev_info * devip)
1290{
1291 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1292 int param_len, res, errsts, mpage;
1293 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1294 unsigned char *cmd = (unsigned char *)scp->cmnd;
1295
1296 if ((errsts = check_readiness(scp, 1, devip)))
1297 return errsts;
1298 memset(arr, 0, sizeof(arr));
1299 pf = cmd[1] & 0x10;
1300 sp = cmd[1] & 0x1;
1301 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1302 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1303 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1304 INVALID_FIELD_IN_CDB, 0);
1305 return check_condition_result;
1306 }
1307 res = fetch_to_dev_buffer(scp, arr, param_len);
1308 if (-1 == res)
1309 return (DID_ERROR << 16);
1310 else if ((res < param_len) &&
1311 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1312 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1313 " IO sent=%d bytes\n", param_len, res);
1314 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1315 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001316 if (md_len > 2) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001317 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1318 INVALID_FIELD_IN_PARAM_LIST, 0);
1319 return check_condition_result;
1320 }
1321 off = bd_len + (mselect6 ? 4 : 8);
1322 mpage = arr[off] & 0x3f;
1323 ps = !!(arr[off] & 0x80);
1324 if (ps) {
1325 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1326 INVALID_FIELD_IN_PARAM_LIST, 0);
1327 return check_condition_result;
1328 }
1329 spf = !!(arr[off] & 0x40);
1330 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1331 (arr[off + 1] + 2);
1332 if ((pg_len + off) > param_len) {
1333 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1334 PARAMETER_LIST_LENGTH_ERR, 0);
1335 return check_condition_result;
1336 }
1337 switch (mpage) {
1338 case 0xa: /* Control Mode page */
1339 if (ctrl_m_pg[1] == arr[off + 1]) {
1340 memcpy(ctrl_m_pg + 2, arr + off + 2,
1341 sizeof(ctrl_m_pg) - 2);
1342 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1343 return 0;
1344 }
1345 break;
1346 case 0x1c: /* Informational Exceptions Mode page */
1347 if (iec_m_pg[1] == arr[off + 1]) {
1348 memcpy(iec_m_pg + 2, arr + off + 2,
1349 sizeof(iec_m_pg) - 2);
1350 return 0;
1351 }
1352 break;
1353 default:
1354 break;
1355 }
1356 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1357 INVALID_FIELD_IN_PARAM_LIST, 0);
1358 return check_condition_result;
1359}
1360
1361static int resp_temp_l_pg(unsigned char * arr)
1362{
1363 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1364 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1365 };
1366
1367 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1368 return sizeof(temp_l_pg);
1369}
1370
1371static int resp_ie_l_pg(unsigned char * arr)
1372{
1373 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1374 };
1375
1376 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1377 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1378 arr[4] = THRESHOLD_EXCEEDED;
1379 arr[5] = 0xff;
1380 }
1381 return sizeof(ie_l_pg);
1382}
1383
1384#define SDEBUG_MAX_LSENSE_SZ 512
1385
1386static int resp_log_sense(struct scsi_cmnd * scp,
1387 struct sdebug_dev_info * devip)
1388{
Douglas Gilbert23183912006-09-16 20:30:47 -04001389 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001390 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1391 unsigned char *cmd = (unsigned char *)scp->cmnd;
1392
1393 if ((errsts = check_readiness(scp, 1, devip)))
1394 return errsts;
1395 memset(arr, 0, sizeof(arr));
1396 ppc = cmd[1] & 0x2;
1397 sp = cmd[1] & 0x1;
1398 if (ppc || sp) {
1399 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1400 INVALID_FIELD_IN_CDB, 0);
1401 return check_condition_result;
1402 }
1403 pcontrol = (cmd[2] & 0xc0) >> 6;
1404 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001405 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001406 alloc_len = (cmd[7] << 8) + cmd[8];
1407 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001408 if (0 == subpcode) {
1409 switch (pcode) {
1410 case 0x0: /* Supported log pages log page */
1411 n = 4;
1412 arr[n++] = 0x0; /* this page */
1413 arr[n++] = 0xd; /* Temperature */
1414 arr[n++] = 0x2f; /* Informational exceptions */
1415 arr[3] = n - 4;
1416 break;
1417 case 0xd: /* Temperature log page */
1418 arr[3] = resp_temp_l_pg(arr + 4);
1419 break;
1420 case 0x2f: /* Informational exceptions log page */
1421 arr[3] = resp_ie_l_pg(arr + 4);
1422 break;
1423 default:
1424 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1425 INVALID_FIELD_IN_CDB, 0);
1426 return check_condition_result;
1427 }
1428 } else if (0xff == subpcode) {
1429 arr[0] |= 0x40;
1430 arr[1] = subpcode;
1431 switch (pcode) {
1432 case 0x0: /* Supported log pages and subpages log page */
1433 n = 4;
1434 arr[n++] = 0x0;
1435 arr[n++] = 0x0; /* 0,0 page */
1436 arr[n++] = 0x0;
1437 arr[n++] = 0xff; /* this page */
1438 arr[n++] = 0xd;
1439 arr[n++] = 0x0; /* Temperature */
1440 arr[n++] = 0x2f;
1441 arr[n++] = 0x0; /* Informational exceptions */
1442 arr[3] = n - 4;
1443 break;
1444 case 0xd: /* Temperature subpages */
1445 n = 4;
1446 arr[n++] = 0xd;
1447 arr[n++] = 0x0; /* Temperature */
1448 arr[3] = n - 4;
1449 break;
1450 case 0x2f: /* Informational exceptions subpages */
1451 n = 4;
1452 arr[n++] = 0x2f;
1453 arr[n++] = 0x0; /* Informational exceptions */
1454 arr[3] = n - 4;
1455 break;
1456 default:
1457 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1458 INVALID_FIELD_IN_CDB, 0);
1459 return check_condition_result;
1460 }
1461 } else {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001462 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1463 INVALID_FIELD_IN_CDB, 0);
1464 return check_condition_result;
1465 }
1466 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1467 return fill_from_dev_buffer(scp, arr,
1468 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1469}
1470
FUJITA Tomonori19789102008-03-30 00:59:56 +09001471static int check_device_access_params(struct sdebug_dev_info *devi,
1472 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001474 if (lba + num > sdebug_capacity) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001475 mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 return check_condition_result;
1477 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001478 /* transfer length excessive (tie in to block limits VPD page) */
1479 if (num > sdebug_store_sectors) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001480 mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001481 return check_condition_result;
1482 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09001483 return 0;
1484}
1485
1486static int do_device_access(struct scsi_cmnd *scmd,
1487 struct sdebug_dev_info *devi,
1488 unsigned long long lba, unsigned int num, int write)
1489{
1490 int ret;
1491 unsigned int block, rest = 0;
1492 int (*func)(struct scsi_cmnd *, unsigned char *, int);
1493
1494 func = write ? fetch_to_dev_buffer : fill_from_dev_buffer;
1495
1496 block = do_div(lba, sdebug_store_sectors);
1497 if (block + num > sdebug_store_sectors)
1498 rest = block + num - sdebug_store_sectors;
1499
1500 ret = func(scmd, fake_storep + (block * SECT_SIZE),
1501 (num - rest) * SECT_SIZE);
1502 if (!ret && rest)
1503 ret = func(scmd, fake_storep, rest * SECT_SIZE);
1504
1505 return ret;
1506}
1507
1508static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
1509 unsigned int num, struct sdebug_dev_info *devip)
1510{
1511 unsigned long iflags;
1512 int ret;
1513
1514 ret = check_device_access_params(devip, lba, num);
1515 if (ret)
1516 return ret;
1517
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001519 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1520 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1521 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1523 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001524 /* set info field and valid bit for fixed descriptor */
1525 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1526 devip->sense_buff[0] |= 0x80; /* Valid bit */
1527 ret = OPT_MEDIUM_ERR_ADDR;
1528 devip->sense_buff[3] = (ret >> 24) & 0xff;
1529 devip->sense_buff[4] = (ret >> 16) & 0xff;
1530 devip->sense_buff[5] = (ret >> 8) & 0xff;
1531 devip->sense_buff[6] = ret & 0xff;
1532 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 return check_condition_result;
1534 }
1535 read_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001536 ret = do_device_access(SCpnt, devip, lba, num, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 read_unlock_irqrestore(&atomic_rw, iflags);
1538 return ret;
1539}
1540
FUJITA Tomonori19789102008-03-30 00:59:56 +09001541static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
1542 unsigned int num, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543{
1544 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09001545 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546
FUJITA Tomonori19789102008-03-30 00:59:56 +09001547 ret = check_device_access_params(devip, lba, num);
1548 if (ret)
1549 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550
1551 write_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001552 ret = do_device_access(SCpnt, devip, lba, num, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 write_unlock_irqrestore(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001554 if (-1 == ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 return (DID_ERROR << 16);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001556 else if ((ret < (num * SECT_SIZE)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001558 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
FUJITA Tomonori19789102008-03-30 00:59:56 +09001559 " IO sent=%d bytes\n", num * SECT_SIZE, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 return 0;
1561}
1562
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001563#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564
1565static int resp_report_luns(struct scsi_cmnd * scp,
1566 struct sdebug_dev_info * devip)
1567{
1568 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001569 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 unsigned char *cmd = (unsigned char *)scp->cmnd;
1571 int select_report = (int)cmd[2];
1572 struct scsi_lun *one_lun;
1573 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001574 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575
1576 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001577 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1579 0);
1580 return check_condition_result;
1581 }
1582 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
1583 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
1584 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001585 if (1 == select_report)
1586 lun_cnt = 0;
1587 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
1588 --lun_cnt;
1589 wlun = (select_report > 0) ? 1 : 0;
1590 num = lun_cnt + wlun;
1591 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
1592 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
1593 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
1594 sizeof(struct scsi_lun)), num);
1595 if (n < num) {
1596 wlun = 0;
1597 lun_cnt = n;
1598 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001600 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
1601 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
1602 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
1603 i++, lun++) {
1604 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 if (upper)
1606 one_lun[i].scsi_lun[0] =
1607 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001608 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001610 if (wlun) {
1611 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
1612 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
1613 i++;
1614 }
1615 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 return fill_from_dev_buffer(scp, arr,
1617 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
1618}
1619
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001620static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
1621 unsigned int num, struct sdebug_dev_info *devip)
1622{
1623 int i, j, ret = -1;
1624 unsigned char *kaddr, *buf;
1625 unsigned int offset;
1626 struct scatterlist *sg;
1627 struct scsi_data_buffer *sdb = scsi_in(scp);
1628
1629 /* better not to use temporary buffer. */
1630 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
1631 if (!buf)
1632 return ret;
1633
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001634 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001635
1636 offset = 0;
1637 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
1638 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
1639 if (!kaddr)
1640 goto out;
1641
1642 for (j = 0; j < sg->length; j++)
1643 *(kaddr + sg->offset + j) ^= *(buf + offset + j);
1644
1645 offset += sg->length;
1646 kunmap_atomic(kaddr, KM_USER0);
1647 }
1648 ret = 0;
1649out:
1650 kfree(buf);
1651
1652 return ret;
1653}
1654
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655/* When timer goes off this function is called. */
1656static void timer_intr_handler(unsigned long indx)
1657{
1658 struct sdebug_queued_cmd * sqcp;
1659 unsigned long iflags;
1660
1661 if (indx >= SCSI_DEBUG_CANQUEUE) {
1662 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
1663 "large\n");
1664 return;
1665 }
1666 spin_lock_irqsave(&queued_arr_lock, iflags);
1667 sqcp = &queued_arr[(int)indx];
1668 if (! sqcp->in_use) {
1669 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
1670 "interrupt\n");
1671 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1672 return;
1673 }
1674 sqcp->in_use = 0;
1675 if (sqcp->done_funct) {
1676 sqcp->a_cmnd->result = sqcp->scsi_result;
1677 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
1678 }
1679 sqcp->done_funct = NULL;
1680 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1681}
1682
1683static int scsi_debug_slave_alloc(struct scsi_device * sdp)
1684{
1685 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001686 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
1687 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001688 set_bit(QUEUE_FLAG_BIDI, &sdp->request_queue->queue_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 return 0;
1690}
1691
1692static int scsi_debug_slave_configure(struct scsi_device * sdp)
1693{
1694 struct sdebug_dev_info * devip;
1695
1696 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001697 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
1698 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
1700 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
1701 devip = devInfoReg(sdp);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001702 if (NULL == devip)
1703 return 1; /* no resources, will be marked offline */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 sdp->hostdata = devip;
1705 if (sdp->host->cmd_per_lun)
1706 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
1707 sdp->host->cmd_per_lun);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001708 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 return 0;
1710}
1711
1712static void scsi_debug_slave_destroy(struct scsi_device * sdp)
1713{
1714 struct sdebug_dev_info * devip =
1715 (struct sdebug_dev_info *)sdp->hostdata;
1716
1717 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001718 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
1719 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 if (devip) {
1721 /* make this slot avaliable for re-use */
1722 devip->used = 0;
1723 sdp->hostdata = NULL;
1724 }
1725}
1726
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09001727struct sdebug_dev_info *sdebug_device_create(struct sdebug_host_info *sdbg_host,
1728 gfp_t flags)
1729{
1730 struct sdebug_dev_info *devip;
1731
1732 devip = kzalloc(sizeof(*devip), flags);
1733 if (devip) {
1734 devip->sdbg_host = sdbg_host;
1735 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
1736 }
1737 return devip;
1738}
1739
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
1741{
1742 struct sdebug_host_info * sdbg_host;
1743 struct sdebug_dev_info * open_devip = NULL;
1744 struct sdebug_dev_info * devip =
1745 (struct sdebug_dev_info *)sdev->hostdata;
1746
1747 if (devip)
1748 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09001749 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
1750 if (!sdbg_host) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 printk(KERN_ERR "Host info NULL\n");
1752 return NULL;
1753 }
1754 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
1755 if ((devip->used) && (devip->channel == sdev->channel) &&
1756 (devip->target == sdev->id) &&
1757 (devip->lun == sdev->lun))
1758 return devip;
1759 else {
1760 if ((!devip->used) && (!open_devip))
1761 open_devip = devip;
1762 }
1763 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09001764 if (!open_devip) { /* try and make a new one */
1765 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
1766 if (!open_devip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 printk(KERN_ERR "%s: out of memory at line %d\n",
1768 __FUNCTION__, __LINE__);
1769 return NULL;
1770 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09001772
1773 open_devip->channel = sdev->channel;
1774 open_devip->target = sdev->id;
1775 open_devip->lun = sdev->lun;
1776 open_devip->sdbg_host = sdbg_host;
1777 open_devip->reset = 1;
1778 open_devip->used = 1;
1779 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
1780 if (scsi_debug_dsense)
1781 open_devip->sense_buff[0] = 0x72;
1782 else {
1783 open_devip->sense_buff[0] = 0x70;
1784 open_devip->sense_buff[7] = 0xa;
1785 }
1786 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
1787 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
1788
1789 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790}
1791
1792static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
1793 int asc, int asq)
1794{
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09001795 unsigned char *sbuff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796
1797 sbuff = devip->sense_buff;
1798 memset(sbuff, 0, SDEBUG_SENSE_LEN);
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09001799
1800 scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
1801
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1803 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
1804 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
1805}
1806
1807static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
1808{
1809 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1810 printk(KERN_INFO "scsi_debug: abort\n");
1811 ++num_aborts;
1812 stop_queued_cmnd(SCpnt);
1813 return SUCCESS;
1814}
1815
1816static int scsi_debug_biosparam(struct scsi_device *sdev,
1817 struct block_device * bdev, sector_t capacity, int *info)
1818{
1819 int res;
1820 unsigned char *buf;
1821
1822 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1823 printk(KERN_INFO "scsi_debug: biosparam\n");
1824 buf = scsi_bios_ptable(bdev);
1825 if (buf) {
1826 res = scsi_partsize(buf, capacity,
1827 &info[2], &info[0], &info[1]);
1828 kfree(buf);
1829 if (! res)
1830 return res;
1831 }
1832 info[0] = sdebug_heads;
1833 info[1] = sdebug_sectors_per;
1834 info[2] = sdebug_cylinders_per;
1835 return 0;
1836}
1837
1838static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
1839{
1840 struct sdebug_dev_info * devip;
1841
1842 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1843 printk(KERN_INFO "scsi_debug: device_reset\n");
1844 ++num_dev_resets;
1845 if (SCpnt) {
1846 devip = devInfoReg(SCpnt->device);
1847 if (devip)
1848 devip->reset = 1;
1849 }
1850 return SUCCESS;
1851}
1852
1853static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
1854{
1855 struct sdebug_host_info *sdbg_host;
1856 struct sdebug_dev_info * dev_info;
1857 struct scsi_device * sdp;
1858 struct Scsi_Host * hp;
1859
1860 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1861 printk(KERN_INFO "scsi_debug: bus_reset\n");
1862 ++num_bus_resets;
1863 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09001864 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 if (sdbg_host) {
1866 list_for_each_entry(dev_info,
1867 &sdbg_host->dev_info_list,
1868 dev_list)
1869 dev_info->reset = 1;
1870 }
1871 }
1872 return SUCCESS;
1873}
1874
1875static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
1876{
1877 struct sdebug_host_info * sdbg_host;
1878 struct sdebug_dev_info * dev_info;
1879
1880 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1881 printk(KERN_INFO "scsi_debug: host_reset\n");
1882 ++num_host_resets;
1883 spin_lock(&sdebug_host_list_lock);
1884 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
1885 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
1886 dev_list)
1887 dev_info->reset = 1;
1888 }
1889 spin_unlock(&sdebug_host_list_lock);
1890 stop_all_queued();
1891 return SUCCESS;
1892}
1893
1894/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
1895static int stop_queued_cmnd(struct scsi_cmnd * cmnd)
1896{
1897 unsigned long iflags;
1898 int k;
1899 struct sdebug_queued_cmd * sqcp;
1900
1901 spin_lock_irqsave(&queued_arr_lock, iflags);
1902 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1903 sqcp = &queued_arr[k];
1904 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
1905 del_timer_sync(&sqcp->cmnd_timer);
1906 sqcp->in_use = 0;
1907 sqcp->a_cmnd = NULL;
1908 break;
1909 }
1910 }
1911 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1912 return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
1913}
1914
1915/* Deletes (stops) timers of all queued commands */
1916static void stop_all_queued(void)
1917{
1918 unsigned long iflags;
1919 int k;
1920 struct sdebug_queued_cmd * sqcp;
1921
1922 spin_lock_irqsave(&queued_arr_lock, iflags);
1923 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1924 sqcp = &queued_arr[k];
1925 if (sqcp->in_use && sqcp->a_cmnd) {
1926 del_timer_sync(&sqcp->cmnd_timer);
1927 sqcp->in_use = 0;
1928 sqcp->a_cmnd = NULL;
1929 }
1930 }
1931 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1932}
1933
1934/* Initializes timers in queued array */
1935static void __init init_all_queued(void)
1936{
1937 unsigned long iflags;
1938 int k;
1939 struct sdebug_queued_cmd * sqcp;
1940
1941 spin_lock_irqsave(&queued_arr_lock, iflags);
1942 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1943 sqcp = &queued_arr[k];
1944 init_timer(&sqcp->cmnd_timer);
1945 sqcp->in_use = 0;
1946 sqcp->a_cmnd = NULL;
1947 }
1948 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1949}
1950
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09001951static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09001952 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953{
1954 struct partition * pp;
1955 int starts[SDEBUG_MAX_PARTS + 2];
1956 int sectors_per_part, num_sectors, k;
1957 int heads_by_sects, start_sec, end_sec;
1958
1959 /* assume partition table already zeroed */
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09001960 if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 return;
1962 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
1963 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
1964 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
1965 "partitions to %d\n", SDEBUG_MAX_PARTS);
1966 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001967 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 sectors_per_part = (num_sectors - sdebug_sectors_per)
1969 / scsi_debug_num_parts;
1970 heads_by_sects = sdebug_heads * sdebug_sectors_per;
1971 starts[0] = sdebug_sectors_per;
1972 for (k = 1; k < scsi_debug_num_parts; ++k)
1973 starts[k] = ((k * sectors_per_part) / heads_by_sects)
1974 * heads_by_sects;
1975 starts[scsi_debug_num_parts] = num_sectors;
1976 starts[scsi_debug_num_parts + 1] = 0;
1977
1978 ramp[510] = 0x55; /* magic partition markings */
1979 ramp[511] = 0xAA;
1980 pp = (struct partition *)(ramp + 0x1be);
1981 for (k = 0; starts[k + 1]; ++k, ++pp) {
1982 start_sec = starts[k];
1983 end_sec = starts[k + 1] - 1;
1984 pp->boot_ind = 0;
1985
1986 pp->cyl = start_sec / heads_by_sects;
1987 pp->head = (start_sec - (pp->cyl * heads_by_sects))
1988 / sdebug_sectors_per;
1989 pp->sector = (start_sec % sdebug_sectors_per) + 1;
1990
1991 pp->end_cyl = end_sec / heads_by_sects;
1992 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
1993 / sdebug_sectors_per;
1994 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
1995
1996 pp->start_sect = start_sec;
1997 pp->nr_sects = end_sec - start_sec + 1;
1998 pp->sys_ind = 0x83; /* plain Linux partition */
1999 }
2000}
2001
2002static int schedule_resp(struct scsi_cmnd * cmnd,
2003 struct sdebug_dev_info * devip,
2004 done_funct_t done, int scsi_result, int delta_jiff)
2005{
2006 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2007 if (scsi_result) {
2008 struct scsi_device * sdp = cmnd->device;
2009
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002010 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2011 "non-zero result=0x%x\n", sdp->host->host_no,
2012 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 }
2014 }
2015 if (cmnd && devip) {
2016 /* simulate autosense by this driver */
2017 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2018 memcpy(cmnd->sense_buffer, devip->sense_buff,
2019 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2020 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2021 }
2022 if (delta_jiff <= 0) {
2023 if (cmnd)
2024 cmnd->result = scsi_result;
2025 if (done)
2026 done(cmnd);
2027 return 0;
2028 } else {
2029 unsigned long iflags;
2030 int k;
2031 struct sdebug_queued_cmd * sqcp = NULL;
2032
2033 spin_lock_irqsave(&queued_arr_lock, iflags);
2034 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2035 sqcp = &queued_arr[k];
2036 if (! sqcp->in_use)
2037 break;
2038 }
2039 if (k >= SCSI_DEBUG_CANQUEUE) {
2040 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2041 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2042 return 1; /* report busy to mid level */
2043 }
2044 sqcp->in_use = 1;
2045 sqcp->a_cmnd = cmnd;
2046 sqcp->scsi_result = scsi_result;
2047 sqcp->done_funct = done;
2048 sqcp->cmnd_timer.function = timer_intr_handler;
2049 sqcp->cmnd_timer.data = k;
2050 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2051 add_timer(&sqcp->cmnd_timer);
2052 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2053 if (cmnd)
2054 cmnd->result = 0;
2055 return 0;
2056 }
2057}
2058
Douglas Gilbert23183912006-09-16 20:30:47 -04002059/* Note: The following macros create attribute files in the
2060 /sys/module/scsi_debug/parameters directory. Unfortunately this
2061 driver is unaware of a change and cannot trigger auxiliary actions
2062 as it can when the corresponding attribute in the
2063 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2064 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002065module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2066module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2067module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2068module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2069module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002070module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002071module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2072module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2073module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2074module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2075module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2076module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2077module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2078module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002079module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2080 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081
2082MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2083MODULE_DESCRIPTION("SCSI debug adapter driver");
2084MODULE_LICENSE("GPL");
2085MODULE_VERSION(SCSI_DEBUG_VERSION);
2086
2087MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2088MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002089MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2090MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07002091MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002092MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002093MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2094MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002096MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002097MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2099MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002100MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002101MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102
2103
2104static char sdebug_info[256];
2105
2106static const char * scsi_debug_info(struct Scsi_Host * shp)
2107{
2108 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2109 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2110 scsi_debug_version_date, scsi_debug_dev_size_mb,
2111 scsi_debug_opts);
2112 return sdebug_info;
2113}
2114
2115/* scsi_debug_proc_info
2116 * Used if the driver currently has no own support for /proc/scsi
2117 */
2118static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2119 int length, int inout)
2120{
2121 int len, pos, begin;
2122 int orig_length;
2123
2124 orig_length = length;
2125
2126 if (inout == 1) {
2127 char arr[16];
2128 int minLen = length > 15 ? 15 : length;
2129
2130 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2131 return -EACCES;
2132 memcpy(arr, buffer, minLen);
2133 arr[minLen] = '\0';
2134 if (1 != sscanf(arr, "%d", &pos))
2135 return -EINVAL;
2136 scsi_debug_opts = pos;
2137 if (scsi_debug_every_nth != 0)
2138 scsi_debug_cmnd_count = 0;
2139 return length;
2140 }
2141 begin = 0;
2142 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2143 "%s [%s]\n"
2144 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2145 "every_nth=%d(curr:%d)\n"
2146 "delay=%d, max_luns=%d, scsi_level=%d\n"
2147 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2148 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
2149 "host_resets=%d\n",
2150 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2151 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2152 scsi_debug_cmnd_count, scsi_debug_delay,
2153 scsi_debug_max_luns, scsi_debug_scsi_level,
2154 SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
2155 num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
2156 if (pos < offset) {
2157 len = 0;
2158 begin = pos;
2159 }
2160 *start = buffer + (offset - begin); /* Start of wanted data */
2161 len -= (offset - begin);
2162 if (len > length)
2163 len = length;
2164 return len;
2165}
2166
2167static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2168{
2169 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2170}
2171
2172static ssize_t sdebug_delay_store(struct device_driver * ddp,
2173 const char * buf, size_t count)
2174{
2175 int delay;
2176 char work[20];
2177
2178 if (1 == sscanf(buf, "%10s", work)) {
2179 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2180 scsi_debug_delay = delay;
2181 return count;
2182 }
2183 }
2184 return -EINVAL;
2185}
2186DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2187 sdebug_delay_store);
2188
2189static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2190{
2191 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2192}
2193
2194static ssize_t sdebug_opts_store(struct device_driver * ddp,
2195 const char * buf, size_t count)
2196{
2197 int opts;
2198 char work[20];
2199
2200 if (1 == sscanf(buf, "%10s", work)) {
2201 if (0 == strnicmp(work,"0x", 2)) {
2202 if (1 == sscanf(&work[2], "%x", &opts))
2203 goto opts_done;
2204 } else {
2205 if (1 == sscanf(work, "%d", &opts))
2206 goto opts_done;
2207 }
2208 }
2209 return -EINVAL;
2210opts_done:
2211 scsi_debug_opts = opts;
2212 scsi_debug_cmnd_count = 0;
2213 return count;
2214}
2215DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2216 sdebug_opts_store);
2217
2218static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2219{
2220 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2221}
2222static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2223 const char * buf, size_t count)
2224{
2225 int n;
2226
2227 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2228 scsi_debug_ptype = n;
2229 return count;
2230 }
2231 return -EINVAL;
2232}
2233DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2234
2235static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2236{
2237 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2238}
2239static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2240 const char * buf, size_t count)
2241{
2242 int n;
2243
2244 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2245 scsi_debug_dsense = n;
2246 return count;
2247 }
2248 return -EINVAL;
2249}
2250DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2251 sdebug_dsense_store);
2252
Douglas Gilbert23183912006-09-16 20:30:47 -04002253static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2254{
2255 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2256}
2257static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2258 const char * buf, size_t count)
2259{
2260 int n;
2261
2262 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2263 scsi_debug_fake_rw = n;
2264 return count;
2265 }
2266 return -EINVAL;
2267}
2268DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2269 sdebug_fake_rw_store);
2270
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002271static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2272{
2273 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2274}
2275static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2276 const char * buf, size_t count)
2277{
2278 int n;
2279
2280 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2281 scsi_debug_no_lun_0 = n;
2282 return count;
2283 }
2284 return -EINVAL;
2285}
2286DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2287 sdebug_no_lun_0_store);
2288
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2290{
2291 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2292}
2293static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2294 const char * buf, size_t count)
2295{
2296 int n;
2297
2298 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2299 scsi_debug_num_tgts = n;
2300 sdebug_max_tgts_luns();
2301 return count;
2302 }
2303 return -EINVAL;
2304}
2305DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2306 sdebug_num_tgts_store);
2307
2308static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2309{
2310 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2311}
2312DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2313
2314static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2315{
2316 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2317}
2318DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2319
2320static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2321{
2322 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2323}
2324static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2325 const char * buf, size_t count)
2326{
2327 int nth;
2328
2329 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2330 scsi_debug_every_nth = nth;
2331 scsi_debug_cmnd_count = 0;
2332 return count;
2333 }
2334 return -EINVAL;
2335}
2336DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2337 sdebug_every_nth_store);
2338
2339static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2340{
2341 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2342}
2343static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2344 const char * buf, size_t count)
2345{
2346 int n;
2347
2348 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2349 scsi_debug_max_luns = n;
2350 sdebug_max_tgts_luns();
2351 return count;
2352 }
2353 return -EINVAL;
2354}
2355DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2356 sdebug_max_luns_store);
2357
2358static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
2359{
2360 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
2361}
2362DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
2363
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002364static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2365{
2366 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2367}
2368static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2369 const char * buf, size_t count)
2370{
2371 int n;
2372
2373 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2374 scsi_debug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002375
2376 sdebug_capacity = get_sdebug_capacity();
2377
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002378 return count;
2379 }
2380 return -EINVAL;
2381}
2382DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2383 sdebug_virtual_gb_store);
2384
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
2386{
2387 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
2388}
2389
2390static ssize_t sdebug_add_host_store(struct device_driver * ddp,
2391 const char * buf, size_t count)
2392{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002393 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002395 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 if (delta_hosts > 0) {
2398 do {
2399 sdebug_add_adapter();
2400 } while (--delta_hosts);
2401 } else if (delta_hosts < 0) {
2402 do {
2403 sdebug_remove_adapter();
2404 } while (++delta_hosts);
2405 }
2406 return count;
2407}
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002408DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 sdebug_add_host_store);
2410
Douglas Gilbert23183912006-09-16 20:30:47 -04002411static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
2412 char * buf)
2413{
2414 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
2415}
2416static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
2417 const char * buf, size_t count)
2418{
2419 int n;
2420
2421 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2422 scsi_debug_vpd_use_hostno = n;
2423 return count;
2424 }
2425 return -EINVAL;
2426}
2427DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
2428 sdebug_vpd_use_hostno_store);
2429
2430/* Note: The following function creates attribute files in the
2431 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
2432 files (over those found in the /sys/module/scsi_debug/parameters
2433 directory) is that auxiliary actions can be triggered when an attribute
2434 is changed. For example see: sdebug_add_host_store() above.
2435 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002436static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002438 int ret;
2439
2440 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2441 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
2442 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2443 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2444 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04002445 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002446 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002447 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002448 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002449 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002450 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
2451 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
2452 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04002453 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
2454 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002455 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456}
2457
2458static void do_remove_driverfs_files(void)
2459{
Douglas Gilbert23183912006-09-16 20:30:47 -04002460 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
2461 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
2463 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
2464 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002466 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
2467 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002469 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
2471 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2472 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2473 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
2474 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2475}
2476
2477static int __init scsi_debug_init(void)
2478{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09002479 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 int host_to_add;
2481 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002482 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483
2484 if (scsi_debug_dev_size_mb < 1)
2485 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09002486 sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002487 sdebug_store_sectors = sz / SECT_SIZE;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002488 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489
2490 /* play around with geometry, don't waste too much on track 0 */
2491 sdebug_heads = 8;
2492 sdebug_sectors_per = 32;
2493 if (scsi_debug_dev_size_mb >= 16)
2494 sdebug_heads = 32;
2495 else if (scsi_debug_dev_size_mb >= 256)
2496 sdebug_heads = 64;
2497 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2498 (sdebug_sectors_per * sdebug_heads);
2499 if (sdebug_cylinders_per >= 1024) {
2500 /* other LLDs do this; implies >= 1GB ram disk ... */
2501 sdebug_heads = 255;
2502 sdebug_sectors_per = 63;
2503 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2504 (sdebug_sectors_per * sdebug_heads);
2505 }
2506
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 fake_storep = vmalloc(sz);
2508 if (NULL == fake_storep) {
2509 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
2510 return -ENOMEM;
2511 }
2512 memset(fake_storep, 0, sz);
2513 if (scsi_debug_num_parts > 0)
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002514 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002516 ret = device_register(&pseudo_primary);
2517 if (ret < 0) {
2518 printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
2519 ret);
2520 goto free_vm;
2521 }
2522 ret = bus_register(&pseudo_lld_bus);
2523 if (ret < 0) {
2524 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
2525 ret);
2526 goto dev_unreg;
2527 }
2528 ret = driver_register(&sdebug_driverfs_driver);
2529 if (ret < 0) {
2530 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
2531 ret);
2532 goto bus_unreg;
2533 }
2534 ret = do_create_driverfs_files();
2535 if (ret < 0) {
2536 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
2537 ret);
2538 goto del_files;
2539 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002541 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543 host_to_add = scsi_debug_add_host;
2544 scsi_debug_add_host = 0;
2545
2546 for (k = 0; k < host_to_add; k++) {
2547 if (sdebug_add_adapter()) {
2548 printk(KERN_ERR "scsi_debug_init: "
2549 "sdebug_add_adapter failed k=%d\n", k);
2550 break;
2551 }
2552 }
2553
2554 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
2555 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
2556 scsi_debug_add_host);
2557 }
2558 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002559
2560del_files:
2561 do_remove_driverfs_files();
2562 driver_unregister(&sdebug_driverfs_driver);
2563bus_unreg:
2564 bus_unregister(&pseudo_lld_bus);
2565dev_unreg:
2566 device_unregister(&pseudo_primary);
2567free_vm:
2568 vfree(fake_storep);
2569
2570 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571}
2572
2573static void __exit scsi_debug_exit(void)
2574{
2575 int k = scsi_debug_add_host;
2576
2577 stop_all_queued();
2578 for (; k; k--)
2579 sdebug_remove_adapter();
2580 do_remove_driverfs_files();
2581 driver_unregister(&sdebug_driverfs_driver);
2582 bus_unregister(&pseudo_lld_bus);
2583 device_unregister(&pseudo_primary);
2584
2585 vfree(fake_storep);
2586}
2587
2588device_initcall(scsi_debug_init);
2589module_exit(scsi_debug_exit);
2590
Adrian Bunk52c1da32005-06-23 22:05:33 -07002591static void pseudo_0_release(struct device * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592{
2593 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2594 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
2595}
2596
2597static struct device pseudo_primary = {
2598 .bus_id = "pseudo_0",
2599 .release = pseudo_0_release,
2600};
2601
2602static int pseudo_lld_bus_match(struct device *dev,
2603 struct device_driver *dev_driver)
2604{
2605 return 1;
2606}
2607
2608static struct bus_type pseudo_lld_bus = {
2609 .name = "pseudo",
2610 .match = pseudo_lld_bus_match,
Russell Kingbbbe3a42006-01-05 14:44:46 +00002611 .probe = sdebug_driver_probe,
2612 .remove = sdebug_driver_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613};
2614
2615static void sdebug_release_adapter(struct device * dev)
2616{
2617 struct sdebug_host_info *sdbg_host;
2618
2619 sdbg_host = to_sdebug_host(dev);
2620 kfree(sdbg_host);
2621}
2622
2623static int sdebug_add_adapter(void)
2624{
2625 int k, devs_per_host;
2626 int error = 0;
2627 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09002628 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002630 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 if (NULL == sdbg_host) {
2632 printk(KERN_ERR "%s: out of memory at line %d\n",
2633 __FUNCTION__, __LINE__);
2634 return -ENOMEM;
2635 }
2636
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
2638
2639 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
2640 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002641 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
2642 if (!sdbg_devinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 printk(KERN_ERR "%s: out of memory at line %d\n",
2644 __FUNCTION__, __LINE__);
2645 error = -ENOMEM;
2646 goto clean;
2647 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 }
2649
2650 spin_lock(&sdebug_host_list_lock);
2651 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
2652 spin_unlock(&sdebug_host_list_lock);
2653
2654 sdbg_host->dev.bus = &pseudo_lld_bus;
2655 sdbg_host->dev.parent = &pseudo_primary;
2656 sdbg_host->dev.release = &sdebug_release_adapter;
2657 sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host);
2658
2659 error = device_register(&sdbg_host->dev);
2660
2661 if (error)
2662 goto clean;
2663
2664 ++scsi_debug_add_host;
2665 return error;
2666
2667clean:
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09002668 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
2669 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 list_del(&sdbg_devinfo->dev_list);
2671 kfree(sdbg_devinfo);
2672 }
2673
2674 kfree(sdbg_host);
2675 return error;
2676}
2677
2678static void sdebug_remove_adapter(void)
2679{
2680 struct sdebug_host_info * sdbg_host = NULL;
2681
2682 spin_lock(&sdebug_host_list_lock);
2683 if (!list_empty(&sdebug_host_list)) {
2684 sdbg_host = list_entry(sdebug_host_list.prev,
2685 struct sdebug_host_info, host_list);
2686 list_del(&sdbg_host->host_list);
2687 }
2688 spin_unlock(&sdebug_host_list_lock);
2689
2690 if (!sdbg_host)
2691 return;
2692
2693 device_unregister(&sdbg_host->dev);
2694 --scsi_debug_add_host;
2695}
2696
FUJITA Tomonori639db472008-03-20 11:09:19 +09002697static
2698int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
2699{
2700 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
2701 int len, k;
2702 unsigned int num;
2703 unsigned long long lba;
2704 int errsts = 0;
2705 int target = SCpnt->device->id;
2706 struct sdebug_dev_info *devip = NULL;
2707 int inj_recovered = 0;
2708 int inj_transport = 0;
2709 int delay_override = 0;
2710
2711 scsi_set_resid(SCpnt, 0);
2712 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
2713 printk(KERN_INFO "scsi_debug: cmd ");
2714 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
2715 printk("%02x ", (int)cmd[k]);
2716 printk("\n");
2717 }
2718
2719 if (target == SCpnt->device->host->hostt->this_id) {
2720 printk(KERN_INFO "scsi_debug: initiator's id used as "
2721 "target!\n");
2722 return schedule_resp(SCpnt, NULL, done,
2723 DID_NO_CONNECT << 16, 0);
2724 }
2725
2726 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
2727 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
2728 return schedule_resp(SCpnt, NULL, done,
2729 DID_NO_CONNECT << 16, 0);
2730 devip = devInfoReg(SCpnt->device);
2731 if (NULL == devip)
2732 return schedule_resp(SCpnt, NULL, done,
2733 DID_NO_CONNECT << 16, 0);
2734
2735 if ((scsi_debug_every_nth != 0) &&
2736 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
2737 scsi_debug_cmnd_count = 0;
2738 if (scsi_debug_every_nth < -1)
2739 scsi_debug_every_nth = -1;
2740 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
2741 return 0; /* ignore command causing timeout */
2742 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
2743 inj_recovered = 1; /* to reads and writes below */
2744 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
2745 inj_transport = 1; /* to reads and writes below */
2746 }
2747
2748 if (devip->wlun) {
2749 switch (*cmd) {
2750 case INQUIRY:
2751 case REQUEST_SENSE:
2752 case TEST_UNIT_READY:
2753 case REPORT_LUNS:
2754 break; /* only allowable wlun commands */
2755 default:
2756 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2757 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
2758 "not supported for wlun\n", *cmd);
2759 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2760 INVALID_OPCODE, 0);
2761 errsts = check_condition_result;
2762 return schedule_resp(SCpnt, devip, done, errsts,
2763 0);
2764 }
2765 }
2766
2767 switch (*cmd) {
2768 case INQUIRY: /* mandatory, ignore unit attention */
2769 delay_override = 1;
2770 errsts = resp_inquiry(SCpnt, target, devip);
2771 break;
2772 case REQUEST_SENSE: /* mandatory, ignore unit attention */
2773 delay_override = 1;
2774 errsts = resp_requests(SCpnt, devip);
2775 break;
2776 case REZERO_UNIT: /* actually this is REWIND for SSC */
2777 case START_STOP:
2778 errsts = resp_start_stop(SCpnt, devip);
2779 break;
2780 case ALLOW_MEDIUM_REMOVAL:
2781 errsts = check_readiness(SCpnt, 1, devip);
2782 if (errsts)
2783 break;
2784 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2785 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
2786 cmd[4] ? "inhibited" : "enabled");
2787 break;
2788 case SEND_DIAGNOSTIC: /* mandatory */
2789 errsts = check_readiness(SCpnt, 1, devip);
2790 break;
2791 case TEST_UNIT_READY: /* mandatory */
2792 delay_override = 1;
2793 errsts = check_readiness(SCpnt, 0, devip);
2794 break;
2795 case RESERVE:
2796 errsts = check_readiness(SCpnt, 1, devip);
2797 break;
2798 case RESERVE_10:
2799 errsts = check_readiness(SCpnt, 1, devip);
2800 break;
2801 case RELEASE:
2802 errsts = check_readiness(SCpnt, 1, devip);
2803 break;
2804 case RELEASE_10:
2805 errsts = check_readiness(SCpnt, 1, devip);
2806 break;
2807 case READ_CAPACITY:
2808 errsts = resp_readcap(SCpnt, devip);
2809 break;
2810 case SERVICE_ACTION_IN:
2811 if (SAI_READ_CAPACITY_16 != cmd[1]) {
2812 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2813 INVALID_OPCODE, 0);
2814 errsts = check_condition_result;
2815 break;
2816 }
2817 errsts = resp_readcap16(SCpnt, devip);
2818 break;
2819 case MAINTENANCE_IN:
2820 if (MI_REPORT_TARGET_PGS != cmd[1]) {
2821 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2822 INVALID_OPCODE, 0);
2823 errsts = check_condition_result;
2824 break;
2825 }
2826 errsts = resp_report_tgtpgs(SCpnt, devip);
2827 break;
2828 case READ_16:
2829 case READ_12:
2830 case READ_10:
2831 case READ_6:
2832 errsts = check_readiness(SCpnt, 0, devip);
2833 if (errsts)
2834 break;
2835 if (scsi_debug_fake_rw)
2836 break;
2837 get_data_transfer_info(cmd, &lba, &num);
2838 errsts = resp_read(SCpnt, lba, num, devip);
2839 if (inj_recovered && (0 == errsts)) {
2840 mk_sense_buffer(devip, RECOVERED_ERROR,
2841 THRESHOLD_EXCEEDED, 0);
2842 errsts = check_condition_result;
2843 } else if (inj_transport && (0 == errsts)) {
2844 mk_sense_buffer(devip, ABORTED_COMMAND,
2845 TRANSPORT_PROBLEM, ACK_NAK_TO);
2846 errsts = check_condition_result;
2847 }
2848 break;
2849 case REPORT_LUNS: /* mandatory, ignore unit attention */
2850 delay_override = 1;
2851 errsts = resp_report_luns(SCpnt, devip);
2852 break;
2853 case VERIFY: /* 10 byte SBC-2 command */
2854 errsts = check_readiness(SCpnt, 0, devip);
2855 break;
2856 case WRITE_16:
2857 case WRITE_12:
2858 case WRITE_10:
2859 case WRITE_6:
2860 errsts = check_readiness(SCpnt, 0, devip);
2861 if (errsts)
2862 break;
2863 if (scsi_debug_fake_rw)
2864 break;
2865 get_data_transfer_info(cmd, &lba, &num);
2866 errsts = resp_write(SCpnt, lba, num, devip);
2867 if (inj_recovered && (0 == errsts)) {
2868 mk_sense_buffer(devip, RECOVERED_ERROR,
2869 THRESHOLD_EXCEEDED, 0);
2870 errsts = check_condition_result;
2871 }
2872 break;
2873 case MODE_SENSE:
2874 case MODE_SENSE_10:
2875 errsts = resp_mode_sense(SCpnt, target, devip);
2876 break;
2877 case MODE_SELECT:
2878 errsts = resp_mode_select(SCpnt, 1, devip);
2879 break;
2880 case MODE_SELECT_10:
2881 errsts = resp_mode_select(SCpnt, 0, devip);
2882 break;
2883 case LOG_SENSE:
2884 errsts = resp_log_sense(SCpnt, devip);
2885 break;
2886 case SYNCHRONIZE_CACHE:
2887 delay_override = 1;
2888 errsts = check_readiness(SCpnt, 0, devip);
2889 break;
2890 case WRITE_BUFFER:
2891 errsts = check_readiness(SCpnt, 1, devip);
2892 break;
2893 case XDWRITEREAD_10:
2894 if (!scsi_bidi_cmnd(SCpnt)) {
2895 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2896 INVALID_FIELD_IN_CDB, 0);
2897 errsts = check_condition_result;
2898 break;
2899 }
2900
2901 errsts = check_readiness(SCpnt, 0, devip);
2902 if (errsts)
2903 break;
2904 if (scsi_debug_fake_rw)
2905 break;
2906 get_data_transfer_info(cmd, &lba, &num);
2907 errsts = resp_read(SCpnt, lba, num, devip);
2908 if (errsts)
2909 break;
2910 errsts = resp_write(SCpnt, lba, num, devip);
2911 if (errsts)
2912 break;
2913 errsts = resp_xdwriteread(SCpnt, lba, num, devip);
2914 break;
2915 default:
2916 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2917 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
2918 "supported\n", *cmd);
2919 errsts = check_readiness(SCpnt, 1, devip);
2920 if (errsts)
2921 break; /* Unit attention takes precedence */
2922 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
2923 errsts = check_condition_result;
2924 break;
2925 }
2926 return schedule_resp(SCpnt, devip, done, errsts,
2927 (delay_override ? 0 : scsi_debug_delay));
2928}
2929
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09002930static struct scsi_host_template sdebug_driver_template = {
2931 .proc_info = scsi_debug_proc_info,
2932 .proc_name = sdebug_proc_name,
2933 .name = "SCSI DEBUG",
2934 .info = scsi_debug_info,
2935 .slave_alloc = scsi_debug_slave_alloc,
2936 .slave_configure = scsi_debug_slave_configure,
2937 .slave_destroy = scsi_debug_slave_destroy,
2938 .ioctl = scsi_debug_ioctl,
2939 .queuecommand = scsi_debug_queuecommand,
2940 .eh_abort_handler = scsi_debug_abort,
2941 .eh_bus_reset_handler = scsi_debug_bus_reset,
2942 .eh_device_reset_handler = scsi_debug_device_reset,
2943 .eh_host_reset_handler = scsi_debug_host_reset,
2944 .bios_param = scsi_debug_biosparam,
2945 .can_queue = SCSI_DEBUG_CANQUEUE,
2946 .this_id = 7,
2947 .sg_tablesize = 256,
2948 .cmd_per_lun = 16,
2949 .max_sectors = 0xffff,
2950 .use_clustering = DISABLE_CLUSTERING,
2951 .module = THIS_MODULE,
2952};
2953
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954static int sdebug_driver_probe(struct device * dev)
2955{
2956 int error = 0;
2957 struct sdebug_host_info *sdbg_host;
2958 struct Scsi_Host *hpnt;
2959
2960 sdbg_host = to_sdebug_host(dev);
2961
2962 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
2963 if (NULL == hpnt) {
2964 printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__);
2965 error = -ENODEV;
2966 return error;
2967 }
2968
2969 sdbg_host->shost = hpnt;
2970 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
2971 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
2972 hpnt->max_id = scsi_debug_num_tgts + 1;
2973 else
2974 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002975 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976
2977 error = scsi_add_host(hpnt, &sdbg_host->dev);
2978 if (error) {
2979 printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
2980 error = -ENODEV;
2981 scsi_host_put(hpnt);
2982 } else
2983 scsi_scan_host(hpnt);
2984
2985
2986 return error;
2987}
2988
2989static int sdebug_driver_remove(struct device * dev)
2990{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09002992 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993
2994 sdbg_host = to_sdebug_host(dev);
2995
2996 if (!sdbg_host) {
2997 printk(KERN_ERR "%s: Unable to locate host info\n",
2998 __FUNCTION__);
2999 return -ENODEV;
3000 }
3001
3002 scsi_remove_host(sdbg_host->shost);
3003
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003004 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
3005 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 list_del(&sdbg_devinfo->dev_list);
3007 kfree(sdbg_devinfo);
3008 }
3009
3010 scsi_host_put(sdbg_host->shost);
3011 return 0;
3012}
3013
3014static void sdebug_max_tgts_luns(void)
3015{
3016 struct sdebug_host_info * sdbg_host;
3017 struct Scsi_Host *hpnt;
3018
3019 spin_lock(&sdebug_host_list_lock);
3020 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3021 hpnt = sdbg_host->shost;
3022 if ((hpnt->this_id >= 0) &&
3023 (scsi_debug_num_tgts > hpnt->this_id))
3024 hpnt->max_id = scsi_debug_num_tgts + 1;
3025 else
3026 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003027 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028 }
3029 spin_unlock(&sdebug_host_list_lock);
3030}