blob: 3abd2861a58a7753c0ea2443f5bc99e68f0382cc [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>
49
50#include <linux/stat.h>
51
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include "scsi_logging.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050054#define SCSI_DEBUG_VERSION "1.81"
55static const char * scsi_debug_version_date = "20070104";
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050057/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040058#define NO_ADDITIONAL_SENSE 0x0
59#define LOGICAL_UNIT_NOT_READY 0x4
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040061#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#define INVALID_OPCODE 0x20
63#define ADDR_OUT_OF_RANGE 0x21
64#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040065#define INVALID_FIELD_IN_PARAM_LIST 0x26
Linus Torvalds1da177e2005-04-16 15:20:36 -070066#define POWERON_RESET 0x29
67#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050068#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040069#define THRESHOLD_EXCEEDED 0x5d
70#define LOW_POWER_COND_ON 0x5e
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050072/* Additional Sense Code Qualifier (ASCQ) */
73#define ACK_NAK_TO 0x3
74
Linus Torvalds1da177e2005-04-16 15:20:36 -070075#define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
76
77/* Default values for driver parameters */
78#define DEF_NUM_HOST 1
79#define DEF_NUM_TGTS 1
80#define DEF_MAX_LUNS 1
81/* With these defaults, this driver will make 1 host with 1 target
82 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
83 */
84#define DEF_DELAY 1
85#define DEF_DEV_SIZE_MB 8
86#define DEF_EVERY_NTH 0
87#define DEF_NUM_PARTS 0
88#define DEF_OPTS 0
89#define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */
90#define DEF_PTYPE 0
91#define DEF_D_SENSE 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -040092#define DEF_NO_LUN_0 0
93#define DEF_VIRTUAL_GB 0
Douglas Gilbert23183912006-09-16 20:30:47 -040094#define DEF_FAKE_RW 0
95#define DEF_VPD_USE_HOSTNO 1
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
97/* bit mask values for scsi_debug_opts */
98#define SCSI_DEBUG_OPT_NOISE 1
99#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
100#define SCSI_DEBUG_OPT_TIMEOUT 4
101#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500102#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103/* When "every_nth" > 0 then modulo "every_nth" commands:
104 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
105 * - a RECOVERED_ERROR is simulated on successful read and write
106 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500107 * - a TRANSPORT_ERROR is simulated on successful read and write
108 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 *
110 * When "every_nth" < 0 then after "- every_nth" commands:
111 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
112 * - a RECOVERED_ERROR is simulated on successful read and write
113 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500114 * - a TRANSPORT_ERROR is simulated on successful read and write
115 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 * This will continue until some other action occurs (e.g. the user
117 * writing a new value (other than -1 or 1) to every_nth via sysfs).
118 */
119
120/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
121 * sector on read commands: */
122#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
123
124/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
125 * or "peripheral device" addressing (value 0) */
126#define SAM2_LUN_ADDRESS_METHOD 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400127#define SAM2_WLUN_REPORT_LUNS 0xc101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128
129static int scsi_debug_add_host = DEF_NUM_HOST;
130static int scsi_debug_delay = DEF_DELAY;
131static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
132static int scsi_debug_every_nth = DEF_EVERY_NTH;
133static int scsi_debug_max_luns = DEF_MAX_LUNS;
134static int scsi_debug_num_parts = DEF_NUM_PARTS;
135static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
136static int scsi_debug_opts = DEF_OPTS;
137static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
138static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
139static int scsi_debug_dsense = DEF_D_SENSE;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400140static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
141static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
Douglas Gilbert23183912006-09-16 20:30:47 -0400142static int scsi_debug_fake_rw = DEF_FAKE_RW;
143static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
145static int scsi_debug_cmnd_count = 0;
146
147#define DEV_READONLY(TGT) (0)
148#define DEV_REMOVEABLE(TGT) (0)
149
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400150static unsigned int sdebug_store_size; /* in bytes */
151static 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 -0700238/* function declarations */
239static int resp_inquiry(struct scsi_cmnd * SCpnt, int target,
240 struct sdebug_dev_info * devip);
241static int resp_requests(struct scsi_cmnd * SCpnt,
242 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400243static int resp_start_stop(struct scsi_cmnd * scp,
244 struct sdebug_dev_info * devip);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200245static int resp_report_tgtpgs(struct scsi_cmnd * scp,
246 struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247static int resp_readcap(struct scsi_cmnd * SCpnt,
248 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400249static int resp_readcap16(struct scsi_cmnd * SCpnt,
250 struct sdebug_dev_info * devip);
251static int resp_mode_sense(struct scsi_cmnd * scp, int target,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400253static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
254 struct sdebug_dev_info * devip);
255static int resp_log_sense(struct scsi_cmnd * scp,
256 struct sdebug_dev_info * devip);
257static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
258 unsigned int num, struct sdebug_dev_info * devip);
259static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
260 unsigned int num, struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261static int resp_report_luns(struct scsi_cmnd * SCpnt,
262 struct sdebug_dev_info * devip);
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900263static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
264 unsigned int num, struct sdebug_dev_info *devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
266 int arr_len);
267static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
268 int max_arr_len);
269static void timer_intr_handler(unsigned long);
270static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev);
271static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
272 int asc, int asq);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400273static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
274 struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275static int schedule_resp(struct scsi_cmnd * cmnd,
276 struct sdebug_dev_info * devip,
277 done_funct_t done, int scsi_result, int delta_jiff);
278static void __init sdebug_build_parts(unsigned char * ramp);
279static void __init init_all_queued(void);
280static void stop_all_queued(void);
281static int stop_queued_cmnd(struct scsi_cmnd * cmnd);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200282static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
283 int target_dev_id, int dev_id_num,
284 const char * dev_id_str, int dev_id_str_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400285static int inquiry_evpd_88(unsigned char * arr, int target_dev_id);
Randy Dunlap6ecaff72006-07-11 20:53:22 -0700286static int do_create_driverfs_files(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287static void do_remove_driverfs_files(void);
288
289static int sdebug_add_adapter(void);
290static void sdebug_remove_adapter(void);
291static void sdebug_max_tgts_luns(void);
292
293static struct device pseudo_primary;
294static struct bus_type pseudo_lld_bus;
295
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900296static void get_data_transfer_info(unsigned char *cmd,
297 unsigned long long *lba, unsigned int *num)
298{
299 int i;
300
301 switch (*cmd) {
302 case WRITE_16:
303 case READ_16:
304 for (*lba = 0, i = 0; i < 8; ++i) {
305 if (i > 0)
306 *lba <<= 8;
307 *lba += cmd[2 + i];
308 }
309 *num = cmd[13] + (cmd[12] << 8) +
310 (cmd[11] << 16) + (cmd[10] << 24);
311 break;
312 case WRITE_12:
313 case READ_12:
314 *lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
315 *num = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
316 break;
317 case WRITE_10:
318 case READ_10:
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900319 case XDWRITEREAD_10:
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900320 *lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
321 *num = cmd[8] + (cmd[7] << 8);
322 break;
323 case WRITE_6:
324 case READ_6:
325 *lba = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
326 *num = (0 == cmd[4]) ? 256 : cmd[4];
327 break;
328 default:
329 break;
330 }
331}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
333static
334int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
335{
336 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900337 int len, k;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400338 unsigned int num;
339 unsigned long long lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 int errsts = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400341 int target = SCpnt->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 struct sdebug_dev_info * devip = NULL;
343 int inj_recovered = 0;
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500344 int inj_transport = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400345 int delay_override = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
Boaz Harroshc73961e2007-09-07 06:50:20 +0900347 scsi_set_resid(SCpnt, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
349 printk(KERN_INFO "scsi_debug: cmd ");
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400350 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 printk("%02x ", (int)cmd[k]);
352 printk("\n");
353 }
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +0900354
355 if (target == SCpnt->device->host->hostt->this_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 printk(KERN_INFO "scsi_debug: initiator's id used as "
357 "target!\n");
358 return schedule_resp(SCpnt, NULL, done,
359 DID_NO_CONNECT << 16, 0);
360 }
361
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400362 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
363 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 return schedule_resp(SCpnt, NULL, done,
365 DID_NO_CONNECT << 16, 0);
366 devip = devInfoReg(SCpnt->device);
367 if (NULL == devip)
368 return schedule_resp(SCpnt, NULL, done,
369 DID_NO_CONNECT << 16, 0);
370
371 if ((scsi_debug_every_nth != 0) &&
372 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
373 scsi_debug_cmnd_count = 0;
374 if (scsi_debug_every_nth < -1)
375 scsi_debug_every_nth = -1;
376 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
377 return 0; /* ignore command causing timeout */
378 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
379 inj_recovered = 1; /* to reads and writes below */
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500380 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
381 inj_transport = 1; /* to reads and writes below */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 }
383
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400384 if (devip->wlun) {
385 switch (*cmd) {
386 case INQUIRY:
387 case REQUEST_SENSE:
388 case TEST_UNIT_READY:
389 case REPORT_LUNS:
390 break; /* only allowable wlun commands */
391 default:
392 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
393 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
394 "not supported for wlun\n", *cmd);
395 mk_sense_buffer(devip, ILLEGAL_REQUEST,
396 INVALID_OPCODE, 0);
397 errsts = check_condition_result;
398 return schedule_resp(SCpnt, devip, done, errsts,
399 0);
400 }
401 }
402
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 switch (*cmd) {
404 case INQUIRY: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400405 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 errsts = resp_inquiry(SCpnt, target, devip);
407 break;
408 case REQUEST_SENSE: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400409 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 errsts = resp_requests(SCpnt, devip);
411 break;
412 case REZERO_UNIT: /* actually this is REWIND for SSC */
413 case START_STOP:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400414 errsts = resp_start_stop(SCpnt, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 break;
416 case ALLOW_MEDIUM_REMOVAL:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400417 if ((errsts = check_readiness(SCpnt, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 break;
419 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
420 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
421 cmd[4] ? "inhibited" : "enabled");
422 break;
423 case SEND_DIAGNOSTIC: /* mandatory */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400424 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 break;
426 case TEST_UNIT_READY: /* mandatory */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400427 delay_override = 1;
428 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 break;
430 case RESERVE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400431 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 break;
433 case RESERVE_10:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400434 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 break;
436 case RELEASE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400437 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 break;
439 case RELEASE_10:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400440 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 break;
442 case READ_CAPACITY:
443 errsts = resp_readcap(SCpnt, devip);
444 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400445 case SERVICE_ACTION_IN:
446 if (SAI_READ_CAPACITY_16 != cmd[1]) {
447 mk_sense_buffer(devip, ILLEGAL_REQUEST,
448 INVALID_OPCODE, 0);
449 errsts = check_condition_result;
450 break;
451 }
452 errsts = resp_readcap16(SCpnt, devip);
453 break;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200454 case MAINTENANCE_IN:
455 if (MI_REPORT_TARGET_PGS != cmd[1]) {
456 mk_sense_buffer(devip, ILLEGAL_REQUEST,
457 INVALID_OPCODE, 0);
458 errsts = check_condition_result;
459 break;
460 }
461 errsts = resp_report_tgtpgs(SCpnt, devip);
462 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 case READ_16:
464 case READ_12:
465 case READ_10:
466 case READ_6:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400467 if ((errsts = check_readiness(SCpnt, 0, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 break;
Douglas Gilbert23183912006-09-16 20:30:47 -0400469 if (scsi_debug_fake_rw)
470 break;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900471 get_data_transfer_info(cmd, &lba, &num);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400472 errsts = resp_read(SCpnt, lba, num, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 if (inj_recovered && (0 == errsts)) {
474 mk_sense_buffer(devip, RECOVERED_ERROR,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400475 THRESHOLD_EXCEEDED, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 errsts = check_condition_result;
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500477 } else if (inj_transport && (0 == errsts)) {
478 mk_sense_buffer(devip, ABORTED_COMMAND,
479 TRANSPORT_PROBLEM, ACK_NAK_TO);
480 errsts = check_condition_result;
481 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 break;
483 case REPORT_LUNS: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400484 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 errsts = resp_report_luns(SCpnt, devip);
486 break;
487 case VERIFY: /* 10 byte SBC-2 command */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400488 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 break;
490 case WRITE_16:
491 case WRITE_12:
492 case WRITE_10:
493 case WRITE_6:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400494 if ((errsts = check_readiness(SCpnt, 0, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 break;
Douglas Gilbert23183912006-09-16 20:30:47 -0400496 if (scsi_debug_fake_rw)
497 break;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900498 get_data_transfer_info(cmd, &lba, &num);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400499 errsts = resp_write(SCpnt, lba, num, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 if (inj_recovered && (0 == errsts)) {
501 mk_sense_buffer(devip, RECOVERED_ERROR,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400502 THRESHOLD_EXCEEDED, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 errsts = check_condition_result;
504 }
505 break;
506 case MODE_SENSE:
507 case MODE_SENSE_10:
508 errsts = resp_mode_sense(SCpnt, target, devip);
509 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400510 case MODE_SELECT:
511 errsts = resp_mode_select(SCpnt, 1, devip);
512 break;
513 case MODE_SELECT_10:
514 errsts = resp_mode_select(SCpnt, 0, devip);
515 break;
516 case LOG_SENSE:
517 errsts = resp_log_sense(SCpnt, devip);
518 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 case SYNCHRONIZE_CACHE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400520 delay_override = 1;
521 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 break;
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500523 case WRITE_BUFFER:
524 errsts = check_readiness(SCpnt, 1, devip);
525 break;
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900526 case XDWRITEREAD_10:
527 if (!scsi_bidi_cmnd(SCpnt)) {
528 mk_sense_buffer(devip, ILLEGAL_REQUEST,
529 INVALID_FIELD_IN_CDB, 0);
530 errsts = check_condition_result;
531 break;
532 }
533
534 errsts = check_readiness(SCpnt, 0, devip);
535 if (errsts)
536 break;
537 if (scsi_debug_fake_rw)
538 break;
539 get_data_transfer_info(cmd, &lba, &num);
540 errsts = resp_read(SCpnt, lba, num, devip);
541 if (errsts)
542 break;
543 errsts = resp_write(SCpnt, lba, num, devip);
544 if (errsts)
545 break;
546 errsts = resp_xdwriteread(SCpnt, lba, num, devip);
547 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 default:
549 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
550 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
551 "supported\n", *cmd);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400552 if ((errsts = check_readiness(SCpnt, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 break; /* Unit attention takes precedence */
554 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
555 errsts = check_condition_result;
556 break;
557 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400558 return schedule_resp(SCpnt, devip, done, errsts,
559 (delay_override ? 0 : scsi_debug_delay));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560}
561
562static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
563{
564 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
565 printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
566 }
567 return -EINVAL;
568 /* return -ENOTTY; // correct return but upsets fdisk */
569}
570
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400571static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
572 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573{
574 if (devip->reset) {
575 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
576 printk(KERN_INFO "scsi_debug: Reporting Unit "
577 "attention: power on reset\n");
578 devip->reset = 0;
579 mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
580 return check_condition_result;
581 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400582 if ((0 == reset_only) && devip->stopped) {
583 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
584 printk(KERN_INFO "scsi_debug: Reporting Not "
585 "ready: initializing command required\n");
586 mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
587 0x2);
588 return check_condition_result;
589 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 return 0;
591}
592
593/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
594static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
595 int arr_len)
596{
597 int k, req_len, act_len, len, active;
598 void * kaddr;
599 void * kaddr_off;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900600 struct scatterlist *sg;
601 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900603 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900605 if (!sdb->table.sgl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 return (DID_ERROR << 16);
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900607 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 return (DID_ERROR << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 active = 1;
Jens Axboe852e0342007-07-16 10:19:24 +0200610 req_len = act_len = 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900611 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, k) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 if (active) {
613 kaddr = (unsigned char *)
Jens Axboe45711f12007-10-22 21:19:53 +0200614 kmap_atomic(sg_page(sg), KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 if (NULL == kaddr)
616 return (DID_ERROR << 16);
Jens Axboe852e0342007-07-16 10:19:24 +0200617 kaddr_off = (unsigned char *)kaddr + sg->offset;
618 len = sg->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 if ((req_len + len) > arr_len) {
620 active = 0;
621 len = arr_len - req_len;
622 }
623 memcpy(kaddr_off, arr + req_len, len);
624 kunmap_atomic(kaddr, KM_USER0);
625 act_len += len;
626 }
Jens Axboe852e0342007-07-16 10:19:24 +0200627 req_len += sg->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 }
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900629 if (sdb->resid)
630 sdb->resid -= act_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400631 else
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900632 sdb->resid = req_len - act_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 return 0;
634}
635
636/* Returns number of bytes fetched into 'arr' or -1 if error. */
637static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
638 int max_arr_len)
639{
640 int k, req_len, len, fin;
641 void * kaddr;
642 void * kaddr_off;
Jens Axboe852e0342007-07-16 10:19:24 +0200643 struct scatterlist * sg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644
Boaz Harroshc73961e2007-09-07 06:50:20 +0900645 if (0 == scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 return 0;
Boaz Harroshc73961e2007-09-07 06:50:20 +0900647 if (NULL == scsi_sglist(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 return -1;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900649 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 return -1;
Jens Axboe852e0342007-07-16 10:19:24 +0200651 req_len = fin = 0;
Boaz Harroshc73961e2007-09-07 06:50:20 +0900652 scsi_for_each_sg(scp, sg, scsi_sg_count(scp), k) {
Jens Axboe45711f12007-10-22 21:19:53 +0200653 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 if (NULL == kaddr)
655 return -1;
Jens Axboe852e0342007-07-16 10:19:24 +0200656 kaddr_off = (unsigned char *)kaddr + sg->offset;
657 len = sg->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 if ((req_len + len) > max_arr_len) {
659 len = max_arr_len - req_len;
660 fin = 1;
661 }
662 memcpy(arr + req_len, kaddr_off, len);
663 kunmap_atomic(kaddr, KM_USER0);
664 if (fin)
665 return req_len + len;
Jens Axboe852e0342007-07-16 10:19:24 +0200666 req_len += sg->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 }
668 return req_len;
669}
670
671
672static const char * inq_vendor_id = "Linux ";
673static const char * inq_product_id = "scsi_debug ";
674static const char * inq_product_rev = "0004";
675
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200676static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
677 int target_dev_id, int dev_id_num,
678 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400679 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400681 int num, port_a;
682 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400684 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 /* T10 vendor identifier field format (faked) */
686 arr[0] = 0x2; /* ASCII */
687 arr[1] = 0x1;
688 arr[2] = 0x0;
689 memcpy(&arr[4], inq_vendor_id, 8);
690 memcpy(&arr[12], inq_product_id, 16);
691 memcpy(&arr[28], dev_id_str, dev_id_str_len);
692 num = 8 + 16 + dev_id_str_len;
693 arr[3] = num;
694 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400695 if (dev_id_num >= 0) {
696 /* NAA-5, Logical unit identifier (binary) */
697 arr[num++] = 0x1; /* binary (not necessarily sas) */
698 arr[num++] = 0x3; /* PIV=0, lu, naa */
699 arr[num++] = 0x0;
700 arr[num++] = 0x8;
701 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
702 arr[num++] = 0x33;
703 arr[num++] = 0x33;
704 arr[num++] = 0x30;
705 arr[num++] = (dev_id_num >> 24);
706 arr[num++] = (dev_id_num >> 16) & 0xff;
707 arr[num++] = (dev_id_num >> 8) & 0xff;
708 arr[num++] = dev_id_num & 0xff;
709 /* Target relative port number */
710 arr[num++] = 0x61; /* proto=sas, binary */
711 arr[num++] = 0x94; /* PIV=1, target port, rel port */
712 arr[num++] = 0x0; /* reserved */
713 arr[num++] = 0x4; /* length */
714 arr[num++] = 0x0; /* reserved */
715 arr[num++] = 0x0; /* reserved */
716 arr[num++] = 0x0;
717 arr[num++] = 0x1; /* relative port A */
718 }
719 /* NAA-5, Target port identifier */
720 arr[num++] = 0x61; /* proto=sas, binary */
721 arr[num++] = 0x93; /* piv=1, target port, naa */
722 arr[num++] = 0x0;
723 arr[num++] = 0x8;
724 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
725 arr[num++] = 0x22;
726 arr[num++] = 0x22;
727 arr[num++] = 0x20;
728 arr[num++] = (port_a >> 24);
729 arr[num++] = (port_a >> 16) & 0xff;
730 arr[num++] = (port_a >> 8) & 0xff;
731 arr[num++] = port_a & 0xff;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200732 /* NAA-5, Target port group identifier */
733 arr[num++] = 0x61; /* proto=sas, binary */
734 arr[num++] = 0x95; /* piv=1, target port group id */
735 arr[num++] = 0x0;
736 arr[num++] = 0x4;
737 arr[num++] = 0;
738 arr[num++] = 0;
739 arr[num++] = (port_group_id >> 8) & 0xff;
740 arr[num++] = port_group_id & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400741 /* NAA-5, Target device identifier */
742 arr[num++] = 0x61; /* proto=sas, binary */
743 arr[num++] = 0xa3; /* piv=1, target device, naa */
744 arr[num++] = 0x0;
745 arr[num++] = 0x8;
746 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
747 arr[num++] = 0x22;
748 arr[num++] = 0x22;
749 arr[num++] = 0x20;
750 arr[num++] = (target_dev_id >> 24);
751 arr[num++] = (target_dev_id >> 16) & 0xff;
752 arr[num++] = (target_dev_id >> 8) & 0xff;
753 arr[num++] = target_dev_id & 0xff;
754 /* SCSI name string: Target device identifier */
755 arr[num++] = 0x63; /* proto=sas, UTF-8 */
756 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
757 arr[num++] = 0x0;
758 arr[num++] = 24;
759 memcpy(arr + num, "naa.52222220", 12);
760 num += 12;
761 snprintf(b, sizeof(b), "%08X", target_dev_id);
762 memcpy(arr + num, b, 8);
763 num += 8;
764 memset(arr + num, 0, 4);
765 num += 4;
766 return num;
767}
768
769
770static unsigned char vpd84_data[] = {
771/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
772 0x22,0x22,0x22,0x0,0xbb,0x1,
773 0x22,0x22,0x22,0x0,0xbb,0x2,
774};
775
776static int inquiry_evpd_84(unsigned char * arr)
777{
778 memcpy(arr, vpd84_data, sizeof(vpd84_data));
779 return sizeof(vpd84_data);
780}
781
782static int inquiry_evpd_85(unsigned char * arr)
783{
784 int num = 0;
785 const char * na1 = "https://www.kernel.org/config";
786 const char * na2 = "http://www.kernel.org/log";
787 int plen, olen;
788
789 arr[num++] = 0x1; /* lu, storage config */
790 arr[num++] = 0x0; /* reserved */
791 arr[num++] = 0x0;
792 olen = strlen(na1);
793 plen = olen + 1;
794 if (plen % 4)
795 plen = ((plen / 4) + 1) * 4;
796 arr[num++] = plen; /* length, null termianted, padded */
797 memcpy(arr + num, na1, olen);
798 memset(arr + num + olen, 0, plen - olen);
799 num += plen;
800
801 arr[num++] = 0x4; /* lu, logging */
802 arr[num++] = 0x0; /* reserved */
803 arr[num++] = 0x0;
804 olen = strlen(na2);
805 plen = olen + 1;
806 if (plen % 4)
807 plen = ((plen / 4) + 1) * 4;
808 arr[num++] = plen; /* length, null terminated, padded */
809 memcpy(arr + num, na2, olen);
810 memset(arr + num + olen, 0, plen - olen);
811 num += plen;
812
813 return num;
814}
815
816/* SCSI ports VPD page */
817static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
818{
819 int num = 0;
820 int port_a, port_b;
821
822 port_a = target_dev_id + 1;
823 port_b = port_a + 1;
824 arr[num++] = 0x0; /* reserved */
825 arr[num++] = 0x0; /* reserved */
826 arr[num++] = 0x0;
827 arr[num++] = 0x1; /* relative port 1 (primary) */
828 memset(arr + num, 0, 6);
829 num += 6;
830 arr[num++] = 0x0;
831 arr[num++] = 12; /* length tp descriptor */
832 /* naa-5 target port identifier (A) */
833 arr[num++] = 0x61; /* proto=sas, binary */
834 arr[num++] = 0x93; /* PIV=1, target port, NAA */
835 arr[num++] = 0x0; /* reserved */
836 arr[num++] = 0x8; /* length */
837 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
838 arr[num++] = 0x22;
839 arr[num++] = 0x22;
840 arr[num++] = 0x20;
841 arr[num++] = (port_a >> 24);
842 arr[num++] = (port_a >> 16) & 0xff;
843 arr[num++] = (port_a >> 8) & 0xff;
844 arr[num++] = port_a & 0xff;
845
846 arr[num++] = 0x0; /* reserved */
847 arr[num++] = 0x0; /* reserved */
848 arr[num++] = 0x0;
849 arr[num++] = 0x2; /* relative port 2 (secondary) */
850 memset(arr + num, 0, 6);
851 num += 6;
852 arr[num++] = 0x0;
853 arr[num++] = 12; /* length tp descriptor */
854 /* naa-5 target port identifier (B) */
855 arr[num++] = 0x61; /* proto=sas, binary */
856 arr[num++] = 0x93; /* PIV=1, target port, NAA */
857 arr[num++] = 0x0; /* reserved */
858 arr[num++] = 0x8; /* length */
859 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
860 arr[num++] = 0x22;
861 arr[num++] = 0x22;
862 arr[num++] = 0x20;
863 arr[num++] = (port_b >> 24);
864 arr[num++] = (port_b >> 16) & 0xff;
865 arr[num++] = (port_b >> 8) & 0xff;
866 arr[num++] = port_b & 0xff;
867
868 return num;
869}
870
871
872static unsigned char vpd89_data[] = {
873/* from 4th byte */ 0,0,0,0,
874'l','i','n','u','x',' ',' ',' ',
875'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
876'1','2','3','4',
8770x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
8780xec,0,0,0,
8790x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
8800,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
8810x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
8820x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
8830x53,0x41,
8840x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
8850x20,0x20,
8860x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
8870x10,0x80,
8880,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
8890x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
8900x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
8910,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
8920x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
8930x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
8940,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
8950,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8960,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8970,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8980x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
8990,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
9000xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
9010,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
9020,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9030,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9040,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9050,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9060,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9070,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9080,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9090,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9120,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9130,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
914};
915
916static int inquiry_evpd_89(unsigned char * arr)
917{
918 memcpy(arr, vpd89_data, sizeof(vpd89_data));
919 return sizeof(vpd89_data);
920}
921
922
923static unsigned char vpdb0_data[] = {
924 /* from 4th byte */ 0,0,0,4,
925 0,0,0x4,0,
926 0,0,0,64,
927};
928
929static int inquiry_evpd_b0(unsigned char * arr)
930{
931 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
932 if (sdebug_store_sectors > 0x400) {
933 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
934 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
935 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
936 arr[7] = sdebug_store_sectors & 0xff;
937 }
938 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939}
940
941
942#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400943#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944
945static int resp_inquiry(struct scsi_cmnd * scp, int target,
946 struct sdebug_dev_info * devip)
947{
948 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200949 unsigned char * arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 unsigned char *cmd = (unsigned char *)scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200951 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
953 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500954 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
955 if (! arr)
956 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400957 if (devip->wlun)
958 pq_pdt = 0x1e; /* present, wlun */
959 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
960 pq_pdt = 0x7f; /* not present, no device type */
961 else
962 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 arr[0] = pq_pdt;
964 if (0x2 & cmd[1]) { /* CMDDT bit set */
965 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
966 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200967 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 return check_condition_result;
969 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200970 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400971 char lu_id_str[6];
972 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200974 port_group_id = (((host_no + 1) & 0x7f) << 8) +
975 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -0400976 if (0 == scsi_debug_vpd_use_hostno)
977 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400978 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
979 (devip->target * 1000) + devip->lun);
980 target_dev_id = ((host_no + 1) * 2000) +
981 (devip->target * 1000) - 3;
982 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400984 arr[1] = cmd[2]; /*sanity */
985 n = 4;
986 arr[n++] = 0x0; /* this page */
987 arr[n++] = 0x80; /* unit serial number */
988 arr[n++] = 0x83; /* device identification */
989 arr[n++] = 0x84; /* software interface ident. */
990 arr[n++] = 0x85; /* management network addresses */
991 arr[n++] = 0x86; /* extended inquiry */
992 arr[n++] = 0x87; /* mode page policy */
993 arr[n++] = 0x88; /* SCSI ports */
994 arr[n++] = 0x89; /* ATA information */
995 arr[n++] = 0xb0; /* Block limits (SBC) */
996 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400998 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001000 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001002 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001003 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
1004 target_dev_id, lu_id_num,
1005 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001006 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1007 arr[1] = cmd[2]; /*sanity */
1008 arr[3] = inquiry_evpd_84(&arr[4]);
1009 } else if (0x85 == cmd[2]) { /* Management network addresses */
1010 arr[1] = cmd[2]; /*sanity */
1011 arr[3] = inquiry_evpd_85(&arr[4]);
1012 } else if (0x86 == cmd[2]) { /* extended inquiry */
1013 arr[1] = cmd[2]; /*sanity */
1014 arr[3] = 0x3c; /* number of following entries */
1015 arr[4] = 0x0; /* no protection stuff */
1016 arr[5] = 0x7; /* head of q, ordered + simple q's */
1017 } else if (0x87 == cmd[2]) { /* mode page policy */
1018 arr[1] = cmd[2]; /*sanity */
1019 arr[3] = 0x8; /* number of following entries */
1020 arr[4] = 0x2; /* disconnect-reconnect mp */
1021 arr[6] = 0x80; /* mlus, shared */
1022 arr[8] = 0x18; /* protocol specific lu */
1023 arr[10] = 0x82; /* mlus, per initiator port */
1024 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1025 arr[1] = cmd[2]; /*sanity */
1026 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
1027 } else if (0x89 == cmd[2]) { /* ATA information */
1028 arr[1] = cmd[2]; /*sanity */
1029 n = inquiry_evpd_89(&arr[4]);
1030 arr[2] = (n >> 8);
1031 arr[3] = (n & 0xff);
1032 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
1033 arr[1] = cmd[2]; /*sanity */
1034 arr[3] = inquiry_evpd_b0(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 } else {
1036 /* Illegal request, invalid field in cdb */
1037 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1038 INVALID_FIELD_IN_CDB, 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001039 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 return check_condition_result;
1041 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001042 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001043 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001044 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001045 kfree(arr);
1046 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 }
1048 /* drops through here for a standard inquiry */
1049 arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
1050 arr[2] = scsi_debug_scsi_level;
1051 arr[3] = 2; /* response_data_format==2 */
1052 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001053 if (0 == scsi_debug_vpd_use_hostno)
1054 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001055 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001057 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 memcpy(&arr[8], inq_vendor_id, 8);
1059 memcpy(&arr[16], inq_product_id, 16);
1060 memcpy(&arr[32], inq_product_rev, 4);
1061 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001062 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
1063 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
1064 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001066 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001068 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001070 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001071 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001073 kfree(arr);
1074 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075}
1076
1077static int resp_requests(struct scsi_cmnd * scp,
1078 struct sdebug_dev_info * devip)
1079{
1080 unsigned char * sbuff;
1081 unsigned char *cmd = (unsigned char *)scp->cmnd;
1082 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001083 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 int len = 18;
1085
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001086 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001088 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
1089 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001091 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1092 if (want_dsense) {
1093 arr[0] = 0x72;
1094 arr[1] = 0x0; /* NO_SENSE in sense_key */
1095 arr[2] = THRESHOLD_EXCEEDED;
1096 arr[3] = 0xff; /* TEST set and MRIE==6 */
1097 } else {
1098 arr[0] = 0x70;
1099 arr[2] = 0x0; /* NO_SENSE in sense_key */
1100 arr[7] = 0xa; /* 18 byte sense buffer */
1101 arr[12] = THRESHOLD_EXCEEDED;
1102 arr[13] = 0xff; /* TEST set and MRIE==6 */
1103 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001104 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001106 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
1107 /* DESC bit set and sense_buff in fixed format */
1108 memset(arr, 0, sizeof(arr));
1109 arr[0] = 0x72;
1110 arr[1] = sbuff[2]; /* sense key */
1111 arr[2] = sbuff[12]; /* asc */
1112 arr[3] = sbuff[13]; /* ascq */
1113 len = 8;
1114 }
1115 }
1116 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 return fill_from_dev_buffer(scp, arr, len);
1118}
1119
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001120static int resp_start_stop(struct scsi_cmnd * scp,
1121 struct sdebug_dev_info * devip)
1122{
1123 unsigned char *cmd = (unsigned char *)scp->cmnd;
1124 int power_cond, errsts, start;
1125
1126 if ((errsts = check_readiness(scp, 1, devip)))
1127 return errsts;
1128 power_cond = (cmd[4] & 0xf0) >> 4;
1129 if (power_cond) {
1130 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1131 0);
1132 return check_condition_result;
1133 }
1134 start = cmd[4] & 1;
1135 if (start == devip->stopped)
1136 devip->stopped = !start;
1137 return 0;
1138}
1139
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140#define SDEBUG_READCAP_ARR_SZ 8
1141static int resp_readcap(struct scsi_cmnd * scp,
1142 struct sdebug_dev_info * devip)
1143{
1144 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001145 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 int errsts;
1147
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001148 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001150 /* following just in case virtual_gb changed */
1151 if (scsi_debug_virtual_gb > 0) {
1152 sdebug_capacity = 2048 * 1024;
1153 sdebug_capacity *= scsi_debug_virtual_gb;
1154 } else
1155 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001157 if (sdebug_capacity < 0xffffffff) {
1158 capac = (unsigned int)sdebug_capacity - 1;
1159 arr[0] = (capac >> 24);
1160 arr[1] = (capac >> 16) & 0xff;
1161 arr[2] = (capac >> 8) & 0xff;
1162 arr[3] = capac & 0xff;
1163 } else {
1164 arr[0] = 0xff;
1165 arr[1] = 0xff;
1166 arr[2] = 0xff;
1167 arr[3] = 0xff;
1168 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1170 arr[7] = SECT_SIZE_PER(target) & 0xff;
1171 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1172}
1173
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001174#define SDEBUG_READCAP16_ARR_SZ 32
1175static int resp_readcap16(struct scsi_cmnd * scp,
1176 struct sdebug_dev_info * devip)
1177{
1178 unsigned char *cmd = (unsigned char *)scp->cmnd;
1179 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1180 unsigned long long capac;
1181 int errsts, k, alloc_len;
1182
1183 if ((errsts = check_readiness(scp, 1, devip)))
1184 return errsts;
1185 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1186 + cmd[13]);
1187 /* following just in case virtual_gb changed */
1188 if (scsi_debug_virtual_gb > 0) {
1189 sdebug_capacity = 2048 * 1024;
1190 sdebug_capacity *= scsi_debug_virtual_gb;
1191 } else
1192 sdebug_capacity = sdebug_store_sectors;
1193 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1194 capac = sdebug_capacity - 1;
1195 for (k = 0; k < 8; ++k, capac >>= 8)
1196 arr[7 - k] = capac & 0xff;
1197 arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff;
1198 arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff;
1199 arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1200 arr[11] = SECT_SIZE_PER(target) & 0xff;
1201 return fill_from_dev_buffer(scp, arr,
1202 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1203}
1204
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001205#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1206
1207static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1208 struct sdebug_dev_info * devip)
1209{
1210 unsigned char *cmd = (unsigned char *)scp->cmnd;
1211 unsigned char * arr;
1212 int host_no = devip->sdbg_host->shost->host_no;
1213 int n, ret, alen, rlen;
1214 int port_group_a, port_group_b, port_a, port_b;
1215
1216 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
1217 + cmd[9]);
1218
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001219 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1220 if (! arr)
1221 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001222 /*
1223 * EVPD page 0x88 states we have two ports, one
1224 * real and a fake port with no device connected.
1225 * So we create two port groups with one port each
1226 * and set the group with port B to unavailable.
1227 */
1228 port_a = 0x1; /* relative port A */
1229 port_b = 0x2; /* relative port B */
1230 port_group_a = (((host_no + 1) & 0x7f) << 8) +
1231 (devip->channel & 0x7f);
1232 port_group_b = (((host_no + 1) & 0x7f) << 8) +
1233 (devip->channel & 0x7f) + 0x80;
1234
1235 /*
1236 * The asymmetric access state is cycled according to the host_id.
1237 */
1238 n = 4;
1239 if (0 == scsi_debug_vpd_use_hostno) {
1240 arr[n++] = host_no % 3; /* Asymm access state */
1241 arr[n++] = 0x0F; /* claim: all states are supported */
1242 } else {
1243 arr[n++] = 0x0; /* Active/Optimized path */
1244 arr[n++] = 0x01; /* claim: only support active/optimized paths */
1245 }
1246 arr[n++] = (port_group_a >> 8) & 0xff;
1247 arr[n++] = port_group_a & 0xff;
1248 arr[n++] = 0; /* Reserved */
1249 arr[n++] = 0; /* Status code */
1250 arr[n++] = 0; /* Vendor unique */
1251 arr[n++] = 0x1; /* One port per group */
1252 arr[n++] = 0; /* Reserved */
1253 arr[n++] = 0; /* Reserved */
1254 arr[n++] = (port_a >> 8) & 0xff;
1255 arr[n++] = port_a & 0xff;
1256 arr[n++] = 3; /* Port unavailable */
1257 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1258 arr[n++] = (port_group_b >> 8) & 0xff;
1259 arr[n++] = port_group_b & 0xff;
1260 arr[n++] = 0; /* Reserved */
1261 arr[n++] = 0; /* Status code */
1262 arr[n++] = 0; /* Vendor unique */
1263 arr[n++] = 0x1; /* One port per group */
1264 arr[n++] = 0; /* Reserved */
1265 arr[n++] = 0; /* Reserved */
1266 arr[n++] = (port_b >> 8) & 0xff;
1267 arr[n++] = port_b & 0xff;
1268
1269 rlen = n - 4;
1270 arr[0] = (rlen >> 24) & 0xff;
1271 arr[1] = (rlen >> 16) & 0xff;
1272 arr[2] = (rlen >> 8) & 0xff;
1273 arr[3] = rlen & 0xff;
1274
1275 /*
1276 * Return the smallest value of either
1277 * - The allocated length
1278 * - The constructed command length
1279 * - The maximum array size
1280 */
1281 rlen = min(alen,n);
1282 ret = fill_from_dev_buffer(scp, arr,
1283 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1284 kfree(arr);
1285 return ret;
1286}
1287
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288/* <<Following mode page info copied from ST318451LW>> */
1289
1290static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1291{ /* Read-Write Error Recovery page for mode_sense */
1292 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1293 5, 0, 0xff, 0xff};
1294
1295 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1296 if (1 == pcontrol)
1297 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1298 return sizeof(err_recov_pg);
1299}
1300
1301static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1302{ /* Disconnect-Reconnect page for mode_sense */
1303 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1304 0, 0, 0, 0, 0, 0, 0, 0};
1305
1306 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1307 if (1 == pcontrol)
1308 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1309 return sizeof(disconnect_pg);
1310}
1311
1312static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1313{ /* Format device page for mode_sense */
1314 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1315 0, 0, 0, 0, 0, 0, 0, 0,
1316 0, 0, 0, 0, 0x40, 0, 0, 0};
1317
1318 memcpy(p, format_pg, sizeof(format_pg));
1319 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1320 p[11] = sdebug_sectors_per & 0xff;
1321 p[12] = (SECT_SIZE >> 8) & 0xff;
1322 p[13] = SECT_SIZE & 0xff;
1323 if (DEV_REMOVEABLE(target))
1324 p[20] |= 0x20; /* should agree with INQUIRY */
1325 if (1 == pcontrol)
1326 memset(p + 2, 0, sizeof(format_pg) - 2);
1327 return sizeof(format_pg);
1328}
1329
1330static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1331{ /* Caching page for mode_sense */
1332 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1333 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1334
1335 memcpy(p, caching_pg, sizeof(caching_pg));
1336 if (1 == pcontrol)
1337 memset(p + 2, 0, sizeof(caching_pg) - 2);
1338 return sizeof(caching_pg);
1339}
1340
1341static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1342{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001343 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1344 0, 0, 0, 0};
1345 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 0, 0, 0x2, 0x4b};
1347
1348 if (scsi_debug_dsense)
1349 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001350 else
1351 ctrl_m_pg[2] &= ~0x4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1353 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001354 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1355 else if (2 == pcontrol)
1356 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 return sizeof(ctrl_m_pg);
1358}
1359
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001360
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1362{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001363 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1364 0, 0, 0x0, 0x0};
1365 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1366 0, 0, 0x0, 0x0};
1367
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1369 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001370 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1371 else if (2 == pcontrol)
1372 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 return sizeof(iec_m_pg);
1374}
1375
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001376static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1377{ /* SAS SSP mode page - short format for mode_sense */
1378 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1379 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1380
1381 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1382 if (1 == pcontrol)
1383 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1384 return sizeof(sas_sf_m_pg);
1385}
1386
1387
1388static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1389 int target_dev_id)
1390{ /* SAS phy control and discover mode page for mode_sense */
1391 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1392 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1393 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1394 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1395 0x2, 0, 0, 0, 0, 0, 0, 0,
1396 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1397 0, 0, 0, 0, 0, 0, 0, 0,
1398 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1399 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1400 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1401 0x3, 0, 0, 0, 0, 0, 0, 0,
1402 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1403 0, 0, 0, 0, 0, 0, 0, 0,
1404 };
1405 int port_a, port_b;
1406
1407 port_a = target_dev_id + 1;
1408 port_b = port_a + 1;
1409 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1410 p[20] = (port_a >> 24);
1411 p[21] = (port_a >> 16) & 0xff;
1412 p[22] = (port_a >> 8) & 0xff;
1413 p[23] = port_a & 0xff;
1414 p[48 + 20] = (port_b >> 24);
1415 p[48 + 21] = (port_b >> 16) & 0xff;
1416 p[48 + 22] = (port_b >> 8) & 0xff;
1417 p[48 + 23] = port_b & 0xff;
1418 if (1 == pcontrol)
1419 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1420 return sizeof(sas_pcd_m_pg);
1421}
1422
1423static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1424{ /* SAS SSP shared protocol specific port mode subpage */
1425 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1426 0, 0, 0, 0, 0, 0, 0, 0,
1427 };
1428
1429 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1430 if (1 == pcontrol)
1431 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1432 return sizeof(sas_sha_m_pg);
1433}
1434
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435#define SDEBUG_MAX_MSENSE_SZ 256
1436
1437static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1438 struct sdebug_dev_info * devip)
1439{
Douglas Gilbert23183912006-09-16 20:30:47 -04001440 unsigned char dbd, llbaa;
1441 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001443 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 unsigned char * ap;
1445 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1446 unsigned char *cmd = (unsigned char *)scp->cmnd;
1447
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001448 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001450 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 pcontrol = (cmd[2] & 0xc0) >> 6;
1452 pcode = cmd[2] & 0x3f;
1453 subpcode = cmd[3];
1454 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001455 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1456 if ((0 == scsi_debug_ptype) && (0 == dbd))
1457 bd_len = llbaa ? 16 : 8;
1458 else
1459 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1461 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1462 if (0x3 == pcontrol) { /* Saving values not supported */
1463 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1464 0);
1465 return check_condition_result;
1466 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001467 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1468 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001469 /* set DPOFUA bit for disks */
1470 if (0 == scsi_debug_ptype)
1471 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1472 else
1473 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 if (msense_6) {
1475 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001476 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 offset = 4;
1478 } else {
1479 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001480 if (16 == bd_len)
1481 arr[4] = 0x1; /* set LONGLBA bit */
1482 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 offset = 8;
1484 }
1485 ap = arr + offset;
Douglas Gilbert23183912006-09-16 20:30:47 -04001486 if ((bd_len > 0) && (0 == sdebug_capacity)) {
1487 if (scsi_debug_virtual_gb > 0) {
1488 sdebug_capacity = 2048 * 1024;
1489 sdebug_capacity *= scsi_debug_virtual_gb;
1490 } else
1491 sdebug_capacity = sdebug_store_sectors;
1492 }
1493 if (8 == bd_len) {
1494 if (sdebug_capacity > 0xfffffffe) {
1495 ap[0] = 0xff;
1496 ap[1] = 0xff;
1497 ap[2] = 0xff;
1498 ap[3] = 0xff;
1499 } else {
1500 ap[0] = (sdebug_capacity >> 24) & 0xff;
1501 ap[1] = (sdebug_capacity >> 16) & 0xff;
1502 ap[2] = (sdebug_capacity >> 8) & 0xff;
1503 ap[3] = sdebug_capacity & 0xff;
1504 }
1505 ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1506 ap[7] = SECT_SIZE_PER(target) & 0xff;
1507 offset += bd_len;
1508 ap = arr + offset;
1509 } else if (16 == bd_len) {
1510 unsigned long long capac = sdebug_capacity;
1511
1512 for (k = 0; k < 8; ++k, capac >>= 8)
1513 ap[7 - k] = capac & 0xff;
1514 ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff;
1515 ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff;
1516 ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1517 ap[15] = SECT_SIZE_PER(target) & 0xff;
1518 offset += bd_len;
1519 ap = arr + offset;
1520 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001522 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1523 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1525 0);
1526 return check_condition_result;
1527 }
1528 switch (pcode) {
1529 case 0x1: /* Read-Write error recovery page, direct access */
1530 len = resp_err_recov_pg(ap, pcontrol, target);
1531 offset += len;
1532 break;
1533 case 0x2: /* Disconnect-Reconnect page, all devices */
1534 len = resp_disconnect_pg(ap, pcontrol, target);
1535 offset += len;
1536 break;
1537 case 0x3: /* Format device page, direct access */
1538 len = resp_format_pg(ap, pcontrol, target);
1539 offset += len;
1540 break;
1541 case 0x8: /* Caching page, direct access */
1542 len = resp_caching_pg(ap, pcontrol, target);
1543 offset += len;
1544 break;
1545 case 0xa: /* Control Mode page, all devices */
1546 len = resp_ctrl_m_pg(ap, pcontrol, target);
1547 offset += len;
1548 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001549 case 0x19: /* if spc==1 then sas phy, control+discover */
1550 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1551 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1552 INVALID_FIELD_IN_CDB, 0);
1553 return check_condition_result;
1554 }
1555 len = 0;
1556 if ((0x0 == subpcode) || (0xff == subpcode))
1557 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1558 if ((0x1 == subpcode) || (0xff == subpcode))
1559 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1560 target_dev_id);
1561 if ((0x2 == subpcode) || (0xff == subpcode))
1562 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1563 offset += len;
1564 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 case 0x1c: /* Informational Exceptions Mode page, all devices */
1566 len = resp_iec_m_pg(ap, pcontrol, target);
1567 offset += len;
1568 break;
1569 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001570 if ((0 == subpcode) || (0xff == subpcode)) {
1571 len = resp_err_recov_pg(ap, pcontrol, target);
1572 len += resp_disconnect_pg(ap + len, pcontrol, target);
1573 len += resp_format_pg(ap + len, pcontrol, target);
1574 len += resp_caching_pg(ap + len, pcontrol, target);
1575 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1576 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1577 if (0xff == subpcode) {
1578 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1579 target, target_dev_id);
1580 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1581 }
1582 len += resp_iec_m_pg(ap + len, pcontrol, target);
1583 } else {
1584 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1585 INVALID_FIELD_IN_CDB, 0);
1586 return check_condition_result;
1587 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 offset += len;
1589 break;
1590 default:
1591 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1592 0);
1593 return check_condition_result;
1594 }
1595 if (msense_6)
1596 arr[0] = offset - 1;
1597 else {
1598 arr[0] = ((offset - 2) >> 8) & 0xff;
1599 arr[1] = (offset - 2) & 0xff;
1600 }
1601 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1602}
1603
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001604#define SDEBUG_MAX_MSELECT_SZ 512
1605
1606static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1607 struct sdebug_dev_info * devip)
1608{
1609 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1610 int param_len, res, errsts, mpage;
1611 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1612 unsigned char *cmd = (unsigned char *)scp->cmnd;
1613
1614 if ((errsts = check_readiness(scp, 1, devip)))
1615 return errsts;
1616 memset(arr, 0, sizeof(arr));
1617 pf = cmd[1] & 0x10;
1618 sp = cmd[1] & 0x1;
1619 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1620 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1621 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1622 INVALID_FIELD_IN_CDB, 0);
1623 return check_condition_result;
1624 }
1625 res = fetch_to_dev_buffer(scp, arr, param_len);
1626 if (-1 == res)
1627 return (DID_ERROR << 16);
1628 else if ((res < param_len) &&
1629 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1630 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1631 " IO sent=%d bytes\n", param_len, res);
1632 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1633 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001634 if (md_len > 2) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001635 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1636 INVALID_FIELD_IN_PARAM_LIST, 0);
1637 return check_condition_result;
1638 }
1639 off = bd_len + (mselect6 ? 4 : 8);
1640 mpage = arr[off] & 0x3f;
1641 ps = !!(arr[off] & 0x80);
1642 if (ps) {
1643 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1644 INVALID_FIELD_IN_PARAM_LIST, 0);
1645 return check_condition_result;
1646 }
1647 spf = !!(arr[off] & 0x40);
1648 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1649 (arr[off + 1] + 2);
1650 if ((pg_len + off) > param_len) {
1651 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1652 PARAMETER_LIST_LENGTH_ERR, 0);
1653 return check_condition_result;
1654 }
1655 switch (mpage) {
1656 case 0xa: /* Control Mode page */
1657 if (ctrl_m_pg[1] == arr[off + 1]) {
1658 memcpy(ctrl_m_pg + 2, arr + off + 2,
1659 sizeof(ctrl_m_pg) - 2);
1660 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1661 return 0;
1662 }
1663 break;
1664 case 0x1c: /* Informational Exceptions Mode page */
1665 if (iec_m_pg[1] == arr[off + 1]) {
1666 memcpy(iec_m_pg + 2, arr + off + 2,
1667 sizeof(iec_m_pg) - 2);
1668 return 0;
1669 }
1670 break;
1671 default:
1672 break;
1673 }
1674 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1675 INVALID_FIELD_IN_PARAM_LIST, 0);
1676 return check_condition_result;
1677}
1678
1679static int resp_temp_l_pg(unsigned char * arr)
1680{
1681 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1682 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1683 };
1684
1685 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1686 return sizeof(temp_l_pg);
1687}
1688
1689static int resp_ie_l_pg(unsigned char * arr)
1690{
1691 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1692 };
1693
1694 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1695 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1696 arr[4] = THRESHOLD_EXCEEDED;
1697 arr[5] = 0xff;
1698 }
1699 return sizeof(ie_l_pg);
1700}
1701
1702#define SDEBUG_MAX_LSENSE_SZ 512
1703
1704static int resp_log_sense(struct scsi_cmnd * scp,
1705 struct sdebug_dev_info * devip)
1706{
Douglas Gilbert23183912006-09-16 20:30:47 -04001707 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001708 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1709 unsigned char *cmd = (unsigned char *)scp->cmnd;
1710
1711 if ((errsts = check_readiness(scp, 1, devip)))
1712 return errsts;
1713 memset(arr, 0, sizeof(arr));
1714 ppc = cmd[1] & 0x2;
1715 sp = cmd[1] & 0x1;
1716 if (ppc || sp) {
1717 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1718 INVALID_FIELD_IN_CDB, 0);
1719 return check_condition_result;
1720 }
1721 pcontrol = (cmd[2] & 0xc0) >> 6;
1722 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001723 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001724 alloc_len = (cmd[7] << 8) + cmd[8];
1725 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001726 if (0 == subpcode) {
1727 switch (pcode) {
1728 case 0x0: /* Supported log pages log page */
1729 n = 4;
1730 arr[n++] = 0x0; /* this page */
1731 arr[n++] = 0xd; /* Temperature */
1732 arr[n++] = 0x2f; /* Informational exceptions */
1733 arr[3] = n - 4;
1734 break;
1735 case 0xd: /* Temperature log page */
1736 arr[3] = resp_temp_l_pg(arr + 4);
1737 break;
1738 case 0x2f: /* Informational exceptions log page */
1739 arr[3] = resp_ie_l_pg(arr + 4);
1740 break;
1741 default:
1742 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1743 INVALID_FIELD_IN_CDB, 0);
1744 return check_condition_result;
1745 }
1746 } else if (0xff == subpcode) {
1747 arr[0] |= 0x40;
1748 arr[1] = subpcode;
1749 switch (pcode) {
1750 case 0x0: /* Supported log pages and subpages log page */
1751 n = 4;
1752 arr[n++] = 0x0;
1753 arr[n++] = 0x0; /* 0,0 page */
1754 arr[n++] = 0x0;
1755 arr[n++] = 0xff; /* this page */
1756 arr[n++] = 0xd;
1757 arr[n++] = 0x0; /* Temperature */
1758 arr[n++] = 0x2f;
1759 arr[n++] = 0x0; /* Informational exceptions */
1760 arr[3] = n - 4;
1761 break;
1762 case 0xd: /* Temperature subpages */
1763 n = 4;
1764 arr[n++] = 0xd;
1765 arr[n++] = 0x0; /* Temperature */
1766 arr[3] = n - 4;
1767 break;
1768 case 0x2f: /* Informational exceptions subpages */
1769 n = 4;
1770 arr[n++] = 0x2f;
1771 arr[n++] = 0x0; /* Informational exceptions */
1772 arr[3] = n - 4;
1773 break;
1774 default:
1775 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1776 INVALID_FIELD_IN_CDB, 0);
1777 return check_condition_result;
1778 }
1779 } else {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001780 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1781 INVALID_FIELD_IN_CDB, 0);
1782 return check_condition_result;
1783 }
1784 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1785 return fill_from_dev_buffer(scp, arr,
1786 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1787}
1788
1789static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
1790 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791{
1792 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001793 unsigned int block, from_bottom;
1794 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 int ret;
1796
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001797 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1799 0);
1800 return check_condition_result;
1801 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001802 /* transfer length excessive (tie in to block limits VPD page) */
1803 if (num > sdebug_store_sectors) {
1804 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1805 0);
1806 return check_condition_result;
1807 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001809 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1810 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1811 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1813 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001814 /* set info field and valid bit for fixed descriptor */
1815 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1816 devip->sense_buff[0] |= 0x80; /* Valid bit */
1817 ret = OPT_MEDIUM_ERR_ADDR;
1818 devip->sense_buff[3] = (ret >> 24) & 0xff;
1819 devip->sense_buff[4] = (ret >> 16) & 0xff;
1820 devip->sense_buff[5] = (ret >> 8) & 0xff;
1821 devip->sense_buff[6] = ret & 0xff;
1822 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 return check_condition_result;
1824 }
1825 read_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001826 if ((lba + num) <= sdebug_store_sectors)
1827 ret = fill_from_dev_buffer(SCpnt,
1828 fake_storep + (lba * SECT_SIZE),
1829 num * SECT_SIZE);
1830 else {
1831 /* modulo when one arg is 64 bits needs do_div() */
1832 u = lba;
1833 block = do_div(u, sdebug_store_sectors);
1834 from_bottom = 0;
1835 if ((block + num) > sdebug_store_sectors)
1836 from_bottom = (block + num) - sdebug_store_sectors;
1837 ret = fill_from_dev_buffer(SCpnt,
1838 fake_storep + (block * SECT_SIZE),
1839 (num - from_bottom) * SECT_SIZE);
1840 if ((0 == ret) && (from_bottom > 0))
1841 ret = fill_from_dev_buffer(SCpnt, fake_storep,
1842 from_bottom * SECT_SIZE);
1843 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 read_unlock_irqrestore(&atomic_rw, iflags);
1845 return ret;
1846}
1847
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001848static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
1849 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850{
1851 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001852 unsigned int block, to_bottom;
1853 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 int res;
1855
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001856 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1858 0);
1859 return check_condition_result;
1860 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001861 /* transfer length excessive (tie in to block limits VPD page) */
1862 if (num > sdebug_store_sectors) {
1863 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1864 0);
1865 return check_condition_result;
1866 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867
1868 write_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001869 if ((lba + num) <= sdebug_store_sectors)
1870 res = fetch_to_dev_buffer(SCpnt,
1871 fake_storep + (lba * SECT_SIZE),
1872 num * SECT_SIZE);
1873 else {
1874 /* modulo when one arg is 64 bits needs do_div() */
1875 u = lba;
1876 block = do_div(u, sdebug_store_sectors);
1877 to_bottom = 0;
1878 if ((block + num) > sdebug_store_sectors)
1879 to_bottom = (block + num) - sdebug_store_sectors;
1880 res = fetch_to_dev_buffer(SCpnt,
1881 fake_storep + (block * SECT_SIZE),
1882 (num - to_bottom) * SECT_SIZE);
1883 if ((0 == res) && (to_bottom > 0))
1884 res = fetch_to_dev_buffer(SCpnt, fake_storep,
1885 to_bottom * SECT_SIZE);
1886 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 write_unlock_irqrestore(&atomic_rw, iflags);
1888 if (-1 == res)
1889 return (DID_ERROR << 16);
1890 else if ((res < (num * SECT_SIZE)) &&
1891 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001892 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 " IO sent=%d bytes\n", num * SECT_SIZE, res);
1894 return 0;
1895}
1896
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001897#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898
1899static int resp_report_luns(struct scsi_cmnd * scp,
1900 struct sdebug_dev_info * devip)
1901{
1902 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001903 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 unsigned char *cmd = (unsigned char *)scp->cmnd;
1905 int select_report = (int)cmd[2];
1906 struct scsi_lun *one_lun;
1907 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001908 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909
1910 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001911 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1913 0);
1914 return check_condition_result;
1915 }
1916 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
1917 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
1918 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001919 if (1 == select_report)
1920 lun_cnt = 0;
1921 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
1922 --lun_cnt;
1923 wlun = (select_report > 0) ? 1 : 0;
1924 num = lun_cnt + wlun;
1925 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
1926 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
1927 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
1928 sizeof(struct scsi_lun)), num);
1929 if (n < num) {
1930 wlun = 0;
1931 lun_cnt = n;
1932 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001934 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
1935 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
1936 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
1937 i++, lun++) {
1938 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 if (upper)
1940 one_lun[i].scsi_lun[0] =
1941 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001942 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001944 if (wlun) {
1945 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
1946 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
1947 i++;
1948 }
1949 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 return fill_from_dev_buffer(scp, arr,
1951 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
1952}
1953
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001954static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
1955 unsigned int num, struct sdebug_dev_info *devip)
1956{
1957 int i, j, ret = -1;
1958 unsigned char *kaddr, *buf;
1959 unsigned int offset;
1960 struct scatterlist *sg;
1961 struct scsi_data_buffer *sdb = scsi_in(scp);
1962
1963 /* better not to use temporary buffer. */
1964 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
1965 if (!buf)
1966 return ret;
1967
1968 offset = 0;
1969 scsi_for_each_sg(scp, sg, scsi_sg_count(scp), i) {
1970 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
1971 if (!kaddr)
1972 goto out;
1973
1974 memcpy(buf + offset, kaddr + sg->offset, sg->length);
1975 offset += sg->length;
1976 kunmap_atomic(kaddr, KM_USER0);
1977 }
1978
1979 offset = 0;
1980 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
1981 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
1982 if (!kaddr)
1983 goto out;
1984
1985 for (j = 0; j < sg->length; j++)
1986 *(kaddr + sg->offset + j) ^= *(buf + offset + j);
1987
1988 offset += sg->length;
1989 kunmap_atomic(kaddr, KM_USER0);
1990 }
1991 ret = 0;
1992out:
1993 kfree(buf);
1994
1995 return ret;
1996}
1997
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998/* When timer goes off this function is called. */
1999static void timer_intr_handler(unsigned long indx)
2000{
2001 struct sdebug_queued_cmd * sqcp;
2002 unsigned long iflags;
2003
2004 if (indx >= SCSI_DEBUG_CANQUEUE) {
2005 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
2006 "large\n");
2007 return;
2008 }
2009 spin_lock_irqsave(&queued_arr_lock, iflags);
2010 sqcp = &queued_arr[(int)indx];
2011 if (! sqcp->in_use) {
2012 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
2013 "interrupt\n");
2014 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2015 return;
2016 }
2017 sqcp->in_use = 0;
2018 if (sqcp->done_funct) {
2019 sqcp->a_cmnd->result = sqcp->scsi_result;
2020 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
2021 }
2022 sqcp->done_funct = NULL;
2023 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2024}
2025
2026static int scsi_debug_slave_alloc(struct scsi_device * sdp)
2027{
2028 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002029 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
2030 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002031 set_bit(QUEUE_FLAG_BIDI, &sdp->request_queue->queue_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 return 0;
2033}
2034
2035static int scsi_debug_slave_configure(struct scsi_device * sdp)
2036{
2037 struct sdebug_dev_info * devip;
2038
2039 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002040 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
2041 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
2043 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
2044 devip = devInfoReg(sdp);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002045 if (NULL == devip)
2046 return 1; /* no resources, will be marked offline */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 sdp->hostdata = devip;
2048 if (sdp->host->cmd_per_lun)
2049 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
2050 sdp->host->cmd_per_lun);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002051 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 return 0;
2053}
2054
2055static void scsi_debug_slave_destroy(struct scsi_device * sdp)
2056{
2057 struct sdebug_dev_info * devip =
2058 (struct sdebug_dev_info *)sdp->hostdata;
2059
2060 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002061 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
2062 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 if (devip) {
2064 /* make this slot avaliable for re-use */
2065 devip->used = 0;
2066 sdp->hostdata = NULL;
2067 }
2068}
2069
2070static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
2071{
2072 struct sdebug_host_info * sdbg_host;
2073 struct sdebug_dev_info * open_devip = NULL;
2074 struct sdebug_dev_info * devip =
2075 (struct sdebug_dev_info *)sdev->hostdata;
2076
2077 if (devip)
2078 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002079 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
2080 if (!sdbg_host) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 printk(KERN_ERR "Host info NULL\n");
2082 return NULL;
2083 }
2084 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
2085 if ((devip->used) && (devip->channel == sdev->channel) &&
2086 (devip->target == sdev->id) &&
2087 (devip->lun == sdev->lun))
2088 return devip;
2089 else {
2090 if ((!devip->used) && (!open_devip))
2091 open_devip = devip;
2092 }
2093 }
2094 if (NULL == open_devip) { /* try and make a new one */
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002095 open_devip = kzalloc(sizeof(*open_devip),GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 if (NULL == open_devip) {
2097 printk(KERN_ERR "%s: out of memory at line %d\n",
2098 __FUNCTION__, __LINE__);
2099 return NULL;
2100 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 open_devip->sdbg_host = sdbg_host;
2102 list_add_tail(&open_devip->dev_list,
2103 &sdbg_host->dev_info_list);
2104 }
2105 if (open_devip) {
2106 open_devip->channel = sdev->channel;
2107 open_devip->target = sdev->id;
2108 open_devip->lun = sdev->lun;
2109 open_devip->sdbg_host = sdbg_host;
2110 open_devip->reset = 1;
2111 open_devip->used = 1;
2112 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
2113 if (scsi_debug_dsense)
2114 open_devip->sense_buff[0] = 0x72;
2115 else {
2116 open_devip->sense_buff[0] = 0x70;
2117 open_devip->sense_buff[7] = 0xa;
2118 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002119 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2120 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 return open_devip;
2122 }
2123 return NULL;
2124}
2125
2126static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
2127 int asc, int asq)
2128{
2129 unsigned char * sbuff;
2130
2131 sbuff = devip->sense_buff;
2132 memset(sbuff, 0, SDEBUG_SENSE_LEN);
2133 if (scsi_debug_dsense) {
2134 sbuff[0] = 0x72; /* descriptor, current */
2135 sbuff[1] = key;
2136 sbuff[2] = asc;
2137 sbuff[3] = asq;
2138 } else {
2139 sbuff[0] = 0x70; /* fixed, current */
2140 sbuff[2] = key;
2141 sbuff[7] = 0xa; /* implies 18 byte sense buffer */
2142 sbuff[12] = asc;
2143 sbuff[13] = asq;
2144 }
2145 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2146 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
2147 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
2148}
2149
2150static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
2151{
2152 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2153 printk(KERN_INFO "scsi_debug: abort\n");
2154 ++num_aborts;
2155 stop_queued_cmnd(SCpnt);
2156 return SUCCESS;
2157}
2158
2159static int scsi_debug_biosparam(struct scsi_device *sdev,
2160 struct block_device * bdev, sector_t capacity, int *info)
2161{
2162 int res;
2163 unsigned char *buf;
2164
2165 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2166 printk(KERN_INFO "scsi_debug: biosparam\n");
2167 buf = scsi_bios_ptable(bdev);
2168 if (buf) {
2169 res = scsi_partsize(buf, capacity,
2170 &info[2], &info[0], &info[1]);
2171 kfree(buf);
2172 if (! res)
2173 return res;
2174 }
2175 info[0] = sdebug_heads;
2176 info[1] = sdebug_sectors_per;
2177 info[2] = sdebug_cylinders_per;
2178 return 0;
2179}
2180
2181static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
2182{
2183 struct sdebug_dev_info * devip;
2184
2185 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2186 printk(KERN_INFO "scsi_debug: device_reset\n");
2187 ++num_dev_resets;
2188 if (SCpnt) {
2189 devip = devInfoReg(SCpnt->device);
2190 if (devip)
2191 devip->reset = 1;
2192 }
2193 return SUCCESS;
2194}
2195
2196static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
2197{
2198 struct sdebug_host_info *sdbg_host;
2199 struct sdebug_dev_info * dev_info;
2200 struct scsi_device * sdp;
2201 struct Scsi_Host * hp;
2202
2203 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2204 printk(KERN_INFO "scsi_debug: bus_reset\n");
2205 ++num_bus_resets;
2206 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002207 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208 if (sdbg_host) {
2209 list_for_each_entry(dev_info,
2210 &sdbg_host->dev_info_list,
2211 dev_list)
2212 dev_info->reset = 1;
2213 }
2214 }
2215 return SUCCESS;
2216}
2217
2218static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
2219{
2220 struct sdebug_host_info * sdbg_host;
2221 struct sdebug_dev_info * dev_info;
2222
2223 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2224 printk(KERN_INFO "scsi_debug: host_reset\n");
2225 ++num_host_resets;
2226 spin_lock(&sdebug_host_list_lock);
2227 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
2228 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
2229 dev_list)
2230 dev_info->reset = 1;
2231 }
2232 spin_unlock(&sdebug_host_list_lock);
2233 stop_all_queued();
2234 return SUCCESS;
2235}
2236
2237/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
2238static int stop_queued_cmnd(struct scsi_cmnd * cmnd)
2239{
2240 unsigned long iflags;
2241 int k;
2242 struct sdebug_queued_cmd * sqcp;
2243
2244 spin_lock_irqsave(&queued_arr_lock, iflags);
2245 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2246 sqcp = &queued_arr[k];
2247 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
2248 del_timer_sync(&sqcp->cmnd_timer);
2249 sqcp->in_use = 0;
2250 sqcp->a_cmnd = NULL;
2251 break;
2252 }
2253 }
2254 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2255 return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
2256}
2257
2258/* Deletes (stops) timers of all queued commands */
2259static void stop_all_queued(void)
2260{
2261 unsigned long iflags;
2262 int k;
2263 struct sdebug_queued_cmd * sqcp;
2264
2265 spin_lock_irqsave(&queued_arr_lock, iflags);
2266 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2267 sqcp = &queued_arr[k];
2268 if (sqcp->in_use && sqcp->a_cmnd) {
2269 del_timer_sync(&sqcp->cmnd_timer);
2270 sqcp->in_use = 0;
2271 sqcp->a_cmnd = NULL;
2272 }
2273 }
2274 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2275}
2276
2277/* Initializes timers in queued array */
2278static void __init init_all_queued(void)
2279{
2280 unsigned long iflags;
2281 int k;
2282 struct sdebug_queued_cmd * sqcp;
2283
2284 spin_lock_irqsave(&queued_arr_lock, iflags);
2285 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2286 sqcp = &queued_arr[k];
2287 init_timer(&sqcp->cmnd_timer);
2288 sqcp->in_use = 0;
2289 sqcp->a_cmnd = NULL;
2290 }
2291 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2292}
2293
2294static void __init sdebug_build_parts(unsigned char * ramp)
2295{
2296 struct partition * pp;
2297 int starts[SDEBUG_MAX_PARTS + 2];
2298 int sectors_per_part, num_sectors, k;
2299 int heads_by_sects, start_sec, end_sec;
2300
2301 /* assume partition table already zeroed */
2302 if ((scsi_debug_num_parts < 1) || (sdebug_store_size < 1048576))
2303 return;
2304 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
2305 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
2306 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
2307 "partitions to %d\n", SDEBUG_MAX_PARTS);
2308 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002309 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 sectors_per_part = (num_sectors - sdebug_sectors_per)
2311 / scsi_debug_num_parts;
2312 heads_by_sects = sdebug_heads * sdebug_sectors_per;
2313 starts[0] = sdebug_sectors_per;
2314 for (k = 1; k < scsi_debug_num_parts; ++k)
2315 starts[k] = ((k * sectors_per_part) / heads_by_sects)
2316 * heads_by_sects;
2317 starts[scsi_debug_num_parts] = num_sectors;
2318 starts[scsi_debug_num_parts + 1] = 0;
2319
2320 ramp[510] = 0x55; /* magic partition markings */
2321 ramp[511] = 0xAA;
2322 pp = (struct partition *)(ramp + 0x1be);
2323 for (k = 0; starts[k + 1]; ++k, ++pp) {
2324 start_sec = starts[k];
2325 end_sec = starts[k + 1] - 1;
2326 pp->boot_ind = 0;
2327
2328 pp->cyl = start_sec / heads_by_sects;
2329 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2330 / sdebug_sectors_per;
2331 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2332
2333 pp->end_cyl = end_sec / heads_by_sects;
2334 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2335 / sdebug_sectors_per;
2336 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2337
2338 pp->start_sect = start_sec;
2339 pp->nr_sects = end_sec - start_sec + 1;
2340 pp->sys_ind = 0x83; /* plain Linux partition */
2341 }
2342}
2343
2344static int schedule_resp(struct scsi_cmnd * cmnd,
2345 struct sdebug_dev_info * devip,
2346 done_funct_t done, int scsi_result, int delta_jiff)
2347{
2348 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2349 if (scsi_result) {
2350 struct scsi_device * sdp = cmnd->device;
2351
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002352 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2353 "non-zero result=0x%x\n", sdp->host->host_no,
2354 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 }
2356 }
2357 if (cmnd && devip) {
2358 /* simulate autosense by this driver */
2359 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2360 memcpy(cmnd->sense_buffer, devip->sense_buff,
2361 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2362 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2363 }
2364 if (delta_jiff <= 0) {
2365 if (cmnd)
2366 cmnd->result = scsi_result;
2367 if (done)
2368 done(cmnd);
2369 return 0;
2370 } else {
2371 unsigned long iflags;
2372 int k;
2373 struct sdebug_queued_cmd * sqcp = NULL;
2374
2375 spin_lock_irqsave(&queued_arr_lock, iflags);
2376 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2377 sqcp = &queued_arr[k];
2378 if (! sqcp->in_use)
2379 break;
2380 }
2381 if (k >= SCSI_DEBUG_CANQUEUE) {
2382 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2383 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2384 return 1; /* report busy to mid level */
2385 }
2386 sqcp->in_use = 1;
2387 sqcp->a_cmnd = cmnd;
2388 sqcp->scsi_result = scsi_result;
2389 sqcp->done_funct = done;
2390 sqcp->cmnd_timer.function = timer_intr_handler;
2391 sqcp->cmnd_timer.data = k;
2392 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2393 add_timer(&sqcp->cmnd_timer);
2394 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2395 if (cmnd)
2396 cmnd->result = 0;
2397 return 0;
2398 }
2399}
2400
Douglas Gilbert23183912006-09-16 20:30:47 -04002401/* Note: The following macros create attribute files in the
2402 /sys/module/scsi_debug/parameters directory. Unfortunately this
2403 driver is unaware of a change and cannot trigger auxiliary actions
2404 as it can when the corresponding attribute in the
2405 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2406 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002407module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2408module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2409module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2410module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2411module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002412module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002413module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2414module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2415module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2416module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2417module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2418module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2419module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2420module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002421module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2422 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423
2424MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2425MODULE_DESCRIPTION("SCSI debug adapter driver");
2426MODULE_LICENSE("GPL");
2427MODULE_VERSION(SCSI_DEBUG_VERSION);
2428
2429MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2430MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002431MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2432MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07002433MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002434MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002435MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2436MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002438MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002439MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2441MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002442MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002443MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444
2445
2446static char sdebug_info[256];
2447
2448static const char * scsi_debug_info(struct Scsi_Host * shp)
2449{
2450 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2451 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2452 scsi_debug_version_date, scsi_debug_dev_size_mb,
2453 scsi_debug_opts);
2454 return sdebug_info;
2455}
2456
2457/* scsi_debug_proc_info
2458 * Used if the driver currently has no own support for /proc/scsi
2459 */
2460static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2461 int length, int inout)
2462{
2463 int len, pos, begin;
2464 int orig_length;
2465
2466 orig_length = length;
2467
2468 if (inout == 1) {
2469 char arr[16];
2470 int minLen = length > 15 ? 15 : length;
2471
2472 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2473 return -EACCES;
2474 memcpy(arr, buffer, minLen);
2475 arr[minLen] = '\0';
2476 if (1 != sscanf(arr, "%d", &pos))
2477 return -EINVAL;
2478 scsi_debug_opts = pos;
2479 if (scsi_debug_every_nth != 0)
2480 scsi_debug_cmnd_count = 0;
2481 return length;
2482 }
2483 begin = 0;
2484 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2485 "%s [%s]\n"
2486 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2487 "every_nth=%d(curr:%d)\n"
2488 "delay=%d, max_luns=%d, scsi_level=%d\n"
2489 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2490 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
2491 "host_resets=%d\n",
2492 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2493 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2494 scsi_debug_cmnd_count, scsi_debug_delay,
2495 scsi_debug_max_luns, scsi_debug_scsi_level,
2496 SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
2497 num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
2498 if (pos < offset) {
2499 len = 0;
2500 begin = pos;
2501 }
2502 *start = buffer + (offset - begin); /* Start of wanted data */
2503 len -= (offset - begin);
2504 if (len > length)
2505 len = length;
2506 return len;
2507}
2508
2509static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2510{
2511 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2512}
2513
2514static ssize_t sdebug_delay_store(struct device_driver * ddp,
2515 const char * buf, size_t count)
2516{
2517 int delay;
2518 char work[20];
2519
2520 if (1 == sscanf(buf, "%10s", work)) {
2521 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2522 scsi_debug_delay = delay;
2523 return count;
2524 }
2525 }
2526 return -EINVAL;
2527}
2528DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2529 sdebug_delay_store);
2530
2531static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2532{
2533 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2534}
2535
2536static ssize_t sdebug_opts_store(struct device_driver * ddp,
2537 const char * buf, size_t count)
2538{
2539 int opts;
2540 char work[20];
2541
2542 if (1 == sscanf(buf, "%10s", work)) {
2543 if (0 == strnicmp(work,"0x", 2)) {
2544 if (1 == sscanf(&work[2], "%x", &opts))
2545 goto opts_done;
2546 } else {
2547 if (1 == sscanf(work, "%d", &opts))
2548 goto opts_done;
2549 }
2550 }
2551 return -EINVAL;
2552opts_done:
2553 scsi_debug_opts = opts;
2554 scsi_debug_cmnd_count = 0;
2555 return count;
2556}
2557DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2558 sdebug_opts_store);
2559
2560static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2561{
2562 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2563}
2564static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2565 const char * buf, size_t count)
2566{
2567 int n;
2568
2569 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2570 scsi_debug_ptype = n;
2571 return count;
2572 }
2573 return -EINVAL;
2574}
2575DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2576
2577static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2578{
2579 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2580}
2581static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2582 const char * buf, size_t count)
2583{
2584 int n;
2585
2586 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2587 scsi_debug_dsense = n;
2588 return count;
2589 }
2590 return -EINVAL;
2591}
2592DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2593 sdebug_dsense_store);
2594
Douglas Gilbert23183912006-09-16 20:30:47 -04002595static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2596{
2597 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2598}
2599static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2600 const char * buf, size_t count)
2601{
2602 int n;
2603
2604 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2605 scsi_debug_fake_rw = n;
2606 return count;
2607 }
2608 return -EINVAL;
2609}
2610DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2611 sdebug_fake_rw_store);
2612
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002613static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2614{
2615 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2616}
2617static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2618 const char * buf, size_t count)
2619{
2620 int n;
2621
2622 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2623 scsi_debug_no_lun_0 = n;
2624 return count;
2625 }
2626 return -EINVAL;
2627}
2628DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2629 sdebug_no_lun_0_store);
2630
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2632{
2633 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2634}
2635static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2636 const char * buf, size_t count)
2637{
2638 int n;
2639
2640 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2641 scsi_debug_num_tgts = n;
2642 sdebug_max_tgts_luns();
2643 return count;
2644 }
2645 return -EINVAL;
2646}
2647DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2648 sdebug_num_tgts_store);
2649
2650static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2651{
2652 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2653}
2654DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2655
2656static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2657{
2658 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2659}
2660DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2661
2662static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2663{
2664 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2665}
2666static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2667 const char * buf, size_t count)
2668{
2669 int nth;
2670
2671 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2672 scsi_debug_every_nth = nth;
2673 scsi_debug_cmnd_count = 0;
2674 return count;
2675 }
2676 return -EINVAL;
2677}
2678DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2679 sdebug_every_nth_store);
2680
2681static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2682{
2683 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2684}
2685static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2686 const char * buf, size_t count)
2687{
2688 int n;
2689
2690 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2691 scsi_debug_max_luns = n;
2692 sdebug_max_tgts_luns();
2693 return count;
2694 }
2695 return -EINVAL;
2696}
2697DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2698 sdebug_max_luns_store);
2699
2700static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
2701{
2702 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
2703}
2704DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
2705
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002706static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2707{
2708 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2709}
2710static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2711 const char * buf, size_t count)
2712{
2713 int n;
2714
2715 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2716 scsi_debug_virtual_gb = n;
2717 if (scsi_debug_virtual_gb > 0) {
2718 sdebug_capacity = 2048 * 1024;
2719 sdebug_capacity *= scsi_debug_virtual_gb;
2720 } else
2721 sdebug_capacity = sdebug_store_sectors;
2722 return count;
2723 }
2724 return -EINVAL;
2725}
2726DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2727 sdebug_virtual_gb_store);
2728
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
2730{
2731 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
2732}
2733
2734static ssize_t sdebug_add_host_store(struct device_driver * ddp,
2735 const char * buf, size_t count)
2736{
2737 int delta_hosts;
2738 char work[20];
2739
2740 if (1 != sscanf(buf, "%10s", work))
2741 return -EINVAL;
2742 { /* temporary hack around sscanf() problem with -ve nums */
2743 int neg = 0;
2744
2745 if ('-' == *work)
2746 neg = 1;
2747 if (1 != sscanf(work + neg, "%d", &delta_hosts))
2748 return -EINVAL;
2749 if (neg)
2750 delta_hosts = -delta_hosts;
2751 }
2752 if (delta_hosts > 0) {
2753 do {
2754 sdebug_add_adapter();
2755 } while (--delta_hosts);
2756 } else if (delta_hosts < 0) {
2757 do {
2758 sdebug_remove_adapter();
2759 } while (++delta_hosts);
2760 }
2761 return count;
2762}
2763DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
2764 sdebug_add_host_store);
2765
Douglas Gilbert23183912006-09-16 20:30:47 -04002766static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
2767 char * buf)
2768{
2769 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
2770}
2771static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
2772 const char * buf, size_t count)
2773{
2774 int n;
2775
2776 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2777 scsi_debug_vpd_use_hostno = n;
2778 return count;
2779 }
2780 return -EINVAL;
2781}
2782DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
2783 sdebug_vpd_use_hostno_store);
2784
2785/* Note: The following function creates attribute files in the
2786 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
2787 files (over those found in the /sys/module/scsi_debug/parameters
2788 directory) is that auxiliary actions can be triggered when an attribute
2789 is changed. For example see: sdebug_add_host_store() above.
2790 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002791static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002793 int ret;
2794
2795 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2796 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
2797 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2798 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2799 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04002800 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002801 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002802 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002803 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002804 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002805 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
2806 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
2807 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04002808 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
2809 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002810 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811}
2812
2813static void do_remove_driverfs_files(void)
2814{
Douglas Gilbert23183912006-09-16 20:30:47 -04002815 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
2816 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
2818 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
2819 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002821 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
2822 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002824 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
2826 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2827 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2828 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
2829 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2830}
2831
2832static int __init scsi_debug_init(void)
2833{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002834 unsigned int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 int host_to_add;
2836 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002837 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838
2839 if (scsi_debug_dev_size_mb < 1)
2840 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002841 sdebug_store_size = (unsigned int)scsi_debug_dev_size_mb * 1048576;
2842 sdebug_store_sectors = sdebug_store_size / SECT_SIZE;
2843 if (scsi_debug_virtual_gb > 0) {
2844 sdebug_capacity = 2048 * 1024;
2845 sdebug_capacity *= scsi_debug_virtual_gb;
2846 } else
2847 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848
2849 /* play around with geometry, don't waste too much on track 0 */
2850 sdebug_heads = 8;
2851 sdebug_sectors_per = 32;
2852 if (scsi_debug_dev_size_mb >= 16)
2853 sdebug_heads = 32;
2854 else if (scsi_debug_dev_size_mb >= 256)
2855 sdebug_heads = 64;
2856 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2857 (sdebug_sectors_per * sdebug_heads);
2858 if (sdebug_cylinders_per >= 1024) {
2859 /* other LLDs do this; implies >= 1GB ram disk ... */
2860 sdebug_heads = 255;
2861 sdebug_sectors_per = 63;
2862 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2863 (sdebug_sectors_per * sdebug_heads);
2864 }
2865
2866 sz = sdebug_store_size;
2867 fake_storep = vmalloc(sz);
2868 if (NULL == fake_storep) {
2869 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
2870 return -ENOMEM;
2871 }
2872 memset(fake_storep, 0, sz);
2873 if (scsi_debug_num_parts > 0)
2874 sdebug_build_parts(fake_storep);
2875
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002876 ret = device_register(&pseudo_primary);
2877 if (ret < 0) {
2878 printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
2879 ret);
2880 goto free_vm;
2881 }
2882 ret = bus_register(&pseudo_lld_bus);
2883 if (ret < 0) {
2884 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
2885 ret);
2886 goto dev_unreg;
2887 }
2888 ret = driver_register(&sdebug_driverfs_driver);
2889 if (ret < 0) {
2890 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
2891 ret);
2892 goto bus_unreg;
2893 }
2894 ret = do_create_driverfs_files();
2895 if (ret < 0) {
2896 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
2897 ret);
2898 goto del_files;
2899 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002901 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903 host_to_add = scsi_debug_add_host;
2904 scsi_debug_add_host = 0;
2905
2906 for (k = 0; k < host_to_add; k++) {
2907 if (sdebug_add_adapter()) {
2908 printk(KERN_ERR "scsi_debug_init: "
2909 "sdebug_add_adapter failed k=%d\n", k);
2910 break;
2911 }
2912 }
2913
2914 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
2915 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
2916 scsi_debug_add_host);
2917 }
2918 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002919
2920del_files:
2921 do_remove_driverfs_files();
2922 driver_unregister(&sdebug_driverfs_driver);
2923bus_unreg:
2924 bus_unregister(&pseudo_lld_bus);
2925dev_unreg:
2926 device_unregister(&pseudo_primary);
2927free_vm:
2928 vfree(fake_storep);
2929
2930 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931}
2932
2933static void __exit scsi_debug_exit(void)
2934{
2935 int k = scsi_debug_add_host;
2936
2937 stop_all_queued();
2938 for (; k; k--)
2939 sdebug_remove_adapter();
2940 do_remove_driverfs_files();
2941 driver_unregister(&sdebug_driverfs_driver);
2942 bus_unregister(&pseudo_lld_bus);
2943 device_unregister(&pseudo_primary);
2944
2945 vfree(fake_storep);
2946}
2947
2948device_initcall(scsi_debug_init);
2949module_exit(scsi_debug_exit);
2950
Adrian Bunk52c1da32005-06-23 22:05:33 -07002951static void pseudo_0_release(struct device * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952{
2953 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2954 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
2955}
2956
2957static struct device pseudo_primary = {
2958 .bus_id = "pseudo_0",
2959 .release = pseudo_0_release,
2960};
2961
2962static int pseudo_lld_bus_match(struct device *dev,
2963 struct device_driver *dev_driver)
2964{
2965 return 1;
2966}
2967
2968static struct bus_type pseudo_lld_bus = {
2969 .name = "pseudo",
2970 .match = pseudo_lld_bus_match,
Russell Kingbbbe3a42006-01-05 14:44:46 +00002971 .probe = sdebug_driver_probe,
2972 .remove = sdebug_driver_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973};
2974
2975static void sdebug_release_adapter(struct device * dev)
2976{
2977 struct sdebug_host_info *sdbg_host;
2978
2979 sdbg_host = to_sdebug_host(dev);
2980 kfree(sdbg_host);
2981}
2982
2983static int sdebug_add_adapter(void)
2984{
2985 int k, devs_per_host;
2986 int error = 0;
2987 struct sdebug_host_info *sdbg_host;
2988 struct sdebug_dev_info *sdbg_devinfo;
2989 struct list_head *lh, *lh_sf;
2990
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002991 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 if (NULL == sdbg_host) {
2993 printk(KERN_ERR "%s: out of memory at line %d\n",
2994 __FUNCTION__, __LINE__);
2995 return -ENOMEM;
2996 }
2997
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
2999
3000 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
3001 for (k = 0; k < devs_per_host; k++) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003002 sdbg_devinfo = kzalloc(sizeof(*sdbg_devinfo),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 if (NULL == sdbg_devinfo) {
3004 printk(KERN_ERR "%s: out of memory at line %d\n",
3005 __FUNCTION__, __LINE__);
3006 error = -ENOMEM;
3007 goto clean;
3008 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 sdbg_devinfo->sdbg_host = sdbg_host;
3010 list_add_tail(&sdbg_devinfo->dev_list,
3011 &sdbg_host->dev_info_list);
3012 }
3013
3014 spin_lock(&sdebug_host_list_lock);
3015 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
3016 spin_unlock(&sdebug_host_list_lock);
3017
3018 sdbg_host->dev.bus = &pseudo_lld_bus;
3019 sdbg_host->dev.parent = &pseudo_primary;
3020 sdbg_host->dev.release = &sdebug_release_adapter;
3021 sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host);
3022
3023 error = device_register(&sdbg_host->dev);
3024
3025 if (error)
3026 goto clean;
3027
3028 ++scsi_debug_add_host;
3029 return error;
3030
3031clean:
3032 list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) {
3033 sdbg_devinfo = list_entry(lh, struct sdebug_dev_info,
3034 dev_list);
3035 list_del(&sdbg_devinfo->dev_list);
3036 kfree(sdbg_devinfo);
3037 }
3038
3039 kfree(sdbg_host);
3040 return error;
3041}
3042
3043static void sdebug_remove_adapter(void)
3044{
3045 struct sdebug_host_info * sdbg_host = NULL;
3046
3047 spin_lock(&sdebug_host_list_lock);
3048 if (!list_empty(&sdebug_host_list)) {
3049 sdbg_host = list_entry(sdebug_host_list.prev,
3050 struct sdebug_host_info, host_list);
3051 list_del(&sdbg_host->host_list);
3052 }
3053 spin_unlock(&sdebug_host_list_lock);
3054
3055 if (!sdbg_host)
3056 return;
3057
3058 device_unregister(&sdbg_host->dev);
3059 --scsi_debug_add_host;
3060}
3061
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09003062static struct scsi_host_template sdebug_driver_template = {
3063 .proc_info = scsi_debug_proc_info,
3064 .proc_name = sdebug_proc_name,
3065 .name = "SCSI DEBUG",
3066 .info = scsi_debug_info,
3067 .slave_alloc = scsi_debug_slave_alloc,
3068 .slave_configure = scsi_debug_slave_configure,
3069 .slave_destroy = scsi_debug_slave_destroy,
3070 .ioctl = scsi_debug_ioctl,
3071 .queuecommand = scsi_debug_queuecommand,
3072 .eh_abort_handler = scsi_debug_abort,
3073 .eh_bus_reset_handler = scsi_debug_bus_reset,
3074 .eh_device_reset_handler = scsi_debug_device_reset,
3075 .eh_host_reset_handler = scsi_debug_host_reset,
3076 .bios_param = scsi_debug_biosparam,
3077 .can_queue = SCSI_DEBUG_CANQUEUE,
3078 .this_id = 7,
3079 .sg_tablesize = 256,
3080 .cmd_per_lun = 16,
3081 .max_sectors = 0xffff,
3082 .use_clustering = DISABLE_CLUSTERING,
3083 .module = THIS_MODULE,
3084};
3085
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086static int sdebug_driver_probe(struct device * dev)
3087{
3088 int error = 0;
3089 struct sdebug_host_info *sdbg_host;
3090 struct Scsi_Host *hpnt;
3091
3092 sdbg_host = to_sdebug_host(dev);
3093
3094 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
3095 if (NULL == hpnt) {
3096 printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__);
3097 error = -ENODEV;
3098 return error;
3099 }
3100
3101 sdbg_host->shost = hpnt;
3102 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
3103 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
3104 hpnt->max_id = scsi_debug_num_tgts + 1;
3105 else
3106 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003107 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108
3109 error = scsi_add_host(hpnt, &sdbg_host->dev);
3110 if (error) {
3111 printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
3112 error = -ENODEV;
3113 scsi_host_put(hpnt);
3114 } else
3115 scsi_scan_host(hpnt);
3116
3117
3118 return error;
3119}
3120
3121static int sdebug_driver_remove(struct device * dev)
3122{
3123 struct list_head *lh, *lh_sf;
3124 struct sdebug_host_info *sdbg_host;
3125 struct sdebug_dev_info *sdbg_devinfo;
3126
3127 sdbg_host = to_sdebug_host(dev);
3128
3129 if (!sdbg_host) {
3130 printk(KERN_ERR "%s: Unable to locate host info\n",
3131 __FUNCTION__);
3132 return -ENODEV;
3133 }
3134
3135 scsi_remove_host(sdbg_host->shost);
3136
3137 list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) {
3138 sdbg_devinfo = list_entry(lh, struct sdebug_dev_info,
3139 dev_list);
3140 list_del(&sdbg_devinfo->dev_list);
3141 kfree(sdbg_devinfo);
3142 }
3143
3144 scsi_host_put(sdbg_host->shost);
3145 return 0;
3146}
3147
3148static void sdebug_max_tgts_luns(void)
3149{
3150 struct sdebug_host_info * sdbg_host;
3151 struct Scsi_Host *hpnt;
3152
3153 spin_lock(&sdebug_host_list_lock);
3154 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3155 hpnt = sdbg_host->shost;
3156 if ((hpnt->this_id >= 0) &&
3157 (scsi_debug_num_tgts > hpnt->this_id))
3158 hpnt->max_id = scsi_debug_num_tgts + 1;
3159 else
3160 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003161 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162 }
3163 spin_unlock(&sdebug_host_list_lock);
3164}