blob: 70bcee6516c2f4f3163c037055b6762fc5b37653 [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
1471static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
1472 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473{
1474 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001475 unsigned int block, from_bottom;
1476 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 int ret;
1478
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001479 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1481 0);
1482 return check_condition_result;
1483 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001484 /* transfer length excessive (tie in to block limits VPD page) */
1485 if (num > sdebug_store_sectors) {
1486 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1487 0);
1488 return check_condition_result;
1489 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001491 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1492 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1493 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1495 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001496 /* set info field and valid bit for fixed descriptor */
1497 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1498 devip->sense_buff[0] |= 0x80; /* Valid bit */
1499 ret = OPT_MEDIUM_ERR_ADDR;
1500 devip->sense_buff[3] = (ret >> 24) & 0xff;
1501 devip->sense_buff[4] = (ret >> 16) & 0xff;
1502 devip->sense_buff[5] = (ret >> 8) & 0xff;
1503 devip->sense_buff[6] = ret & 0xff;
1504 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 return check_condition_result;
1506 }
1507 read_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001508 if ((lba + num) <= sdebug_store_sectors)
1509 ret = fill_from_dev_buffer(SCpnt,
1510 fake_storep + (lba * SECT_SIZE),
1511 num * SECT_SIZE);
1512 else {
1513 /* modulo when one arg is 64 bits needs do_div() */
1514 u = lba;
1515 block = do_div(u, sdebug_store_sectors);
1516 from_bottom = 0;
1517 if ((block + num) > sdebug_store_sectors)
1518 from_bottom = (block + num) - sdebug_store_sectors;
1519 ret = fill_from_dev_buffer(SCpnt,
1520 fake_storep + (block * SECT_SIZE),
1521 (num - from_bottom) * SECT_SIZE);
1522 if ((0 == ret) && (from_bottom > 0))
1523 ret = fill_from_dev_buffer(SCpnt, fake_storep,
1524 from_bottom * SECT_SIZE);
1525 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 read_unlock_irqrestore(&atomic_rw, iflags);
1527 return ret;
1528}
1529
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001530static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
1531 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532{
1533 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001534 unsigned int block, to_bottom;
1535 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 int res;
1537
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001538 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1540 0);
1541 return check_condition_result;
1542 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001543 /* transfer length excessive (tie in to block limits VPD page) */
1544 if (num > sdebug_store_sectors) {
1545 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1546 0);
1547 return check_condition_result;
1548 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549
1550 write_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001551 if ((lba + num) <= sdebug_store_sectors)
1552 res = fetch_to_dev_buffer(SCpnt,
1553 fake_storep + (lba * SECT_SIZE),
1554 num * SECT_SIZE);
1555 else {
1556 /* modulo when one arg is 64 bits needs do_div() */
1557 u = lba;
1558 block = do_div(u, sdebug_store_sectors);
1559 to_bottom = 0;
1560 if ((block + num) > sdebug_store_sectors)
1561 to_bottom = (block + num) - sdebug_store_sectors;
1562 res = fetch_to_dev_buffer(SCpnt,
1563 fake_storep + (block * SECT_SIZE),
1564 (num - to_bottom) * SECT_SIZE);
1565 if ((0 == res) && (to_bottom > 0))
1566 res = fetch_to_dev_buffer(SCpnt, fake_storep,
1567 to_bottom * SECT_SIZE);
1568 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 write_unlock_irqrestore(&atomic_rw, iflags);
1570 if (-1 == res)
1571 return (DID_ERROR << 16);
1572 else if ((res < (num * SECT_SIZE)) &&
1573 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001574 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 " IO sent=%d bytes\n", num * SECT_SIZE, res);
1576 return 0;
1577}
1578
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001579#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580
1581static int resp_report_luns(struct scsi_cmnd * scp,
1582 struct sdebug_dev_info * devip)
1583{
1584 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001585 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 unsigned char *cmd = (unsigned char *)scp->cmnd;
1587 int select_report = (int)cmd[2];
1588 struct scsi_lun *one_lun;
1589 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001590 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591
1592 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001593 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1595 0);
1596 return check_condition_result;
1597 }
1598 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
1599 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
1600 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001601 if (1 == select_report)
1602 lun_cnt = 0;
1603 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
1604 --lun_cnt;
1605 wlun = (select_report > 0) ? 1 : 0;
1606 num = lun_cnt + wlun;
1607 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
1608 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
1609 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
1610 sizeof(struct scsi_lun)), num);
1611 if (n < num) {
1612 wlun = 0;
1613 lun_cnt = n;
1614 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001616 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
1617 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
1618 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
1619 i++, lun++) {
1620 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 if (upper)
1622 one_lun[i].scsi_lun[0] =
1623 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001624 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001626 if (wlun) {
1627 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
1628 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
1629 i++;
1630 }
1631 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 return fill_from_dev_buffer(scp, arr,
1633 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
1634}
1635
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001636static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
1637 unsigned int num, struct sdebug_dev_info *devip)
1638{
1639 int i, j, ret = -1;
1640 unsigned char *kaddr, *buf;
1641 unsigned int offset;
1642 struct scatterlist *sg;
1643 struct scsi_data_buffer *sdb = scsi_in(scp);
1644
1645 /* better not to use temporary buffer. */
1646 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
1647 if (!buf)
1648 return ret;
1649
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001650 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001651
1652 offset = 0;
1653 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
1654 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
1655 if (!kaddr)
1656 goto out;
1657
1658 for (j = 0; j < sg->length; j++)
1659 *(kaddr + sg->offset + j) ^= *(buf + offset + j);
1660
1661 offset += sg->length;
1662 kunmap_atomic(kaddr, KM_USER0);
1663 }
1664 ret = 0;
1665out:
1666 kfree(buf);
1667
1668 return ret;
1669}
1670
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671/* When timer goes off this function is called. */
1672static void timer_intr_handler(unsigned long indx)
1673{
1674 struct sdebug_queued_cmd * sqcp;
1675 unsigned long iflags;
1676
1677 if (indx >= SCSI_DEBUG_CANQUEUE) {
1678 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
1679 "large\n");
1680 return;
1681 }
1682 spin_lock_irqsave(&queued_arr_lock, iflags);
1683 sqcp = &queued_arr[(int)indx];
1684 if (! sqcp->in_use) {
1685 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
1686 "interrupt\n");
1687 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1688 return;
1689 }
1690 sqcp->in_use = 0;
1691 if (sqcp->done_funct) {
1692 sqcp->a_cmnd->result = sqcp->scsi_result;
1693 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
1694 }
1695 sqcp->done_funct = NULL;
1696 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1697}
1698
1699static int scsi_debug_slave_alloc(struct scsi_device * sdp)
1700{
1701 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001702 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
1703 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001704 set_bit(QUEUE_FLAG_BIDI, &sdp->request_queue->queue_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 return 0;
1706}
1707
1708static int scsi_debug_slave_configure(struct scsi_device * sdp)
1709{
1710 struct sdebug_dev_info * devip;
1711
1712 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001713 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
1714 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
1716 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
1717 devip = devInfoReg(sdp);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001718 if (NULL == devip)
1719 return 1; /* no resources, will be marked offline */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 sdp->hostdata = devip;
1721 if (sdp->host->cmd_per_lun)
1722 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
1723 sdp->host->cmd_per_lun);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001724 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 return 0;
1726}
1727
1728static void scsi_debug_slave_destroy(struct scsi_device * sdp)
1729{
1730 struct sdebug_dev_info * devip =
1731 (struct sdebug_dev_info *)sdp->hostdata;
1732
1733 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001734 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
1735 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 if (devip) {
1737 /* make this slot avaliable for re-use */
1738 devip->used = 0;
1739 sdp->hostdata = NULL;
1740 }
1741}
1742
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09001743struct sdebug_dev_info *sdebug_device_create(struct sdebug_host_info *sdbg_host,
1744 gfp_t flags)
1745{
1746 struct sdebug_dev_info *devip;
1747
1748 devip = kzalloc(sizeof(*devip), flags);
1749 if (devip) {
1750 devip->sdbg_host = sdbg_host;
1751 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
1752 }
1753 return devip;
1754}
1755
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
1757{
1758 struct sdebug_host_info * sdbg_host;
1759 struct sdebug_dev_info * open_devip = NULL;
1760 struct sdebug_dev_info * devip =
1761 (struct sdebug_dev_info *)sdev->hostdata;
1762
1763 if (devip)
1764 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09001765 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
1766 if (!sdbg_host) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 printk(KERN_ERR "Host info NULL\n");
1768 return NULL;
1769 }
1770 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
1771 if ((devip->used) && (devip->channel == sdev->channel) &&
1772 (devip->target == sdev->id) &&
1773 (devip->lun == sdev->lun))
1774 return devip;
1775 else {
1776 if ((!devip->used) && (!open_devip))
1777 open_devip = devip;
1778 }
1779 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09001780 if (!open_devip) { /* try and make a new one */
1781 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
1782 if (!open_devip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 printk(KERN_ERR "%s: out of memory at line %d\n",
1784 __FUNCTION__, __LINE__);
1785 return NULL;
1786 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09001788
1789 open_devip->channel = sdev->channel;
1790 open_devip->target = sdev->id;
1791 open_devip->lun = sdev->lun;
1792 open_devip->sdbg_host = sdbg_host;
1793 open_devip->reset = 1;
1794 open_devip->used = 1;
1795 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
1796 if (scsi_debug_dsense)
1797 open_devip->sense_buff[0] = 0x72;
1798 else {
1799 open_devip->sense_buff[0] = 0x70;
1800 open_devip->sense_buff[7] = 0xa;
1801 }
1802 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
1803 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
1804
1805 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806}
1807
1808static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
1809 int asc, int asq)
1810{
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09001811 unsigned char *sbuff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812
1813 sbuff = devip->sense_buff;
1814 memset(sbuff, 0, SDEBUG_SENSE_LEN);
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09001815
1816 scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
1817
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1819 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
1820 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
1821}
1822
1823static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
1824{
1825 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1826 printk(KERN_INFO "scsi_debug: abort\n");
1827 ++num_aborts;
1828 stop_queued_cmnd(SCpnt);
1829 return SUCCESS;
1830}
1831
1832static int scsi_debug_biosparam(struct scsi_device *sdev,
1833 struct block_device * bdev, sector_t capacity, int *info)
1834{
1835 int res;
1836 unsigned char *buf;
1837
1838 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1839 printk(KERN_INFO "scsi_debug: biosparam\n");
1840 buf = scsi_bios_ptable(bdev);
1841 if (buf) {
1842 res = scsi_partsize(buf, capacity,
1843 &info[2], &info[0], &info[1]);
1844 kfree(buf);
1845 if (! res)
1846 return res;
1847 }
1848 info[0] = sdebug_heads;
1849 info[1] = sdebug_sectors_per;
1850 info[2] = sdebug_cylinders_per;
1851 return 0;
1852}
1853
1854static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
1855{
1856 struct sdebug_dev_info * devip;
1857
1858 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1859 printk(KERN_INFO "scsi_debug: device_reset\n");
1860 ++num_dev_resets;
1861 if (SCpnt) {
1862 devip = devInfoReg(SCpnt->device);
1863 if (devip)
1864 devip->reset = 1;
1865 }
1866 return SUCCESS;
1867}
1868
1869static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
1870{
1871 struct sdebug_host_info *sdbg_host;
1872 struct sdebug_dev_info * dev_info;
1873 struct scsi_device * sdp;
1874 struct Scsi_Host * hp;
1875
1876 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1877 printk(KERN_INFO "scsi_debug: bus_reset\n");
1878 ++num_bus_resets;
1879 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09001880 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 if (sdbg_host) {
1882 list_for_each_entry(dev_info,
1883 &sdbg_host->dev_info_list,
1884 dev_list)
1885 dev_info->reset = 1;
1886 }
1887 }
1888 return SUCCESS;
1889}
1890
1891static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
1892{
1893 struct sdebug_host_info * sdbg_host;
1894 struct sdebug_dev_info * dev_info;
1895
1896 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1897 printk(KERN_INFO "scsi_debug: host_reset\n");
1898 ++num_host_resets;
1899 spin_lock(&sdebug_host_list_lock);
1900 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
1901 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
1902 dev_list)
1903 dev_info->reset = 1;
1904 }
1905 spin_unlock(&sdebug_host_list_lock);
1906 stop_all_queued();
1907 return SUCCESS;
1908}
1909
1910/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
1911static int stop_queued_cmnd(struct scsi_cmnd * cmnd)
1912{
1913 unsigned long iflags;
1914 int k;
1915 struct sdebug_queued_cmd * sqcp;
1916
1917 spin_lock_irqsave(&queued_arr_lock, iflags);
1918 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1919 sqcp = &queued_arr[k];
1920 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
1921 del_timer_sync(&sqcp->cmnd_timer);
1922 sqcp->in_use = 0;
1923 sqcp->a_cmnd = NULL;
1924 break;
1925 }
1926 }
1927 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1928 return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
1929}
1930
1931/* Deletes (stops) timers of all queued commands */
1932static void stop_all_queued(void)
1933{
1934 unsigned long iflags;
1935 int k;
1936 struct sdebug_queued_cmd * sqcp;
1937
1938 spin_lock_irqsave(&queued_arr_lock, iflags);
1939 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1940 sqcp = &queued_arr[k];
1941 if (sqcp->in_use && sqcp->a_cmnd) {
1942 del_timer_sync(&sqcp->cmnd_timer);
1943 sqcp->in_use = 0;
1944 sqcp->a_cmnd = NULL;
1945 }
1946 }
1947 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1948}
1949
1950/* Initializes timers in queued array */
1951static void __init init_all_queued(void)
1952{
1953 unsigned long iflags;
1954 int k;
1955 struct sdebug_queued_cmd * sqcp;
1956
1957 spin_lock_irqsave(&queued_arr_lock, iflags);
1958 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1959 sqcp = &queued_arr[k];
1960 init_timer(&sqcp->cmnd_timer);
1961 sqcp->in_use = 0;
1962 sqcp->a_cmnd = NULL;
1963 }
1964 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1965}
1966
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09001967static void __init sdebug_build_parts(unsigned char *ramp,
1968 unsigned int store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969{
1970 struct partition * pp;
1971 int starts[SDEBUG_MAX_PARTS + 2];
1972 int sectors_per_part, num_sectors, k;
1973 int heads_by_sects, start_sec, end_sec;
1974
1975 /* assume partition table already zeroed */
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09001976 if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 return;
1978 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
1979 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
1980 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
1981 "partitions to %d\n", SDEBUG_MAX_PARTS);
1982 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001983 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 sectors_per_part = (num_sectors - sdebug_sectors_per)
1985 / scsi_debug_num_parts;
1986 heads_by_sects = sdebug_heads * sdebug_sectors_per;
1987 starts[0] = sdebug_sectors_per;
1988 for (k = 1; k < scsi_debug_num_parts; ++k)
1989 starts[k] = ((k * sectors_per_part) / heads_by_sects)
1990 * heads_by_sects;
1991 starts[scsi_debug_num_parts] = num_sectors;
1992 starts[scsi_debug_num_parts + 1] = 0;
1993
1994 ramp[510] = 0x55; /* magic partition markings */
1995 ramp[511] = 0xAA;
1996 pp = (struct partition *)(ramp + 0x1be);
1997 for (k = 0; starts[k + 1]; ++k, ++pp) {
1998 start_sec = starts[k];
1999 end_sec = starts[k + 1] - 1;
2000 pp->boot_ind = 0;
2001
2002 pp->cyl = start_sec / heads_by_sects;
2003 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2004 / sdebug_sectors_per;
2005 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2006
2007 pp->end_cyl = end_sec / heads_by_sects;
2008 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2009 / sdebug_sectors_per;
2010 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2011
2012 pp->start_sect = start_sec;
2013 pp->nr_sects = end_sec - start_sec + 1;
2014 pp->sys_ind = 0x83; /* plain Linux partition */
2015 }
2016}
2017
2018static int schedule_resp(struct scsi_cmnd * cmnd,
2019 struct sdebug_dev_info * devip,
2020 done_funct_t done, int scsi_result, int delta_jiff)
2021{
2022 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2023 if (scsi_result) {
2024 struct scsi_device * sdp = cmnd->device;
2025
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002026 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2027 "non-zero result=0x%x\n", sdp->host->host_no,
2028 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 }
2030 }
2031 if (cmnd && devip) {
2032 /* simulate autosense by this driver */
2033 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2034 memcpy(cmnd->sense_buffer, devip->sense_buff,
2035 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2036 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2037 }
2038 if (delta_jiff <= 0) {
2039 if (cmnd)
2040 cmnd->result = scsi_result;
2041 if (done)
2042 done(cmnd);
2043 return 0;
2044 } else {
2045 unsigned long iflags;
2046 int k;
2047 struct sdebug_queued_cmd * sqcp = NULL;
2048
2049 spin_lock_irqsave(&queued_arr_lock, iflags);
2050 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2051 sqcp = &queued_arr[k];
2052 if (! sqcp->in_use)
2053 break;
2054 }
2055 if (k >= SCSI_DEBUG_CANQUEUE) {
2056 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2057 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2058 return 1; /* report busy to mid level */
2059 }
2060 sqcp->in_use = 1;
2061 sqcp->a_cmnd = cmnd;
2062 sqcp->scsi_result = scsi_result;
2063 sqcp->done_funct = done;
2064 sqcp->cmnd_timer.function = timer_intr_handler;
2065 sqcp->cmnd_timer.data = k;
2066 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2067 add_timer(&sqcp->cmnd_timer);
2068 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2069 if (cmnd)
2070 cmnd->result = 0;
2071 return 0;
2072 }
2073}
2074
Douglas Gilbert23183912006-09-16 20:30:47 -04002075/* Note: The following macros create attribute files in the
2076 /sys/module/scsi_debug/parameters directory. Unfortunately this
2077 driver is unaware of a change and cannot trigger auxiliary actions
2078 as it can when the corresponding attribute in the
2079 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2080 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002081module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2082module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2083module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2084module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2085module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002086module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002087module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2088module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2089module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2090module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2091module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2092module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2093module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2094module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002095module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2096 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097
2098MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2099MODULE_DESCRIPTION("SCSI debug adapter driver");
2100MODULE_LICENSE("GPL");
2101MODULE_VERSION(SCSI_DEBUG_VERSION);
2102
2103MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2104MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002105MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2106MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07002107MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002108MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002109MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2110MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002112MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002113MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2115MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002116MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002117MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118
2119
2120static char sdebug_info[256];
2121
2122static const char * scsi_debug_info(struct Scsi_Host * shp)
2123{
2124 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2125 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2126 scsi_debug_version_date, scsi_debug_dev_size_mb,
2127 scsi_debug_opts);
2128 return sdebug_info;
2129}
2130
2131/* scsi_debug_proc_info
2132 * Used if the driver currently has no own support for /proc/scsi
2133 */
2134static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2135 int length, int inout)
2136{
2137 int len, pos, begin;
2138 int orig_length;
2139
2140 orig_length = length;
2141
2142 if (inout == 1) {
2143 char arr[16];
2144 int minLen = length > 15 ? 15 : length;
2145
2146 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2147 return -EACCES;
2148 memcpy(arr, buffer, minLen);
2149 arr[minLen] = '\0';
2150 if (1 != sscanf(arr, "%d", &pos))
2151 return -EINVAL;
2152 scsi_debug_opts = pos;
2153 if (scsi_debug_every_nth != 0)
2154 scsi_debug_cmnd_count = 0;
2155 return length;
2156 }
2157 begin = 0;
2158 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2159 "%s [%s]\n"
2160 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2161 "every_nth=%d(curr:%d)\n"
2162 "delay=%d, max_luns=%d, scsi_level=%d\n"
2163 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2164 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
2165 "host_resets=%d\n",
2166 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2167 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2168 scsi_debug_cmnd_count, scsi_debug_delay,
2169 scsi_debug_max_luns, scsi_debug_scsi_level,
2170 SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
2171 num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
2172 if (pos < offset) {
2173 len = 0;
2174 begin = pos;
2175 }
2176 *start = buffer + (offset - begin); /* Start of wanted data */
2177 len -= (offset - begin);
2178 if (len > length)
2179 len = length;
2180 return len;
2181}
2182
2183static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2184{
2185 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2186}
2187
2188static ssize_t sdebug_delay_store(struct device_driver * ddp,
2189 const char * buf, size_t count)
2190{
2191 int delay;
2192 char work[20];
2193
2194 if (1 == sscanf(buf, "%10s", work)) {
2195 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2196 scsi_debug_delay = delay;
2197 return count;
2198 }
2199 }
2200 return -EINVAL;
2201}
2202DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2203 sdebug_delay_store);
2204
2205static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2206{
2207 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2208}
2209
2210static ssize_t sdebug_opts_store(struct device_driver * ddp,
2211 const char * buf, size_t count)
2212{
2213 int opts;
2214 char work[20];
2215
2216 if (1 == sscanf(buf, "%10s", work)) {
2217 if (0 == strnicmp(work,"0x", 2)) {
2218 if (1 == sscanf(&work[2], "%x", &opts))
2219 goto opts_done;
2220 } else {
2221 if (1 == sscanf(work, "%d", &opts))
2222 goto opts_done;
2223 }
2224 }
2225 return -EINVAL;
2226opts_done:
2227 scsi_debug_opts = opts;
2228 scsi_debug_cmnd_count = 0;
2229 return count;
2230}
2231DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2232 sdebug_opts_store);
2233
2234static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2235{
2236 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2237}
2238static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2239 const char * buf, size_t count)
2240{
2241 int n;
2242
2243 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2244 scsi_debug_ptype = n;
2245 return count;
2246 }
2247 return -EINVAL;
2248}
2249DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2250
2251static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2252{
2253 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2254}
2255static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2256 const char * buf, size_t count)
2257{
2258 int n;
2259
2260 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2261 scsi_debug_dsense = n;
2262 return count;
2263 }
2264 return -EINVAL;
2265}
2266DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2267 sdebug_dsense_store);
2268
Douglas Gilbert23183912006-09-16 20:30:47 -04002269static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2270{
2271 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2272}
2273static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2274 const char * buf, size_t count)
2275{
2276 int n;
2277
2278 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2279 scsi_debug_fake_rw = n;
2280 return count;
2281 }
2282 return -EINVAL;
2283}
2284DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2285 sdebug_fake_rw_store);
2286
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002287static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2288{
2289 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2290}
2291static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2292 const char * buf, size_t count)
2293{
2294 int n;
2295
2296 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2297 scsi_debug_no_lun_0 = n;
2298 return count;
2299 }
2300 return -EINVAL;
2301}
2302DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2303 sdebug_no_lun_0_store);
2304
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2306{
2307 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2308}
2309static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2310 const char * buf, size_t count)
2311{
2312 int n;
2313
2314 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2315 scsi_debug_num_tgts = n;
2316 sdebug_max_tgts_luns();
2317 return count;
2318 }
2319 return -EINVAL;
2320}
2321DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2322 sdebug_num_tgts_store);
2323
2324static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2325{
2326 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2327}
2328DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2329
2330static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2331{
2332 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2333}
2334DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2335
2336static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2337{
2338 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2339}
2340static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2341 const char * buf, size_t count)
2342{
2343 int nth;
2344
2345 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2346 scsi_debug_every_nth = nth;
2347 scsi_debug_cmnd_count = 0;
2348 return count;
2349 }
2350 return -EINVAL;
2351}
2352DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2353 sdebug_every_nth_store);
2354
2355static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2356{
2357 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2358}
2359static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2360 const char * buf, size_t count)
2361{
2362 int n;
2363
2364 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2365 scsi_debug_max_luns = n;
2366 sdebug_max_tgts_luns();
2367 return count;
2368 }
2369 return -EINVAL;
2370}
2371DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2372 sdebug_max_luns_store);
2373
2374static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
2375{
2376 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
2377}
2378DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
2379
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002380static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2381{
2382 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2383}
2384static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2385 const char * buf, size_t count)
2386{
2387 int n;
2388
2389 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2390 scsi_debug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002391
2392 sdebug_capacity = get_sdebug_capacity();
2393
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002394 return count;
2395 }
2396 return -EINVAL;
2397}
2398DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2399 sdebug_virtual_gb_store);
2400
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
2402{
2403 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
2404}
2405
2406static ssize_t sdebug_add_host_store(struct device_driver * ddp,
2407 const char * buf, size_t count)
2408{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002409 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002411 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 if (delta_hosts > 0) {
2414 do {
2415 sdebug_add_adapter();
2416 } while (--delta_hosts);
2417 } else if (delta_hosts < 0) {
2418 do {
2419 sdebug_remove_adapter();
2420 } while (++delta_hosts);
2421 }
2422 return count;
2423}
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002424DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 sdebug_add_host_store);
2426
Douglas Gilbert23183912006-09-16 20:30:47 -04002427static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
2428 char * buf)
2429{
2430 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
2431}
2432static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
2433 const char * buf, size_t count)
2434{
2435 int n;
2436
2437 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2438 scsi_debug_vpd_use_hostno = n;
2439 return count;
2440 }
2441 return -EINVAL;
2442}
2443DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
2444 sdebug_vpd_use_hostno_store);
2445
2446/* Note: The following function creates attribute files in the
2447 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
2448 files (over those found in the /sys/module/scsi_debug/parameters
2449 directory) is that auxiliary actions can be triggered when an attribute
2450 is changed. For example see: sdebug_add_host_store() above.
2451 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002452static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002454 int ret;
2455
2456 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2457 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
2458 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2459 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2460 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04002461 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002462 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002463 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002464 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002465 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002466 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
2467 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
2468 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04002469 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
2470 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002471 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472}
2473
2474static void do_remove_driverfs_files(void)
2475{
Douglas Gilbert23183912006-09-16 20:30:47 -04002476 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
2477 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
2479 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
2480 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002482 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
2483 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002485 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
2487 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2488 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2489 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
2490 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2491}
2492
2493static int __init scsi_debug_init(void)
2494{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002495 unsigned int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 int host_to_add;
2497 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002498 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499
2500 if (scsi_debug_dev_size_mb < 1)
2501 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002502 sz = (unsigned int)scsi_debug_dev_size_mb * 1048576;
2503 sdebug_store_sectors = sz / SECT_SIZE;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002504 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505
2506 /* play around with geometry, don't waste too much on track 0 */
2507 sdebug_heads = 8;
2508 sdebug_sectors_per = 32;
2509 if (scsi_debug_dev_size_mb >= 16)
2510 sdebug_heads = 32;
2511 else if (scsi_debug_dev_size_mb >= 256)
2512 sdebug_heads = 64;
2513 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2514 (sdebug_sectors_per * sdebug_heads);
2515 if (sdebug_cylinders_per >= 1024) {
2516 /* other LLDs do this; implies >= 1GB ram disk ... */
2517 sdebug_heads = 255;
2518 sdebug_sectors_per = 63;
2519 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2520 (sdebug_sectors_per * sdebug_heads);
2521 }
2522
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 fake_storep = vmalloc(sz);
2524 if (NULL == fake_storep) {
2525 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
2526 return -ENOMEM;
2527 }
2528 memset(fake_storep, 0, sz);
2529 if (scsi_debug_num_parts > 0)
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002530 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002532 ret = device_register(&pseudo_primary);
2533 if (ret < 0) {
2534 printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
2535 ret);
2536 goto free_vm;
2537 }
2538 ret = bus_register(&pseudo_lld_bus);
2539 if (ret < 0) {
2540 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
2541 ret);
2542 goto dev_unreg;
2543 }
2544 ret = driver_register(&sdebug_driverfs_driver);
2545 if (ret < 0) {
2546 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
2547 ret);
2548 goto bus_unreg;
2549 }
2550 ret = do_create_driverfs_files();
2551 if (ret < 0) {
2552 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
2553 ret);
2554 goto del_files;
2555 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002557 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 host_to_add = scsi_debug_add_host;
2560 scsi_debug_add_host = 0;
2561
2562 for (k = 0; k < host_to_add; k++) {
2563 if (sdebug_add_adapter()) {
2564 printk(KERN_ERR "scsi_debug_init: "
2565 "sdebug_add_adapter failed k=%d\n", k);
2566 break;
2567 }
2568 }
2569
2570 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
2571 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
2572 scsi_debug_add_host);
2573 }
2574 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002575
2576del_files:
2577 do_remove_driverfs_files();
2578 driver_unregister(&sdebug_driverfs_driver);
2579bus_unreg:
2580 bus_unregister(&pseudo_lld_bus);
2581dev_unreg:
2582 device_unregister(&pseudo_primary);
2583free_vm:
2584 vfree(fake_storep);
2585
2586 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587}
2588
2589static void __exit scsi_debug_exit(void)
2590{
2591 int k = scsi_debug_add_host;
2592
2593 stop_all_queued();
2594 for (; k; k--)
2595 sdebug_remove_adapter();
2596 do_remove_driverfs_files();
2597 driver_unregister(&sdebug_driverfs_driver);
2598 bus_unregister(&pseudo_lld_bus);
2599 device_unregister(&pseudo_primary);
2600
2601 vfree(fake_storep);
2602}
2603
2604device_initcall(scsi_debug_init);
2605module_exit(scsi_debug_exit);
2606
Adrian Bunk52c1da32005-06-23 22:05:33 -07002607static void pseudo_0_release(struct device * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608{
2609 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2610 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
2611}
2612
2613static struct device pseudo_primary = {
2614 .bus_id = "pseudo_0",
2615 .release = pseudo_0_release,
2616};
2617
2618static int pseudo_lld_bus_match(struct device *dev,
2619 struct device_driver *dev_driver)
2620{
2621 return 1;
2622}
2623
2624static struct bus_type pseudo_lld_bus = {
2625 .name = "pseudo",
2626 .match = pseudo_lld_bus_match,
Russell Kingbbbe3a42006-01-05 14:44:46 +00002627 .probe = sdebug_driver_probe,
2628 .remove = sdebug_driver_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629};
2630
2631static void sdebug_release_adapter(struct device * dev)
2632{
2633 struct sdebug_host_info *sdbg_host;
2634
2635 sdbg_host = to_sdebug_host(dev);
2636 kfree(sdbg_host);
2637}
2638
2639static int sdebug_add_adapter(void)
2640{
2641 int k, devs_per_host;
2642 int error = 0;
2643 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09002644 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002646 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 if (NULL == sdbg_host) {
2648 printk(KERN_ERR "%s: out of memory at line %d\n",
2649 __FUNCTION__, __LINE__);
2650 return -ENOMEM;
2651 }
2652
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
2654
2655 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
2656 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002657 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
2658 if (!sdbg_devinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 printk(KERN_ERR "%s: out of memory at line %d\n",
2660 __FUNCTION__, __LINE__);
2661 error = -ENOMEM;
2662 goto clean;
2663 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 }
2665
2666 spin_lock(&sdebug_host_list_lock);
2667 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
2668 spin_unlock(&sdebug_host_list_lock);
2669
2670 sdbg_host->dev.bus = &pseudo_lld_bus;
2671 sdbg_host->dev.parent = &pseudo_primary;
2672 sdbg_host->dev.release = &sdebug_release_adapter;
2673 sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host);
2674
2675 error = device_register(&sdbg_host->dev);
2676
2677 if (error)
2678 goto clean;
2679
2680 ++scsi_debug_add_host;
2681 return error;
2682
2683clean:
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09002684 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
2685 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 list_del(&sdbg_devinfo->dev_list);
2687 kfree(sdbg_devinfo);
2688 }
2689
2690 kfree(sdbg_host);
2691 return error;
2692}
2693
2694static void sdebug_remove_adapter(void)
2695{
2696 struct sdebug_host_info * sdbg_host = NULL;
2697
2698 spin_lock(&sdebug_host_list_lock);
2699 if (!list_empty(&sdebug_host_list)) {
2700 sdbg_host = list_entry(sdebug_host_list.prev,
2701 struct sdebug_host_info, host_list);
2702 list_del(&sdbg_host->host_list);
2703 }
2704 spin_unlock(&sdebug_host_list_lock);
2705
2706 if (!sdbg_host)
2707 return;
2708
2709 device_unregister(&sdbg_host->dev);
2710 --scsi_debug_add_host;
2711}
2712
FUJITA Tomonori639db472008-03-20 11:09:19 +09002713static
2714int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
2715{
2716 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
2717 int len, k;
2718 unsigned int num;
2719 unsigned long long lba;
2720 int errsts = 0;
2721 int target = SCpnt->device->id;
2722 struct sdebug_dev_info *devip = NULL;
2723 int inj_recovered = 0;
2724 int inj_transport = 0;
2725 int delay_override = 0;
2726
2727 scsi_set_resid(SCpnt, 0);
2728 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
2729 printk(KERN_INFO "scsi_debug: cmd ");
2730 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
2731 printk("%02x ", (int)cmd[k]);
2732 printk("\n");
2733 }
2734
2735 if (target == SCpnt->device->host->hostt->this_id) {
2736 printk(KERN_INFO "scsi_debug: initiator's id used as "
2737 "target!\n");
2738 return schedule_resp(SCpnt, NULL, done,
2739 DID_NO_CONNECT << 16, 0);
2740 }
2741
2742 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
2743 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
2744 return schedule_resp(SCpnt, NULL, done,
2745 DID_NO_CONNECT << 16, 0);
2746 devip = devInfoReg(SCpnt->device);
2747 if (NULL == devip)
2748 return schedule_resp(SCpnt, NULL, done,
2749 DID_NO_CONNECT << 16, 0);
2750
2751 if ((scsi_debug_every_nth != 0) &&
2752 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
2753 scsi_debug_cmnd_count = 0;
2754 if (scsi_debug_every_nth < -1)
2755 scsi_debug_every_nth = -1;
2756 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
2757 return 0; /* ignore command causing timeout */
2758 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
2759 inj_recovered = 1; /* to reads and writes below */
2760 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
2761 inj_transport = 1; /* to reads and writes below */
2762 }
2763
2764 if (devip->wlun) {
2765 switch (*cmd) {
2766 case INQUIRY:
2767 case REQUEST_SENSE:
2768 case TEST_UNIT_READY:
2769 case REPORT_LUNS:
2770 break; /* only allowable wlun commands */
2771 default:
2772 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2773 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
2774 "not supported for wlun\n", *cmd);
2775 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2776 INVALID_OPCODE, 0);
2777 errsts = check_condition_result;
2778 return schedule_resp(SCpnt, devip, done, errsts,
2779 0);
2780 }
2781 }
2782
2783 switch (*cmd) {
2784 case INQUIRY: /* mandatory, ignore unit attention */
2785 delay_override = 1;
2786 errsts = resp_inquiry(SCpnt, target, devip);
2787 break;
2788 case REQUEST_SENSE: /* mandatory, ignore unit attention */
2789 delay_override = 1;
2790 errsts = resp_requests(SCpnt, devip);
2791 break;
2792 case REZERO_UNIT: /* actually this is REWIND for SSC */
2793 case START_STOP:
2794 errsts = resp_start_stop(SCpnt, devip);
2795 break;
2796 case ALLOW_MEDIUM_REMOVAL:
2797 errsts = check_readiness(SCpnt, 1, devip);
2798 if (errsts)
2799 break;
2800 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2801 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
2802 cmd[4] ? "inhibited" : "enabled");
2803 break;
2804 case SEND_DIAGNOSTIC: /* mandatory */
2805 errsts = check_readiness(SCpnt, 1, devip);
2806 break;
2807 case TEST_UNIT_READY: /* mandatory */
2808 delay_override = 1;
2809 errsts = check_readiness(SCpnt, 0, devip);
2810 break;
2811 case RESERVE:
2812 errsts = check_readiness(SCpnt, 1, devip);
2813 break;
2814 case RESERVE_10:
2815 errsts = check_readiness(SCpnt, 1, devip);
2816 break;
2817 case RELEASE:
2818 errsts = check_readiness(SCpnt, 1, devip);
2819 break;
2820 case RELEASE_10:
2821 errsts = check_readiness(SCpnt, 1, devip);
2822 break;
2823 case READ_CAPACITY:
2824 errsts = resp_readcap(SCpnt, devip);
2825 break;
2826 case SERVICE_ACTION_IN:
2827 if (SAI_READ_CAPACITY_16 != cmd[1]) {
2828 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2829 INVALID_OPCODE, 0);
2830 errsts = check_condition_result;
2831 break;
2832 }
2833 errsts = resp_readcap16(SCpnt, devip);
2834 break;
2835 case MAINTENANCE_IN:
2836 if (MI_REPORT_TARGET_PGS != cmd[1]) {
2837 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2838 INVALID_OPCODE, 0);
2839 errsts = check_condition_result;
2840 break;
2841 }
2842 errsts = resp_report_tgtpgs(SCpnt, devip);
2843 break;
2844 case READ_16:
2845 case READ_12:
2846 case READ_10:
2847 case READ_6:
2848 errsts = check_readiness(SCpnt, 0, devip);
2849 if (errsts)
2850 break;
2851 if (scsi_debug_fake_rw)
2852 break;
2853 get_data_transfer_info(cmd, &lba, &num);
2854 errsts = resp_read(SCpnt, lba, num, devip);
2855 if (inj_recovered && (0 == errsts)) {
2856 mk_sense_buffer(devip, RECOVERED_ERROR,
2857 THRESHOLD_EXCEEDED, 0);
2858 errsts = check_condition_result;
2859 } else if (inj_transport && (0 == errsts)) {
2860 mk_sense_buffer(devip, ABORTED_COMMAND,
2861 TRANSPORT_PROBLEM, ACK_NAK_TO);
2862 errsts = check_condition_result;
2863 }
2864 break;
2865 case REPORT_LUNS: /* mandatory, ignore unit attention */
2866 delay_override = 1;
2867 errsts = resp_report_luns(SCpnt, devip);
2868 break;
2869 case VERIFY: /* 10 byte SBC-2 command */
2870 errsts = check_readiness(SCpnt, 0, devip);
2871 break;
2872 case WRITE_16:
2873 case WRITE_12:
2874 case WRITE_10:
2875 case WRITE_6:
2876 errsts = check_readiness(SCpnt, 0, devip);
2877 if (errsts)
2878 break;
2879 if (scsi_debug_fake_rw)
2880 break;
2881 get_data_transfer_info(cmd, &lba, &num);
2882 errsts = resp_write(SCpnt, lba, num, devip);
2883 if (inj_recovered && (0 == errsts)) {
2884 mk_sense_buffer(devip, RECOVERED_ERROR,
2885 THRESHOLD_EXCEEDED, 0);
2886 errsts = check_condition_result;
2887 }
2888 break;
2889 case MODE_SENSE:
2890 case MODE_SENSE_10:
2891 errsts = resp_mode_sense(SCpnt, target, devip);
2892 break;
2893 case MODE_SELECT:
2894 errsts = resp_mode_select(SCpnt, 1, devip);
2895 break;
2896 case MODE_SELECT_10:
2897 errsts = resp_mode_select(SCpnt, 0, devip);
2898 break;
2899 case LOG_SENSE:
2900 errsts = resp_log_sense(SCpnt, devip);
2901 break;
2902 case SYNCHRONIZE_CACHE:
2903 delay_override = 1;
2904 errsts = check_readiness(SCpnt, 0, devip);
2905 break;
2906 case WRITE_BUFFER:
2907 errsts = check_readiness(SCpnt, 1, devip);
2908 break;
2909 case XDWRITEREAD_10:
2910 if (!scsi_bidi_cmnd(SCpnt)) {
2911 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2912 INVALID_FIELD_IN_CDB, 0);
2913 errsts = check_condition_result;
2914 break;
2915 }
2916
2917 errsts = check_readiness(SCpnt, 0, devip);
2918 if (errsts)
2919 break;
2920 if (scsi_debug_fake_rw)
2921 break;
2922 get_data_transfer_info(cmd, &lba, &num);
2923 errsts = resp_read(SCpnt, lba, num, devip);
2924 if (errsts)
2925 break;
2926 errsts = resp_write(SCpnt, lba, num, devip);
2927 if (errsts)
2928 break;
2929 errsts = resp_xdwriteread(SCpnt, lba, num, devip);
2930 break;
2931 default:
2932 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2933 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
2934 "supported\n", *cmd);
2935 errsts = check_readiness(SCpnt, 1, devip);
2936 if (errsts)
2937 break; /* Unit attention takes precedence */
2938 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
2939 errsts = check_condition_result;
2940 break;
2941 }
2942 return schedule_resp(SCpnt, devip, done, errsts,
2943 (delay_override ? 0 : scsi_debug_delay));
2944}
2945
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09002946static struct scsi_host_template sdebug_driver_template = {
2947 .proc_info = scsi_debug_proc_info,
2948 .proc_name = sdebug_proc_name,
2949 .name = "SCSI DEBUG",
2950 .info = scsi_debug_info,
2951 .slave_alloc = scsi_debug_slave_alloc,
2952 .slave_configure = scsi_debug_slave_configure,
2953 .slave_destroy = scsi_debug_slave_destroy,
2954 .ioctl = scsi_debug_ioctl,
2955 .queuecommand = scsi_debug_queuecommand,
2956 .eh_abort_handler = scsi_debug_abort,
2957 .eh_bus_reset_handler = scsi_debug_bus_reset,
2958 .eh_device_reset_handler = scsi_debug_device_reset,
2959 .eh_host_reset_handler = scsi_debug_host_reset,
2960 .bios_param = scsi_debug_biosparam,
2961 .can_queue = SCSI_DEBUG_CANQUEUE,
2962 .this_id = 7,
2963 .sg_tablesize = 256,
2964 .cmd_per_lun = 16,
2965 .max_sectors = 0xffff,
2966 .use_clustering = DISABLE_CLUSTERING,
2967 .module = THIS_MODULE,
2968};
2969
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970static int sdebug_driver_probe(struct device * dev)
2971{
2972 int error = 0;
2973 struct sdebug_host_info *sdbg_host;
2974 struct Scsi_Host *hpnt;
2975
2976 sdbg_host = to_sdebug_host(dev);
2977
2978 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
2979 if (NULL == hpnt) {
2980 printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__);
2981 error = -ENODEV;
2982 return error;
2983 }
2984
2985 sdbg_host->shost = hpnt;
2986 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
2987 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
2988 hpnt->max_id = scsi_debug_num_tgts + 1;
2989 else
2990 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002991 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992
2993 error = scsi_add_host(hpnt, &sdbg_host->dev);
2994 if (error) {
2995 printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
2996 error = -ENODEV;
2997 scsi_host_put(hpnt);
2998 } else
2999 scsi_scan_host(hpnt);
3000
3001
3002 return error;
3003}
3004
3005static int sdebug_driver_remove(struct device * dev)
3006{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003008 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009
3010 sdbg_host = to_sdebug_host(dev);
3011
3012 if (!sdbg_host) {
3013 printk(KERN_ERR "%s: Unable to locate host info\n",
3014 __FUNCTION__);
3015 return -ENODEV;
3016 }
3017
3018 scsi_remove_host(sdbg_host->shost);
3019
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003020 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
3021 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 list_del(&sdbg_devinfo->dev_list);
3023 kfree(sdbg_devinfo);
3024 }
3025
3026 scsi_host_put(sdbg_host->shost);
3027 return 0;
3028}
3029
3030static void sdebug_max_tgts_luns(void)
3031{
3032 struct sdebug_host_info * sdbg_host;
3033 struct Scsi_Host *hpnt;
3034
3035 spin_lock(&sdebug_host_list_lock);
3036 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3037 hpnt = sdbg_host->shost;
3038 if ((hpnt->this_id >= 0) &&
3039 (scsi_debug_num_tgts > hpnt->this_id))
3040 hpnt->max_id = scsi_debug_num_tgts + 1;
3041 else
3042 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003043 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 }
3045 spin_unlock(&sdebug_host_list_lock);
3046}