blob: be3437c4058ceb8e70b06c47a050eb12d757dca9 [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
347 if (done == NULL)
348 return 0; /* assume mid level reprocessing command */
349
Boaz Harroshc73961e2007-09-07 06:50:20 +0900350 scsi_set_resid(SCpnt, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
352 printk(KERN_INFO "scsi_debug: cmd ");
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400353 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 printk("%02x ", (int)cmd[k]);
355 printk("\n");
356 }
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +0900357
358 if (target == SCpnt->device->host->hostt->this_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 printk(KERN_INFO "scsi_debug: initiator's id used as "
360 "target!\n");
361 return schedule_resp(SCpnt, NULL, done,
362 DID_NO_CONNECT << 16, 0);
363 }
364
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400365 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
366 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 return schedule_resp(SCpnt, NULL, done,
368 DID_NO_CONNECT << 16, 0);
369 devip = devInfoReg(SCpnt->device);
370 if (NULL == devip)
371 return schedule_resp(SCpnt, NULL, done,
372 DID_NO_CONNECT << 16, 0);
373
374 if ((scsi_debug_every_nth != 0) &&
375 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
376 scsi_debug_cmnd_count = 0;
377 if (scsi_debug_every_nth < -1)
378 scsi_debug_every_nth = -1;
379 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
380 return 0; /* ignore command causing timeout */
381 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
382 inj_recovered = 1; /* to reads and writes below */
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500383 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
384 inj_transport = 1; /* to reads and writes below */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 }
386
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400387 if (devip->wlun) {
388 switch (*cmd) {
389 case INQUIRY:
390 case REQUEST_SENSE:
391 case TEST_UNIT_READY:
392 case REPORT_LUNS:
393 break; /* only allowable wlun commands */
394 default:
395 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
396 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
397 "not supported for wlun\n", *cmd);
398 mk_sense_buffer(devip, ILLEGAL_REQUEST,
399 INVALID_OPCODE, 0);
400 errsts = check_condition_result;
401 return schedule_resp(SCpnt, devip, done, errsts,
402 0);
403 }
404 }
405
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 switch (*cmd) {
407 case INQUIRY: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400408 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 errsts = resp_inquiry(SCpnt, target, devip);
410 break;
411 case REQUEST_SENSE: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400412 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 errsts = resp_requests(SCpnt, devip);
414 break;
415 case REZERO_UNIT: /* actually this is REWIND for SSC */
416 case START_STOP:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400417 errsts = resp_start_stop(SCpnt, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 break;
419 case ALLOW_MEDIUM_REMOVAL:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400420 if ((errsts = check_readiness(SCpnt, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 break;
422 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
423 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
424 cmd[4] ? "inhibited" : "enabled");
425 break;
426 case SEND_DIAGNOSTIC: /* mandatory */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400427 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 break;
429 case TEST_UNIT_READY: /* mandatory */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400430 delay_override = 1;
431 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 break;
433 case RESERVE:
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 RESERVE_10:
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:
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 RELEASE_10:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400443 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 break;
445 case READ_CAPACITY:
446 errsts = resp_readcap(SCpnt, devip);
447 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400448 case SERVICE_ACTION_IN:
449 if (SAI_READ_CAPACITY_16 != cmd[1]) {
450 mk_sense_buffer(devip, ILLEGAL_REQUEST,
451 INVALID_OPCODE, 0);
452 errsts = check_condition_result;
453 break;
454 }
455 errsts = resp_readcap16(SCpnt, devip);
456 break;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200457 case MAINTENANCE_IN:
458 if (MI_REPORT_TARGET_PGS != cmd[1]) {
459 mk_sense_buffer(devip, ILLEGAL_REQUEST,
460 INVALID_OPCODE, 0);
461 errsts = check_condition_result;
462 break;
463 }
464 errsts = resp_report_tgtpgs(SCpnt, devip);
465 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 case READ_16:
467 case READ_12:
468 case READ_10:
469 case READ_6:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400470 if ((errsts = check_readiness(SCpnt, 0, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 break;
Douglas Gilbert23183912006-09-16 20:30:47 -0400472 if (scsi_debug_fake_rw)
473 break;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900474 get_data_transfer_info(cmd, &lba, &num);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400475 errsts = resp_read(SCpnt, lba, num, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 if (inj_recovered && (0 == errsts)) {
477 mk_sense_buffer(devip, RECOVERED_ERROR,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400478 THRESHOLD_EXCEEDED, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 errsts = check_condition_result;
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500480 } else if (inj_transport && (0 == errsts)) {
481 mk_sense_buffer(devip, ABORTED_COMMAND,
482 TRANSPORT_PROBLEM, ACK_NAK_TO);
483 errsts = check_condition_result;
484 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 break;
486 case REPORT_LUNS: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400487 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 errsts = resp_report_luns(SCpnt, devip);
489 break;
490 case VERIFY: /* 10 byte SBC-2 command */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400491 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 break;
493 case WRITE_16:
494 case WRITE_12:
495 case WRITE_10:
496 case WRITE_6:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400497 if ((errsts = check_readiness(SCpnt, 0, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 break;
Douglas Gilbert23183912006-09-16 20:30:47 -0400499 if (scsi_debug_fake_rw)
500 break;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900501 get_data_transfer_info(cmd, &lba, &num);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400502 errsts = resp_write(SCpnt, lba, num, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 if (inj_recovered && (0 == errsts)) {
504 mk_sense_buffer(devip, RECOVERED_ERROR,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400505 THRESHOLD_EXCEEDED, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 errsts = check_condition_result;
507 }
508 break;
509 case MODE_SENSE:
510 case MODE_SENSE_10:
511 errsts = resp_mode_sense(SCpnt, target, devip);
512 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400513 case MODE_SELECT:
514 errsts = resp_mode_select(SCpnt, 1, devip);
515 break;
516 case MODE_SELECT_10:
517 errsts = resp_mode_select(SCpnt, 0, devip);
518 break;
519 case LOG_SENSE:
520 errsts = resp_log_sense(SCpnt, devip);
521 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 case SYNCHRONIZE_CACHE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400523 delay_override = 1;
524 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 break;
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500526 case WRITE_BUFFER:
527 errsts = check_readiness(SCpnt, 1, devip);
528 break;
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900529 case XDWRITEREAD_10:
530 if (!scsi_bidi_cmnd(SCpnt)) {
531 mk_sense_buffer(devip, ILLEGAL_REQUEST,
532 INVALID_FIELD_IN_CDB, 0);
533 errsts = check_condition_result;
534 break;
535 }
536
537 errsts = check_readiness(SCpnt, 0, devip);
538 if (errsts)
539 break;
540 if (scsi_debug_fake_rw)
541 break;
542 get_data_transfer_info(cmd, &lba, &num);
543 errsts = resp_read(SCpnt, lba, num, devip);
544 if (errsts)
545 break;
546 errsts = resp_write(SCpnt, lba, num, devip);
547 if (errsts)
548 break;
549 errsts = resp_xdwriteread(SCpnt, lba, num, devip);
550 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 default:
552 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
553 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
554 "supported\n", *cmd);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400555 if ((errsts = check_readiness(SCpnt, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 break; /* Unit attention takes precedence */
557 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
558 errsts = check_condition_result;
559 break;
560 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400561 return schedule_resp(SCpnt, devip, done, errsts,
562 (delay_override ? 0 : scsi_debug_delay));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563}
564
565static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
566{
567 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
568 printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
569 }
570 return -EINVAL;
571 /* return -ENOTTY; // correct return but upsets fdisk */
572}
573
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400574static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
575 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576{
577 if (devip->reset) {
578 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
579 printk(KERN_INFO "scsi_debug: Reporting Unit "
580 "attention: power on reset\n");
581 devip->reset = 0;
582 mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
583 return check_condition_result;
584 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400585 if ((0 == reset_only) && devip->stopped) {
586 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
587 printk(KERN_INFO "scsi_debug: Reporting Not "
588 "ready: initializing command required\n");
589 mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
590 0x2);
591 return check_condition_result;
592 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 return 0;
594}
595
596/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
597static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
598 int arr_len)
599{
600 int k, req_len, act_len, len, active;
601 void * kaddr;
602 void * kaddr_off;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900603 struct scatterlist *sg;
604 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900606 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900608 if (!sdb->table.sgl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 return (DID_ERROR << 16);
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900610 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 return (DID_ERROR << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 active = 1;
Jens Axboe852e0342007-07-16 10:19:24 +0200613 req_len = act_len = 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900614 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, k) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 if (active) {
616 kaddr = (unsigned char *)
Jens Axboe45711f12007-10-22 21:19:53 +0200617 kmap_atomic(sg_page(sg), KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 if (NULL == kaddr)
619 return (DID_ERROR << 16);
Jens Axboe852e0342007-07-16 10:19:24 +0200620 kaddr_off = (unsigned char *)kaddr + sg->offset;
621 len = sg->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 if ((req_len + len) > arr_len) {
623 active = 0;
624 len = arr_len - req_len;
625 }
626 memcpy(kaddr_off, arr + req_len, len);
627 kunmap_atomic(kaddr, KM_USER0);
628 act_len += len;
629 }
Jens Axboe852e0342007-07-16 10:19:24 +0200630 req_len += sg->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 }
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900632 if (sdb->resid)
633 sdb->resid -= act_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400634 else
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900635 sdb->resid = req_len - act_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 return 0;
637}
638
639/* Returns number of bytes fetched into 'arr' or -1 if error. */
640static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
641 int max_arr_len)
642{
643 int k, req_len, len, fin;
644 void * kaddr;
645 void * kaddr_off;
Jens Axboe852e0342007-07-16 10:19:24 +0200646 struct scatterlist * sg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
Boaz Harroshc73961e2007-09-07 06:50:20 +0900648 if (0 == scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 return 0;
Boaz Harroshc73961e2007-09-07 06:50:20 +0900650 if (NULL == scsi_sglist(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 return -1;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900652 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 return -1;
Jens Axboe852e0342007-07-16 10:19:24 +0200654 req_len = fin = 0;
Boaz Harroshc73961e2007-09-07 06:50:20 +0900655 scsi_for_each_sg(scp, sg, scsi_sg_count(scp), k) {
Jens Axboe45711f12007-10-22 21:19:53 +0200656 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 if (NULL == kaddr)
658 return -1;
Jens Axboe852e0342007-07-16 10:19:24 +0200659 kaddr_off = (unsigned char *)kaddr + sg->offset;
660 len = sg->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 if ((req_len + len) > max_arr_len) {
662 len = max_arr_len - req_len;
663 fin = 1;
664 }
665 memcpy(arr + req_len, kaddr_off, len);
666 kunmap_atomic(kaddr, KM_USER0);
667 if (fin)
668 return req_len + len;
Jens Axboe852e0342007-07-16 10:19:24 +0200669 req_len += sg->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 }
671 return req_len;
672}
673
674
675static const char * inq_vendor_id = "Linux ";
676static const char * inq_product_id = "scsi_debug ";
677static const char * inq_product_rev = "0004";
678
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200679static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
680 int target_dev_id, int dev_id_num,
681 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400682 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400684 int num, port_a;
685 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400687 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 /* T10 vendor identifier field format (faked) */
689 arr[0] = 0x2; /* ASCII */
690 arr[1] = 0x1;
691 arr[2] = 0x0;
692 memcpy(&arr[4], inq_vendor_id, 8);
693 memcpy(&arr[12], inq_product_id, 16);
694 memcpy(&arr[28], dev_id_str, dev_id_str_len);
695 num = 8 + 16 + dev_id_str_len;
696 arr[3] = num;
697 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400698 if (dev_id_num >= 0) {
699 /* NAA-5, Logical unit identifier (binary) */
700 arr[num++] = 0x1; /* binary (not necessarily sas) */
701 arr[num++] = 0x3; /* PIV=0, lu, naa */
702 arr[num++] = 0x0;
703 arr[num++] = 0x8;
704 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
705 arr[num++] = 0x33;
706 arr[num++] = 0x33;
707 arr[num++] = 0x30;
708 arr[num++] = (dev_id_num >> 24);
709 arr[num++] = (dev_id_num >> 16) & 0xff;
710 arr[num++] = (dev_id_num >> 8) & 0xff;
711 arr[num++] = dev_id_num & 0xff;
712 /* Target relative port number */
713 arr[num++] = 0x61; /* proto=sas, binary */
714 arr[num++] = 0x94; /* PIV=1, target port, rel port */
715 arr[num++] = 0x0; /* reserved */
716 arr[num++] = 0x4; /* length */
717 arr[num++] = 0x0; /* reserved */
718 arr[num++] = 0x0; /* reserved */
719 arr[num++] = 0x0;
720 arr[num++] = 0x1; /* relative port A */
721 }
722 /* NAA-5, Target port identifier */
723 arr[num++] = 0x61; /* proto=sas, binary */
724 arr[num++] = 0x93; /* piv=1, target port, naa */
725 arr[num++] = 0x0;
726 arr[num++] = 0x8;
727 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
728 arr[num++] = 0x22;
729 arr[num++] = 0x22;
730 arr[num++] = 0x20;
731 arr[num++] = (port_a >> 24);
732 arr[num++] = (port_a >> 16) & 0xff;
733 arr[num++] = (port_a >> 8) & 0xff;
734 arr[num++] = port_a & 0xff;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200735 /* NAA-5, Target port group identifier */
736 arr[num++] = 0x61; /* proto=sas, binary */
737 arr[num++] = 0x95; /* piv=1, target port group id */
738 arr[num++] = 0x0;
739 arr[num++] = 0x4;
740 arr[num++] = 0;
741 arr[num++] = 0;
742 arr[num++] = (port_group_id >> 8) & 0xff;
743 arr[num++] = port_group_id & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400744 /* NAA-5, Target device identifier */
745 arr[num++] = 0x61; /* proto=sas, binary */
746 arr[num++] = 0xa3; /* piv=1, target device, naa */
747 arr[num++] = 0x0;
748 arr[num++] = 0x8;
749 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
750 arr[num++] = 0x22;
751 arr[num++] = 0x22;
752 arr[num++] = 0x20;
753 arr[num++] = (target_dev_id >> 24);
754 arr[num++] = (target_dev_id >> 16) & 0xff;
755 arr[num++] = (target_dev_id >> 8) & 0xff;
756 arr[num++] = target_dev_id & 0xff;
757 /* SCSI name string: Target device identifier */
758 arr[num++] = 0x63; /* proto=sas, UTF-8 */
759 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
760 arr[num++] = 0x0;
761 arr[num++] = 24;
762 memcpy(arr + num, "naa.52222220", 12);
763 num += 12;
764 snprintf(b, sizeof(b), "%08X", target_dev_id);
765 memcpy(arr + num, b, 8);
766 num += 8;
767 memset(arr + num, 0, 4);
768 num += 4;
769 return num;
770}
771
772
773static unsigned char vpd84_data[] = {
774/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
775 0x22,0x22,0x22,0x0,0xbb,0x1,
776 0x22,0x22,0x22,0x0,0xbb,0x2,
777};
778
779static int inquiry_evpd_84(unsigned char * arr)
780{
781 memcpy(arr, vpd84_data, sizeof(vpd84_data));
782 return sizeof(vpd84_data);
783}
784
785static int inquiry_evpd_85(unsigned char * arr)
786{
787 int num = 0;
788 const char * na1 = "https://www.kernel.org/config";
789 const char * na2 = "http://www.kernel.org/log";
790 int plen, olen;
791
792 arr[num++] = 0x1; /* lu, storage config */
793 arr[num++] = 0x0; /* reserved */
794 arr[num++] = 0x0;
795 olen = strlen(na1);
796 plen = olen + 1;
797 if (plen % 4)
798 plen = ((plen / 4) + 1) * 4;
799 arr[num++] = plen; /* length, null termianted, padded */
800 memcpy(arr + num, na1, olen);
801 memset(arr + num + olen, 0, plen - olen);
802 num += plen;
803
804 arr[num++] = 0x4; /* lu, logging */
805 arr[num++] = 0x0; /* reserved */
806 arr[num++] = 0x0;
807 olen = strlen(na2);
808 plen = olen + 1;
809 if (plen % 4)
810 plen = ((plen / 4) + 1) * 4;
811 arr[num++] = plen; /* length, null terminated, padded */
812 memcpy(arr + num, na2, olen);
813 memset(arr + num + olen, 0, plen - olen);
814 num += plen;
815
816 return num;
817}
818
819/* SCSI ports VPD page */
820static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
821{
822 int num = 0;
823 int port_a, port_b;
824
825 port_a = target_dev_id + 1;
826 port_b = port_a + 1;
827 arr[num++] = 0x0; /* reserved */
828 arr[num++] = 0x0; /* reserved */
829 arr[num++] = 0x0;
830 arr[num++] = 0x1; /* relative port 1 (primary) */
831 memset(arr + num, 0, 6);
832 num += 6;
833 arr[num++] = 0x0;
834 arr[num++] = 12; /* length tp descriptor */
835 /* naa-5 target port identifier (A) */
836 arr[num++] = 0x61; /* proto=sas, binary */
837 arr[num++] = 0x93; /* PIV=1, target port, NAA */
838 arr[num++] = 0x0; /* reserved */
839 arr[num++] = 0x8; /* length */
840 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
841 arr[num++] = 0x22;
842 arr[num++] = 0x22;
843 arr[num++] = 0x20;
844 arr[num++] = (port_a >> 24);
845 arr[num++] = (port_a >> 16) & 0xff;
846 arr[num++] = (port_a >> 8) & 0xff;
847 arr[num++] = port_a & 0xff;
848
849 arr[num++] = 0x0; /* reserved */
850 arr[num++] = 0x0; /* reserved */
851 arr[num++] = 0x0;
852 arr[num++] = 0x2; /* relative port 2 (secondary) */
853 memset(arr + num, 0, 6);
854 num += 6;
855 arr[num++] = 0x0;
856 arr[num++] = 12; /* length tp descriptor */
857 /* naa-5 target port identifier (B) */
858 arr[num++] = 0x61; /* proto=sas, binary */
859 arr[num++] = 0x93; /* PIV=1, target port, NAA */
860 arr[num++] = 0x0; /* reserved */
861 arr[num++] = 0x8; /* length */
862 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
863 arr[num++] = 0x22;
864 arr[num++] = 0x22;
865 arr[num++] = 0x20;
866 arr[num++] = (port_b >> 24);
867 arr[num++] = (port_b >> 16) & 0xff;
868 arr[num++] = (port_b >> 8) & 0xff;
869 arr[num++] = port_b & 0xff;
870
871 return num;
872}
873
874
875static unsigned char vpd89_data[] = {
876/* from 4th byte */ 0,0,0,0,
877'l','i','n','u','x',' ',' ',' ',
878'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
879'1','2','3','4',
8800x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
8810xec,0,0,0,
8820x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
8830,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
8840x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
8850x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
8860x53,0x41,
8870x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
8880x20,0x20,
8890x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
8900x10,0x80,
8910,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
8920x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
8930x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
8940,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
8950x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
8960x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
8970,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
8980,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8990,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9010x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
9020,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
9030xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
9040,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,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,0,0,
9140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9160,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
917};
918
919static int inquiry_evpd_89(unsigned char * arr)
920{
921 memcpy(arr, vpd89_data, sizeof(vpd89_data));
922 return sizeof(vpd89_data);
923}
924
925
926static unsigned char vpdb0_data[] = {
927 /* from 4th byte */ 0,0,0,4,
928 0,0,0x4,0,
929 0,0,0,64,
930};
931
932static int inquiry_evpd_b0(unsigned char * arr)
933{
934 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
935 if (sdebug_store_sectors > 0x400) {
936 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
937 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
938 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
939 arr[7] = sdebug_store_sectors & 0xff;
940 }
941 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942}
943
944
945#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400946#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
948static int resp_inquiry(struct scsi_cmnd * scp, int target,
949 struct sdebug_dev_info * devip)
950{
951 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200952 unsigned char * arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 unsigned char *cmd = (unsigned char *)scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200954 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955
956 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500957 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
958 if (! arr)
959 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400960 if (devip->wlun)
961 pq_pdt = 0x1e; /* present, wlun */
962 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
963 pq_pdt = 0x7f; /* not present, no device type */
964 else
965 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 arr[0] = pq_pdt;
967 if (0x2 & cmd[1]) { /* CMDDT bit set */
968 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
969 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200970 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 return check_condition_result;
972 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200973 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400974 char lu_id_str[6];
975 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200977 port_group_id = (((host_no + 1) & 0x7f) << 8) +
978 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -0400979 if (0 == scsi_debug_vpd_use_hostno)
980 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400981 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
982 (devip->target * 1000) + devip->lun);
983 target_dev_id = ((host_no + 1) * 2000) +
984 (devip->target * 1000) - 3;
985 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400987 arr[1] = cmd[2]; /*sanity */
988 n = 4;
989 arr[n++] = 0x0; /* this page */
990 arr[n++] = 0x80; /* unit serial number */
991 arr[n++] = 0x83; /* device identification */
992 arr[n++] = 0x84; /* software interface ident. */
993 arr[n++] = 0x85; /* management network addresses */
994 arr[n++] = 0x86; /* extended inquiry */
995 arr[n++] = 0x87; /* mode page policy */
996 arr[n++] = 0x88; /* SCSI ports */
997 arr[n++] = 0x89; /* ATA information */
998 arr[n++] = 0xb0; /* Block limits (SBC) */
999 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001001 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001003 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001005 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001006 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
1007 target_dev_id, lu_id_num,
1008 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001009 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1010 arr[1] = cmd[2]; /*sanity */
1011 arr[3] = inquiry_evpd_84(&arr[4]);
1012 } else if (0x85 == cmd[2]) { /* Management network addresses */
1013 arr[1] = cmd[2]; /*sanity */
1014 arr[3] = inquiry_evpd_85(&arr[4]);
1015 } else if (0x86 == cmd[2]) { /* extended inquiry */
1016 arr[1] = cmd[2]; /*sanity */
1017 arr[3] = 0x3c; /* number of following entries */
1018 arr[4] = 0x0; /* no protection stuff */
1019 arr[5] = 0x7; /* head of q, ordered + simple q's */
1020 } else if (0x87 == cmd[2]) { /* mode page policy */
1021 arr[1] = cmd[2]; /*sanity */
1022 arr[3] = 0x8; /* number of following entries */
1023 arr[4] = 0x2; /* disconnect-reconnect mp */
1024 arr[6] = 0x80; /* mlus, shared */
1025 arr[8] = 0x18; /* protocol specific lu */
1026 arr[10] = 0x82; /* mlus, per initiator port */
1027 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1028 arr[1] = cmd[2]; /*sanity */
1029 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
1030 } else if (0x89 == cmd[2]) { /* ATA information */
1031 arr[1] = cmd[2]; /*sanity */
1032 n = inquiry_evpd_89(&arr[4]);
1033 arr[2] = (n >> 8);
1034 arr[3] = (n & 0xff);
1035 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
1036 arr[1] = cmd[2]; /*sanity */
1037 arr[3] = inquiry_evpd_b0(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 } else {
1039 /* Illegal request, invalid field in cdb */
1040 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1041 INVALID_FIELD_IN_CDB, 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001042 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 return check_condition_result;
1044 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001045 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001046 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001047 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001048 kfree(arr);
1049 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 }
1051 /* drops through here for a standard inquiry */
1052 arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
1053 arr[2] = scsi_debug_scsi_level;
1054 arr[3] = 2; /* response_data_format==2 */
1055 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001056 if (0 == scsi_debug_vpd_use_hostno)
1057 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001058 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001060 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 memcpy(&arr[8], inq_vendor_id, 8);
1062 memcpy(&arr[16], inq_product_id, 16);
1063 memcpy(&arr[32], inq_product_rev, 4);
1064 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001065 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
1066 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
1067 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001069 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001071 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001073 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001074 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001076 kfree(arr);
1077 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078}
1079
1080static int resp_requests(struct scsi_cmnd * scp,
1081 struct sdebug_dev_info * devip)
1082{
1083 unsigned char * sbuff;
1084 unsigned char *cmd = (unsigned char *)scp->cmnd;
1085 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001086 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 int len = 18;
1088
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001089 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001091 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
1092 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001094 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1095 if (want_dsense) {
1096 arr[0] = 0x72;
1097 arr[1] = 0x0; /* NO_SENSE in sense_key */
1098 arr[2] = THRESHOLD_EXCEEDED;
1099 arr[3] = 0xff; /* TEST set and MRIE==6 */
1100 } else {
1101 arr[0] = 0x70;
1102 arr[2] = 0x0; /* NO_SENSE in sense_key */
1103 arr[7] = 0xa; /* 18 byte sense buffer */
1104 arr[12] = THRESHOLD_EXCEEDED;
1105 arr[13] = 0xff; /* TEST set and MRIE==6 */
1106 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001107 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001109 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
1110 /* DESC bit set and sense_buff in fixed format */
1111 memset(arr, 0, sizeof(arr));
1112 arr[0] = 0x72;
1113 arr[1] = sbuff[2]; /* sense key */
1114 arr[2] = sbuff[12]; /* asc */
1115 arr[3] = sbuff[13]; /* ascq */
1116 len = 8;
1117 }
1118 }
1119 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 return fill_from_dev_buffer(scp, arr, len);
1121}
1122
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001123static int resp_start_stop(struct scsi_cmnd * scp,
1124 struct sdebug_dev_info * devip)
1125{
1126 unsigned char *cmd = (unsigned char *)scp->cmnd;
1127 int power_cond, errsts, start;
1128
1129 if ((errsts = check_readiness(scp, 1, devip)))
1130 return errsts;
1131 power_cond = (cmd[4] & 0xf0) >> 4;
1132 if (power_cond) {
1133 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1134 0);
1135 return check_condition_result;
1136 }
1137 start = cmd[4] & 1;
1138 if (start == devip->stopped)
1139 devip->stopped = !start;
1140 return 0;
1141}
1142
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143#define SDEBUG_READCAP_ARR_SZ 8
1144static int resp_readcap(struct scsi_cmnd * scp,
1145 struct sdebug_dev_info * devip)
1146{
1147 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001148 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 int errsts;
1150
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001151 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001153 /* following just in case virtual_gb changed */
1154 if (scsi_debug_virtual_gb > 0) {
1155 sdebug_capacity = 2048 * 1024;
1156 sdebug_capacity *= scsi_debug_virtual_gb;
1157 } else
1158 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001160 if (sdebug_capacity < 0xffffffff) {
1161 capac = (unsigned int)sdebug_capacity - 1;
1162 arr[0] = (capac >> 24);
1163 arr[1] = (capac >> 16) & 0xff;
1164 arr[2] = (capac >> 8) & 0xff;
1165 arr[3] = capac & 0xff;
1166 } else {
1167 arr[0] = 0xff;
1168 arr[1] = 0xff;
1169 arr[2] = 0xff;
1170 arr[3] = 0xff;
1171 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1173 arr[7] = SECT_SIZE_PER(target) & 0xff;
1174 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1175}
1176
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001177#define SDEBUG_READCAP16_ARR_SZ 32
1178static int resp_readcap16(struct scsi_cmnd * scp,
1179 struct sdebug_dev_info * devip)
1180{
1181 unsigned char *cmd = (unsigned char *)scp->cmnd;
1182 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1183 unsigned long long capac;
1184 int errsts, k, alloc_len;
1185
1186 if ((errsts = check_readiness(scp, 1, devip)))
1187 return errsts;
1188 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1189 + cmd[13]);
1190 /* following just in case virtual_gb changed */
1191 if (scsi_debug_virtual_gb > 0) {
1192 sdebug_capacity = 2048 * 1024;
1193 sdebug_capacity *= scsi_debug_virtual_gb;
1194 } else
1195 sdebug_capacity = sdebug_store_sectors;
1196 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1197 capac = sdebug_capacity - 1;
1198 for (k = 0; k < 8; ++k, capac >>= 8)
1199 arr[7 - k] = capac & 0xff;
1200 arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff;
1201 arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff;
1202 arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1203 arr[11] = SECT_SIZE_PER(target) & 0xff;
1204 return fill_from_dev_buffer(scp, arr,
1205 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1206}
1207
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001208#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1209
1210static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1211 struct sdebug_dev_info * devip)
1212{
1213 unsigned char *cmd = (unsigned char *)scp->cmnd;
1214 unsigned char * arr;
1215 int host_no = devip->sdbg_host->shost->host_no;
1216 int n, ret, alen, rlen;
1217 int port_group_a, port_group_b, port_a, port_b;
1218
1219 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
1220 + cmd[9]);
1221
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001222 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1223 if (! arr)
1224 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001225 /*
1226 * EVPD page 0x88 states we have two ports, one
1227 * real and a fake port with no device connected.
1228 * So we create two port groups with one port each
1229 * and set the group with port B to unavailable.
1230 */
1231 port_a = 0x1; /* relative port A */
1232 port_b = 0x2; /* relative port B */
1233 port_group_a = (((host_no + 1) & 0x7f) << 8) +
1234 (devip->channel & 0x7f);
1235 port_group_b = (((host_no + 1) & 0x7f) << 8) +
1236 (devip->channel & 0x7f) + 0x80;
1237
1238 /*
1239 * The asymmetric access state is cycled according to the host_id.
1240 */
1241 n = 4;
1242 if (0 == scsi_debug_vpd_use_hostno) {
1243 arr[n++] = host_no % 3; /* Asymm access state */
1244 arr[n++] = 0x0F; /* claim: all states are supported */
1245 } else {
1246 arr[n++] = 0x0; /* Active/Optimized path */
1247 arr[n++] = 0x01; /* claim: only support active/optimized paths */
1248 }
1249 arr[n++] = (port_group_a >> 8) & 0xff;
1250 arr[n++] = port_group_a & 0xff;
1251 arr[n++] = 0; /* Reserved */
1252 arr[n++] = 0; /* Status code */
1253 arr[n++] = 0; /* Vendor unique */
1254 arr[n++] = 0x1; /* One port per group */
1255 arr[n++] = 0; /* Reserved */
1256 arr[n++] = 0; /* Reserved */
1257 arr[n++] = (port_a >> 8) & 0xff;
1258 arr[n++] = port_a & 0xff;
1259 arr[n++] = 3; /* Port unavailable */
1260 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1261 arr[n++] = (port_group_b >> 8) & 0xff;
1262 arr[n++] = port_group_b & 0xff;
1263 arr[n++] = 0; /* Reserved */
1264 arr[n++] = 0; /* Status code */
1265 arr[n++] = 0; /* Vendor unique */
1266 arr[n++] = 0x1; /* One port per group */
1267 arr[n++] = 0; /* Reserved */
1268 arr[n++] = 0; /* Reserved */
1269 arr[n++] = (port_b >> 8) & 0xff;
1270 arr[n++] = port_b & 0xff;
1271
1272 rlen = n - 4;
1273 arr[0] = (rlen >> 24) & 0xff;
1274 arr[1] = (rlen >> 16) & 0xff;
1275 arr[2] = (rlen >> 8) & 0xff;
1276 arr[3] = rlen & 0xff;
1277
1278 /*
1279 * Return the smallest value of either
1280 * - The allocated length
1281 * - The constructed command length
1282 * - The maximum array size
1283 */
1284 rlen = min(alen,n);
1285 ret = fill_from_dev_buffer(scp, arr,
1286 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1287 kfree(arr);
1288 return ret;
1289}
1290
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291/* <<Following mode page info copied from ST318451LW>> */
1292
1293static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1294{ /* Read-Write Error Recovery page for mode_sense */
1295 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1296 5, 0, 0xff, 0xff};
1297
1298 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1299 if (1 == pcontrol)
1300 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1301 return sizeof(err_recov_pg);
1302}
1303
1304static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1305{ /* Disconnect-Reconnect page for mode_sense */
1306 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1307 0, 0, 0, 0, 0, 0, 0, 0};
1308
1309 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1310 if (1 == pcontrol)
1311 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1312 return sizeof(disconnect_pg);
1313}
1314
1315static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1316{ /* Format device page for mode_sense */
1317 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1318 0, 0, 0, 0, 0, 0, 0, 0,
1319 0, 0, 0, 0, 0x40, 0, 0, 0};
1320
1321 memcpy(p, format_pg, sizeof(format_pg));
1322 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1323 p[11] = sdebug_sectors_per & 0xff;
1324 p[12] = (SECT_SIZE >> 8) & 0xff;
1325 p[13] = SECT_SIZE & 0xff;
1326 if (DEV_REMOVEABLE(target))
1327 p[20] |= 0x20; /* should agree with INQUIRY */
1328 if (1 == pcontrol)
1329 memset(p + 2, 0, sizeof(format_pg) - 2);
1330 return sizeof(format_pg);
1331}
1332
1333static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1334{ /* Caching page for mode_sense */
1335 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1336 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1337
1338 memcpy(p, caching_pg, sizeof(caching_pg));
1339 if (1 == pcontrol)
1340 memset(p + 2, 0, sizeof(caching_pg) - 2);
1341 return sizeof(caching_pg);
1342}
1343
1344static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1345{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001346 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1347 0, 0, 0, 0};
1348 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 0, 0, 0x2, 0x4b};
1350
1351 if (scsi_debug_dsense)
1352 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001353 else
1354 ctrl_m_pg[2] &= ~0x4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1356 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001357 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1358 else if (2 == pcontrol)
1359 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 return sizeof(ctrl_m_pg);
1361}
1362
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001363
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1365{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001366 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1367 0, 0, 0x0, 0x0};
1368 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1369 0, 0, 0x0, 0x0};
1370
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1372 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001373 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1374 else if (2 == pcontrol)
1375 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 return sizeof(iec_m_pg);
1377}
1378
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001379static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1380{ /* SAS SSP mode page - short format for mode_sense */
1381 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1382 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1383
1384 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1385 if (1 == pcontrol)
1386 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1387 return sizeof(sas_sf_m_pg);
1388}
1389
1390
1391static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1392 int target_dev_id)
1393{ /* SAS phy control and discover mode page for mode_sense */
1394 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1395 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1396 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1397 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1398 0x2, 0, 0, 0, 0, 0, 0, 0,
1399 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1400 0, 0, 0, 0, 0, 0, 0, 0,
1401 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1402 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1403 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1404 0x3, 0, 0, 0, 0, 0, 0, 0,
1405 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1406 0, 0, 0, 0, 0, 0, 0, 0,
1407 };
1408 int port_a, port_b;
1409
1410 port_a = target_dev_id + 1;
1411 port_b = port_a + 1;
1412 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1413 p[20] = (port_a >> 24);
1414 p[21] = (port_a >> 16) & 0xff;
1415 p[22] = (port_a >> 8) & 0xff;
1416 p[23] = port_a & 0xff;
1417 p[48 + 20] = (port_b >> 24);
1418 p[48 + 21] = (port_b >> 16) & 0xff;
1419 p[48 + 22] = (port_b >> 8) & 0xff;
1420 p[48 + 23] = port_b & 0xff;
1421 if (1 == pcontrol)
1422 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1423 return sizeof(sas_pcd_m_pg);
1424}
1425
1426static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1427{ /* SAS SSP shared protocol specific port mode subpage */
1428 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1429 0, 0, 0, 0, 0, 0, 0, 0,
1430 };
1431
1432 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1433 if (1 == pcontrol)
1434 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1435 return sizeof(sas_sha_m_pg);
1436}
1437
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438#define SDEBUG_MAX_MSENSE_SZ 256
1439
1440static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1441 struct sdebug_dev_info * devip)
1442{
Douglas Gilbert23183912006-09-16 20:30:47 -04001443 unsigned char dbd, llbaa;
1444 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001446 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 unsigned char * ap;
1448 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1449 unsigned char *cmd = (unsigned char *)scp->cmnd;
1450
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001451 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001453 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 pcontrol = (cmd[2] & 0xc0) >> 6;
1455 pcode = cmd[2] & 0x3f;
1456 subpcode = cmd[3];
1457 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001458 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1459 if ((0 == scsi_debug_ptype) && (0 == dbd))
1460 bd_len = llbaa ? 16 : 8;
1461 else
1462 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1464 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1465 if (0x3 == pcontrol) { /* Saving values not supported */
1466 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1467 0);
1468 return check_condition_result;
1469 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001470 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1471 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001472 /* set DPOFUA bit for disks */
1473 if (0 == scsi_debug_ptype)
1474 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1475 else
1476 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 if (msense_6) {
1478 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001479 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 offset = 4;
1481 } else {
1482 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001483 if (16 == bd_len)
1484 arr[4] = 0x1; /* set LONGLBA bit */
1485 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 offset = 8;
1487 }
1488 ap = arr + offset;
Douglas Gilbert23183912006-09-16 20:30:47 -04001489 if ((bd_len > 0) && (0 == sdebug_capacity)) {
1490 if (scsi_debug_virtual_gb > 0) {
1491 sdebug_capacity = 2048 * 1024;
1492 sdebug_capacity *= scsi_debug_virtual_gb;
1493 } else
1494 sdebug_capacity = sdebug_store_sectors;
1495 }
1496 if (8 == bd_len) {
1497 if (sdebug_capacity > 0xfffffffe) {
1498 ap[0] = 0xff;
1499 ap[1] = 0xff;
1500 ap[2] = 0xff;
1501 ap[3] = 0xff;
1502 } else {
1503 ap[0] = (sdebug_capacity >> 24) & 0xff;
1504 ap[1] = (sdebug_capacity >> 16) & 0xff;
1505 ap[2] = (sdebug_capacity >> 8) & 0xff;
1506 ap[3] = sdebug_capacity & 0xff;
1507 }
1508 ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1509 ap[7] = SECT_SIZE_PER(target) & 0xff;
1510 offset += bd_len;
1511 ap = arr + offset;
1512 } else if (16 == bd_len) {
1513 unsigned long long capac = sdebug_capacity;
1514
1515 for (k = 0; k < 8; ++k, capac >>= 8)
1516 ap[7 - k] = capac & 0xff;
1517 ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff;
1518 ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff;
1519 ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1520 ap[15] = SECT_SIZE_PER(target) & 0xff;
1521 offset += bd_len;
1522 ap = arr + offset;
1523 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001525 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1526 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1528 0);
1529 return check_condition_result;
1530 }
1531 switch (pcode) {
1532 case 0x1: /* Read-Write error recovery page, direct access */
1533 len = resp_err_recov_pg(ap, pcontrol, target);
1534 offset += len;
1535 break;
1536 case 0x2: /* Disconnect-Reconnect page, all devices */
1537 len = resp_disconnect_pg(ap, pcontrol, target);
1538 offset += len;
1539 break;
1540 case 0x3: /* Format device page, direct access */
1541 len = resp_format_pg(ap, pcontrol, target);
1542 offset += len;
1543 break;
1544 case 0x8: /* Caching page, direct access */
1545 len = resp_caching_pg(ap, pcontrol, target);
1546 offset += len;
1547 break;
1548 case 0xa: /* Control Mode page, all devices */
1549 len = resp_ctrl_m_pg(ap, pcontrol, target);
1550 offset += len;
1551 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001552 case 0x19: /* if spc==1 then sas phy, control+discover */
1553 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1554 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1555 INVALID_FIELD_IN_CDB, 0);
1556 return check_condition_result;
1557 }
1558 len = 0;
1559 if ((0x0 == subpcode) || (0xff == subpcode))
1560 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1561 if ((0x1 == subpcode) || (0xff == subpcode))
1562 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1563 target_dev_id);
1564 if ((0x2 == subpcode) || (0xff == subpcode))
1565 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1566 offset += len;
1567 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 case 0x1c: /* Informational Exceptions Mode page, all devices */
1569 len = resp_iec_m_pg(ap, pcontrol, target);
1570 offset += len;
1571 break;
1572 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001573 if ((0 == subpcode) || (0xff == subpcode)) {
1574 len = resp_err_recov_pg(ap, pcontrol, target);
1575 len += resp_disconnect_pg(ap + len, pcontrol, target);
1576 len += resp_format_pg(ap + len, pcontrol, target);
1577 len += resp_caching_pg(ap + len, pcontrol, target);
1578 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1579 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1580 if (0xff == subpcode) {
1581 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1582 target, target_dev_id);
1583 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1584 }
1585 len += resp_iec_m_pg(ap + len, pcontrol, target);
1586 } else {
1587 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1588 INVALID_FIELD_IN_CDB, 0);
1589 return check_condition_result;
1590 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 offset += len;
1592 break;
1593 default:
1594 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1595 0);
1596 return check_condition_result;
1597 }
1598 if (msense_6)
1599 arr[0] = offset - 1;
1600 else {
1601 arr[0] = ((offset - 2) >> 8) & 0xff;
1602 arr[1] = (offset - 2) & 0xff;
1603 }
1604 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1605}
1606
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001607#define SDEBUG_MAX_MSELECT_SZ 512
1608
1609static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1610 struct sdebug_dev_info * devip)
1611{
1612 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1613 int param_len, res, errsts, mpage;
1614 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1615 unsigned char *cmd = (unsigned char *)scp->cmnd;
1616
1617 if ((errsts = check_readiness(scp, 1, devip)))
1618 return errsts;
1619 memset(arr, 0, sizeof(arr));
1620 pf = cmd[1] & 0x10;
1621 sp = cmd[1] & 0x1;
1622 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1623 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1624 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1625 INVALID_FIELD_IN_CDB, 0);
1626 return check_condition_result;
1627 }
1628 res = fetch_to_dev_buffer(scp, arr, param_len);
1629 if (-1 == res)
1630 return (DID_ERROR << 16);
1631 else if ((res < param_len) &&
1632 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1633 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1634 " IO sent=%d bytes\n", param_len, res);
1635 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1636 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001637 if (md_len > 2) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001638 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1639 INVALID_FIELD_IN_PARAM_LIST, 0);
1640 return check_condition_result;
1641 }
1642 off = bd_len + (mselect6 ? 4 : 8);
1643 mpage = arr[off] & 0x3f;
1644 ps = !!(arr[off] & 0x80);
1645 if (ps) {
1646 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1647 INVALID_FIELD_IN_PARAM_LIST, 0);
1648 return check_condition_result;
1649 }
1650 spf = !!(arr[off] & 0x40);
1651 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1652 (arr[off + 1] + 2);
1653 if ((pg_len + off) > param_len) {
1654 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1655 PARAMETER_LIST_LENGTH_ERR, 0);
1656 return check_condition_result;
1657 }
1658 switch (mpage) {
1659 case 0xa: /* Control Mode page */
1660 if (ctrl_m_pg[1] == arr[off + 1]) {
1661 memcpy(ctrl_m_pg + 2, arr + off + 2,
1662 sizeof(ctrl_m_pg) - 2);
1663 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1664 return 0;
1665 }
1666 break;
1667 case 0x1c: /* Informational Exceptions Mode page */
1668 if (iec_m_pg[1] == arr[off + 1]) {
1669 memcpy(iec_m_pg + 2, arr + off + 2,
1670 sizeof(iec_m_pg) - 2);
1671 return 0;
1672 }
1673 break;
1674 default:
1675 break;
1676 }
1677 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1678 INVALID_FIELD_IN_PARAM_LIST, 0);
1679 return check_condition_result;
1680}
1681
1682static int resp_temp_l_pg(unsigned char * arr)
1683{
1684 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1685 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1686 };
1687
1688 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1689 return sizeof(temp_l_pg);
1690}
1691
1692static int resp_ie_l_pg(unsigned char * arr)
1693{
1694 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1695 };
1696
1697 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1698 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1699 arr[4] = THRESHOLD_EXCEEDED;
1700 arr[5] = 0xff;
1701 }
1702 return sizeof(ie_l_pg);
1703}
1704
1705#define SDEBUG_MAX_LSENSE_SZ 512
1706
1707static int resp_log_sense(struct scsi_cmnd * scp,
1708 struct sdebug_dev_info * devip)
1709{
Douglas Gilbert23183912006-09-16 20:30:47 -04001710 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001711 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1712 unsigned char *cmd = (unsigned char *)scp->cmnd;
1713
1714 if ((errsts = check_readiness(scp, 1, devip)))
1715 return errsts;
1716 memset(arr, 0, sizeof(arr));
1717 ppc = cmd[1] & 0x2;
1718 sp = cmd[1] & 0x1;
1719 if (ppc || sp) {
1720 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1721 INVALID_FIELD_IN_CDB, 0);
1722 return check_condition_result;
1723 }
1724 pcontrol = (cmd[2] & 0xc0) >> 6;
1725 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001726 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001727 alloc_len = (cmd[7] << 8) + cmd[8];
1728 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001729 if (0 == subpcode) {
1730 switch (pcode) {
1731 case 0x0: /* Supported log pages log page */
1732 n = 4;
1733 arr[n++] = 0x0; /* this page */
1734 arr[n++] = 0xd; /* Temperature */
1735 arr[n++] = 0x2f; /* Informational exceptions */
1736 arr[3] = n - 4;
1737 break;
1738 case 0xd: /* Temperature log page */
1739 arr[3] = resp_temp_l_pg(arr + 4);
1740 break;
1741 case 0x2f: /* Informational exceptions log page */
1742 arr[3] = resp_ie_l_pg(arr + 4);
1743 break;
1744 default:
1745 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1746 INVALID_FIELD_IN_CDB, 0);
1747 return check_condition_result;
1748 }
1749 } else if (0xff == subpcode) {
1750 arr[0] |= 0x40;
1751 arr[1] = subpcode;
1752 switch (pcode) {
1753 case 0x0: /* Supported log pages and subpages log page */
1754 n = 4;
1755 arr[n++] = 0x0;
1756 arr[n++] = 0x0; /* 0,0 page */
1757 arr[n++] = 0x0;
1758 arr[n++] = 0xff; /* this page */
1759 arr[n++] = 0xd;
1760 arr[n++] = 0x0; /* Temperature */
1761 arr[n++] = 0x2f;
1762 arr[n++] = 0x0; /* Informational exceptions */
1763 arr[3] = n - 4;
1764 break;
1765 case 0xd: /* Temperature subpages */
1766 n = 4;
1767 arr[n++] = 0xd;
1768 arr[n++] = 0x0; /* Temperature */
1769 arr[3] = n - 4;
1770 break;
1771 case 0x2f: /* Informational exceptions subpages */
1772 n = 4;
1773 arr[n++] = 0x2f;
1774 arr[n++] = 0x0; /* Informational exceptions */
1775 arr[3] = n - 4;
1776 break;
1777 default:
1778 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1779 INVALID_FIELD_IN_CDB, 0);
1780 return check_condition_result;
1781 }
1782 } else {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001783 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1784 INVALID_FIELD_IN_CDB, 0);
1785 return check_condition_result;
1786 }
1787 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1788 return fill_from_dev_buffer(scp, arr,
1789 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1790}
1791
1792static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
1793 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794{
1795 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001796 unsigned int block, from_bottom;
1797 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 int ret;
1799
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001800 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1802 0);
1803 return check_condition_result;
1804 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001805 /* transfer length excessive (tie in to block limits VPD page) */
1806 if (num > sdebug_store_sectors) {
1807 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1808 0);
1809 return check_condition_result;
1810 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001812 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1813 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1814 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1816 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001817 /* set info field and valid bit for fixed descriptor */
1818 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1819 devip->sense_buff[0] |= 0x80; /* Valid bit */
1820 ret = OPT_MEDIUM_ERR_ADDR;
1821 devip->sense_buff[3] = (ret >> 24) & 0xff;
1822 devip->sense_buff[4] = (ret >> 16) & 0xff;
1823 devip->sense_buff[5] = (ret >> 8) & 0xff;
1824 devip->sense_buff[6] = ret & 0xff;
1825 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 return check_condition_result;
1827 }
1828 read_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001829 if ((lba + num) <= sdebug_store_sectors)
1830 ret = fill_from_dev_buffer(SCpnt,
1831 fake_storep + (lba * SECT_SIZE),
1832 num * SECT_SIZE);
1833 else {
1834 /* modulo when one arg is 64 bits needs do_div() */
1835 u = lba;
1836 block = do_div(u, sdebug_store_sectors);
1837 from_bottom = 0;
1838 if ((block + num) > sdebug_store_sectors)
1839 from_bottom = (block + num) - sdebug_store_sectors;
1840 ret = fill_from_dev_buffer(SCpnt,
1841 fake_storep + (block * SECT_SIZE),
1842 (num - from_bottom) * SECT_SIZE);
1843 if ((0 == ret) && (from_bottom > 0))
1844 ret = fill_from_dev_buffer(SCpnt, fake_storep,
1845 from_bottom * SECT_SIZE);
1846 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 read_unlock_irqrestore(&atomic_rw, iflags);
1848 return ret;
1849}
1850
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001851static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
1852 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853{
1854 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001855 unsigned int block, to_bottom;
1856 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 int res;
1858
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001859 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1861 0);
1862 return check_condition_result;
1863 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001864 /* transfer length excessive (tie in to block limits VPD page) */
1865 if (num > sdebug_store_sectors) {
1866 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1867 0);
1868 return check_condition_result;
1869 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870
1871 write_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001872 if ((lba + num) <= sdebug_store_sectors)
1873 res = fetch_to_dev_buffer(SCpnt,
1874 fake_storep + (lba * SECT_SIZE),
1875 num * SECT_SIZE);
1876 else {
1877 /* modulo when one arg is 64 bits needs do_div() */
1878 u = lba;
1879 block = do_div(u, sdebug_store_sectors);
1880 to_bottom = 0;
1881 if ((block + num) > sdebug_store_sectors)
1882 to_bottom = (block + num) - sdebug_store_sectors;
1883 res = fetch_to_dev_buffer(SCpnt,
1884 fake_storep + (block * SECT_SIZE),
1885 (num - to_bottom) * SECT_SIZE);
1886 if ((0 == res) && (to_bottom > 0))
1887 res = fetch_to_dev_buffer(SCpnt, fake_storep,
1888 to_bottom * SECT_SIZE);
1889 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 write_unlock_irqrestore(&atomic_rw, iflags);
1891 if (-1 == res)
1892 return (DID_ERROR << 16);
1893 else if ((res < (num * SECT_SIZE)) &&
1894 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001895 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 " IO sent=%d bytes\n", num * SECT_SIZE, res);
1897 return 0;
1898}
1899
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001900#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901
1902static int resp_report_luns(struct scsi_cmnd * scp,
1903 struct sdebug_dev_info * devip)
1904{
1905 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001906 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 unsigned char *cmd = (unsigned char *)scp->cmnd;
1908 int select_report = (int)cmd[2];
1909 struct scsi_lun *one_lun;
1910 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001911 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912
1913 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001914 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1916 0);
1917 return check_condition_result;
1918 }
1919 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
1920 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
1921 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001922 if (1 == select_report)
1923 lun_cnt = 0;
1924 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
1925 --lun_cnt;
1926 wlun = (select_report > 0) ? 1 : 0;
1927 num = lun_cnt + wlun;
1928 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
1929 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
1930 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
1931 sizeof(struct scsi_lun)), num);
1932 if (n < num) {
1933 wlun = 0;
1934 lun_cnt = n;
1935 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001937 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
1938 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
1939 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
1940 i++, lun++) {
1941 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 if (upper)
1943 one_lun[i].scsi_lun[0] =
1944 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001945 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001947 if (wlun) {
1948 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
1949 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
1950 i++;
1951 }
1952 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 return fill_from_dev_buffer(scp, arr,
1954 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
1955}
1956
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001957static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
1958 unsigned int num, struct sdebug_dev_info *devip)
1959{
1960 int i, j, ret = -1;
1961 unsigned char *kaddr, *buf;
1962 unsigned int offset;
1963 struct scatterlist *sg;
1964 struct scsi_data_buffer *sdb = scsi_in(scp);
1965
1966 /* better not to use temporary buffer. */
1967 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
1968 if (!buf)
1969 return ret;
1970
1971 offset = 0;
1972 scsi_for_each_sg(scp, sg, scsi_sg_count(scp), i) {
1973 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
1974 if (!kaddr)
1975 goto out;
1976
1977 memcpy(buf + offset, kaddr + sg->offset, sg->length);
1978 offset += sg->length;
1979 kunmap_atomic(kaddr, KM_USER0);
1980 }
1981
1982 offset = 0;
1983 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
1984 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
1985 if (!kaddr)
1986 goto out;
1987
1988 for (j = 0; j < sg->length; j++)
1989 *(kaddr + sg->offset + j) ^= *(buf + offset + j);
1990
1991 offset += sg->length;
1992 kunmap_atomic(kaddr, KM_USER0);
1993 }
1994 ret = 0;
1995out:
1996 kfree(buf);
1997
1998 return ret;
1999}
2000
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001/* When timer goes off this function is called. */
2002static void timer_intr_handler(unsigned long indx)
2003{
2004 struct sdebug_queued_cmd * sqcp;
2005 unsigned long iflags;
2006
2007 if (indx >= SCSI_DEBUG_CANQUEUE) {
2008 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
2009 "large\n");
2010 return;
2011 }
2012 spin_lock_irqsave(&queued_arr_lock, iflags);
2013 sqcp = &queued_arr[(int)indx];
2014 if (! sqcp->in_use) {
2015 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
2016 "interrupt\n");
2017 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2018 return;
2019 }
2020 sqcp->in_use = 0;
2021 if (sqcp->done_funct) {
2022 sqcp->a_cmnd->result = sqcp->scsi_result;
2023 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
2024 }
2025 sqcp->done_funct = NULL;
2026 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2027}
2028
2029static int scsi_debug_slave_alloc(struct scsi_device * sdp)
2030{
2031 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002032 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
2033 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002034 set_bit(QUEUE_FLAG_BIDI, &sdp->request_queue->queue_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 return 0;
2036}
2037
2038static int scsi_debug_slave_configure(struct scsi_device * sdp)
2039{
2040 struct sdebug_dev_info * devip;
2041
2042 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002043 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
2044 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
2046 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
2047 devip = devInfoReg(sdp);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002048 if (NULL == devip)
2049 return 1; /* no resources, will be marked offline */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050 sdp->hostdata = devip;
2051 if (sdp->host->cmd_per_lun)
2052 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
2053 sdp->host->cmd_per_lun);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002054 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 return 0;
2056}
2057
2058static void scsi_debug_slave_destroy(struct scsi_device * sdp)
2059{
2060 struct sdebug_dev_info * devip =
2061 (struct sdebug_dev_info *)sdp->hostdata;
2062
2063 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002064 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
2065 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 if (devip) {
2067 /* make this slot avaliable for re-use */
2068 devip->used = 0;
2069 sdp->hostdata = NULL;
2070 }
2071}
2072
2073static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
2074{
2075 struct sdebug_host_info * sdbg_host;
2076 struct sdebug_dev_info * open_devip = NULL;
2077 struct sdebug_dev_info * devip =
2078 (struct sdebug_dev_info *)sdev->hostdata;
2079
2080 if (devip)
2081 return devip;
2082 sdbg_host = *(struct sdebug_host_info **) sdev->host->hostdata;
2083 if(! sdbg_host) {
2084 printk(KERN_ERR "Host info NULL\n");
2085 return NULL;
2086 }
2087 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
2088 if ((devip->used) && (devip->channel == sdev->channel) &&
2089 (devip->target == sdev->id) &&
2090 (devip->lun == sdev->lun))
2091 return devip;
2092 else {
2093 if ((!devip->used) && (!open_devip))
2094 open_devip = devip;
2095 }
2096 }
2097 if (NULL == open_devip) { /* try and make a new one */
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002098 open_devip = kzalloc(sizeof(*open_devip),GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 if (NULL == open_devip) {
2100 printk(KERN_ERR "%s: out of memory at line %d\n",
2101 __FUNCTION__, __LINE__);
2102 return NULL;
2103 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 open_devip->sdbg_host = sdbg_host;
2105 list_add_tail(&open_devip->dev_list,
2106 &sdbg_host->dev_info_list);
2107 }
2108 if (open_devip) {
2109 open_devip->channel = sdev->channel;
2110 open_devip->target = sdev->id;
2111 open_devip->lun = sdev->lun;
2112 open_devip->sdbg_host = sdbg_host;
2113 open_devip->reset = 1;
2114 open_devip->used = 1;
2115 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
2116 if (scsi_debug_dsense)
2117 open_devip->sense_buff[0] = 0x72;
2118 else {
2119 open_devip->sense_buff[0] = 0x70;
2120 open_devip->sense_buff[7] = 0xa;
2121 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002122 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2123 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 return open_devip;
2125 }
2126 return NULL;
2127}
2128
2129static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
2130 int asc, int asq)
2131{
2132 unsigned char * sbuff;
2133
2134 sbuff = devip->sense_buff;
2135 memset(sbuff, 0, SDEBUG_SENSE_LEN);
2136 if (scsi_debug_dsense) {
2137 sbuff[0] = 0x72; /* descriptor, current */
2138 sbuff[1] = key;
2139 sbuff[2] = asc;
2140 sbuff[3] = asq;
2141 } else {
2142 sbuff[0] = 0x70; /* fixed, current */
2143 sbuff[2] = key;
2144 sbuff[7] = 0xa; /* implies 18 byte sense buffer */
2145 sbuff[12] = asc;
2146 sbuff[13] = asq;
2147 }
2148 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2149 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
2150 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
2151}
2152
2153static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
2154{
2155 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2156 printk(KERN_INFO "scsi_debug: abort\n");
2157 ++num_aborts;
2158 stop_queued_cmnd(SCpnt);
2159 return SUCCESS;
2160}
2161
2162static int scsi_debug_biosparam(struct scsi_device *sdev,
2163 struct block_device * bdev, sector_t capacity, int *info)
2164{
2165 int res;
2166 unsigned char *buf;
2167
2168 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2169 printk(KERN_INFO "scsi_debug: biosparam\n");
2170 buf = scsi_bios_ptable(bdev);
2171 if (buf) {
2172 res = scsi_partsize(buf, capacity,
2173 &info[2], &info[0], &info[1]);
2174 kfree(buf);
2175 if (! res)
2176 return res;
2177 }
2178 info[0] = sdebug_heads;
2179 info[1] = sdebug_sectors_per;
2180 info[2] = sdebug_cylinders_per;
2181 return 0;
2182}
2183
2184static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
2185{
2186 struct sdebug_dev_info * devip;
2187
2188 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2189 printk(KERN_INFO "scsi_debug: device_reset\n");
2190 ++num_dev_resets;
2191 if (SCpnt) {
2192 devip = devInfoReg(SCpnt->device);
2193 if (devip)
2194 devip->reset = 1;
2195 }
2196 return SUCCESS;
2197}
2198
2199static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
2200{
2201 struct sdebug_host_info *sdbg_host;
2202 struct sdebug_dev_info * dev_info;
2203 struct scsi_device * sdp;
2204 struct Scsi_Host * hp;
2205
2206 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2207 printk(KERN_INFO "scsi_debug: bus_reset\n");
2208 ++num_bus_resets;
2209 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
2210 sdbg_host = *(struct sdebug_host_info **) hp->hostdata;
2211 if (sdbg_host) {
2212 list_for_each_entry(dev_info,
2213 &sdbg_host->dev_info_list,
2214 dev_list)
2215 dev_info->reset = 1;
2216 }
2217 }
2218 return SUCCESS;
2219}
2220
2221static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
2222{
2223 struct sdebug_host_info * sdbg_host;
2224 struct sdebug_dev_info * dev_info;
2225
2226 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2227 printk(KERN_INFO "scsi_debug: host_reset\n");
2228 ++num_host_resets;
2229 spin_lock(&sdebug_host_list_lock);
2230 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
2231 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
2232 dev_list)
2233 dev_info->reset = 1;
2234 }
2235 spin_unlock(&sdebug_host_list_lock);
2236 stop_all_queued();
2237 return SUCCESS;
2238}
2239
2240/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
2241static int stop_queued_cmnd(struct scsi_cmnd * cmnd)
2242{
2243 unsigned long iflags;
2244 int k;
2245 struct sdebug_queued_cmd * sqcp;
2246
2247 spin_lock_irqsave(&queued_arr_lock, iflags);
2248 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2249 sqcp = &queued_arr[k];
2250 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
2251 del_timer_sync(&sqcp->cmnd_timer);
2252 sqcp->in_use = 0;
2253 sqcp->a_cmnd = NULL;
2254 break;
2255 }
2256 }
2257 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2258 return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
2259}
2260
2261/* Deletes (stops) timers of all queued commands */
2262static void stop_all_queued(void)
2263{
2264 unsigned long iflags;
2265 int k;
2266 struct sdebug_queued_cmd * sqcp;
2267
2268 spin_lock_irqsave(&queued_arr_lock, iflags);
2269 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2270 sqcp = &queued_arr[k];
2271 if (sqcp->in_use && sqcp->a_cmnd) {
2272 del_timer_sync(&sqcp->cmnd_timer);
2273 sqcp->in_use = 0;
2274 sqcp->a_cmnd = NULL;
2275 }
2276 }
2277 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2278}
2279
2280/* Initializes timers in queued array */
2281static void __init init_all_queued(void)
2282{
2283 unsigned long iflags;
2284 int k;
2285 struct sdebug_queued_cmd * sqcp;
2286
2287 spin_lock_irqsave(&queued_arr_lock, iflags);
2288 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2289 sqcp = &queued_arr[k];
2290 init_timer(&sqcp->cmnd_timer);
2291 sqcp->in_use = 0;
2292 sqcp->a_cmnd = NULL;
2293 }
2294 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2295}
2296
2297static void __init sdebug_build_parts(unsigned char * ramp)
2298{
2299 struct partition * pp;
2300 int starts[SDEBUG_MAX_PARTS + 2];
2301 int sectors_per_part, num_sectors, k;
2302 int heads_by_sects, start_sec, end_sec;
2303
2304 /* assume partition table already zeroed */
2305 if ((scsi_debug_num_parts < 1) || (sdebug_store_size < 1048576))
2306 return;
2307 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
2308 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
2309 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
2310 "partitions to %d\n", SDEBUG_MAX_PARTS);
2311 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002312 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 sectors_per_part = (num_sectors - sdebug_sectors_per)
2314 / scsi_debug_num_parts;
2315 heads_by_sects = sdebug_heads * sdebug_sectors_per;
2316 starts[0] = sdebug_sectors_per;
2317 for (k = 1; k < scsi_debug_num_parts; ++k)
2318 starts[k] = ((k * sectors_per_part) / heads_by_sects)
2319 * heads_by_sects;
2320 starts[scsi_debug_num_parts] = num_sectors;
2321 starts[scsi_debug_num_parts + 1] = 0;
2322
2323 ramp[510] = 0x55; /* magic partition markings */
2324 ramp[511] = 0xAA;
2325 pp = (struct partition *)(ramp + 0x1be);
2326 for (k = 0; starts[k + 1]; ++k, ++pp) {
2327 start_sec = starts[k];
2328 end_sec = starts[k + 1] - 1;
2329 pp->boot_ind = 0;
2330
2331 pp->cyl = start_sec / heads_by_sects;
2332 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2333 / sdebug_sectors_per;
2334 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2335
2336 pp->end_cyl = end_sec / heads_by_sects;
2337 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2338 / sdebug_sectors_per;
2339 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2340
2341 pp->start_sect = start_sec;
2342 pp->nr_sects = end_sec - start_sec + 1;
2343 pp->sys_ind = 0x83; /* plain Linux partition */
2344 }
2345}
2346
2347static int schedule_resp(struct scsi_cmnd * cmnd,
2348 struct sdebug_dev_info * devip,
2349 done_funct_t done, int scsi_result, int delta_jiff)
2350{
2351 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2352 if (scsi_result) {
2353 struct scsi_device * sdp = cmnd->device;
2354
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002355 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2356 "non-zero result=0x%x\n", sdp->host->host_no,
2357 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 }
2359 }
2360 if (cmnd && devip) {
2361 /* simulate autosense by this driver */
2362 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2363 memcpy(cmnd->sense_buffer, devip->sense_buff,
2364 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2365 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2366 }
2367 if (delta_jiff <= 0) {
2368 if (cmnd)
2369 cmnd->result = scsi_result;
2370 if (done)
2371 done(cmnd);
2372 return 0;
2373 } else {
2374 unsigned long iflags;
2375 int k;
2376 struct sdebug_queued_cmd * sqcp = NULL;
2377
2378 spin_lock_irqsave(&queued_arr_lock, iflags);
2379 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2380 sqcp = &queued_arr[k];
2381 if (! sqcp->in_use)
2382 break;
2383 }
2384 if (k >= SCSI_DEBUG_CANQUEUE) {
2385 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2386 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2387 return 1; /* report busy to mid level */
2388 }
2389 sqcp->in_use = 1;
2390 sqcp->a_cmnd = cmnd;
2391 sqcp->scsi_result = scsi_result;
2392 sqcp->done_funct = done;
2393 sqcp->cmnd_timer.function = timer_intr_handler;
2394 sqcp->cmnd_timer.data = k;
2395 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2396 add_timer(&sqcp->cmnd_timer);
2397 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2398 if (cmnd)
2399 cmnd->result = 0;
2400 return 0;
2401 }
2402}
2403
Douglas Gilbert23183912006-09-16 20:30:47 -04002404/* Note: The following macros create attribute files in the
2405 /sys/module/scsi_debug/parameters directory. Unfortunately this
2406 driver is unaware of a change and cannot trigger auxiliary actions
2407 as it can when the corresponding attribute in the
2408 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2409 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002410module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2411module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2412module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2413module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2414module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002415module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002416module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2417module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2418module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2419module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2420module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2421module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2422module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2423module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002424module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2425 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426
2427MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2428MODULE_DESCRIPTION("SCSI debug adapter driver");
2429MODULE_LICENSE("GPL");
2430MODULE_VERSION(SCSI_DEBUG_VERSION);
2431
2432MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2433MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002434MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2435MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07002436MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002437MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002438MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2439MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002441MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002442MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2444MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002445MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002446MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447
2448
2449static char sdebug_info[256];
2450
2451static const char * scsi_debug_info(struct Scsi_Host * shp)
2452{
2453 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2454 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2455 scsi_debug_version_date, scsi_debug_dev_size_mb,
2456 scsi_debug_opts);
2457 return sdebug_info;
2458}
2459
2460/* scsi_debug_proc_info
2461 * Used if the driver currently has no own support for /proc/scsi
2462 */
2463static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2464 int length, int inout)
2465{
2466 int len, pos, begin;
2467 int orig_length;
2468
2469 orig_length = length;
2470
2471 if (inout == 1) {
2472 char arr[16];
2473 int minLen = length > 15 ? 15 : length;
2474
2475 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2476 return -EACCES;
2477 memcpy(arr, buffer, minLen);
2478 arr[minLen] = '\0';
2479 if (1 != sscanf(arr, "%d", &pos))
2480 return -EINVAL;
2481 scsi_debug_opts = pos;
2482 if (scsi_debug_every_nth != 0)
2483 scsi_debug_cmnd_count = 0;
2484 return length;
2485 }
2486 begin = 0;
2487 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2488 "%s [%s]\n"
2489 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2490 "every_nth=%d(curr:%d)\n"
2491 "delay=%d, max_luns=%d, scsi_level=%d\n"
2492 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2493 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
2494 "host_resets=%d\n",
2495 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2496 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2497 scsi_debug_cmnd_count, scsi_debug_delay,
2498 scsi_debug_max_luns, scsi_debug_scsi_level,
2499 SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
2500 num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
2501 if (pos < offset) {
2502 len = 0;
2503 begin = pos;
2504 }
2505 *start = buffer + (offset - begin); /* Start of wanted data */
2506 len -= (offset - begin);
2507 if (len > length)
2508 len = length;
2509 return len;
2510}
2511
2512static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2513{
2514 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2515}
2516
2517static ssize_t sdebug_delay_store(struct device_driver * ddp,
2518 const char * buf, size_t count)
2519{
2520 int delay;
2521 char work[20];
2522
2523 if (1 == sscanf(buf, "%10s", work)) {
2524 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2525 scsi_debug_delay = delay;
2526 return count;
2527 }
2528 }
2529 return -EINVAL;
2530}
2531DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2532 sdebug_delay_store);
2533
2534static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2535{
2536 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2537}
2538
2539static ssize_t sdebug_opts_store(struct device_driver * ddp,
2540 const char * buf, size_t count)
2541{
2542 int opts;
2543 char work[20];
2544
2545 if (1 == sscanf(buf, "%10s", work)) {
2546 if (0 == strnicmp(work,"0x", 2)) {
2547 if (1 == sscanf(&work[2], "%x", &opts))
2548 goto opts_done;
2549 } else {
2550 if (1 == sscanf(work, "%d", &opts))
2551 goto opts_done;
2552 }
2553 }
2554 return -EINVAL;
2555opts_done:
2556 scsi_debug_opts = opts;
2557 scsi_debug_cmnd_count = 0;
2558 return count;
2559}
2560DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2561 sdebug_opts_store);
2562
2563static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2564{
2565 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2566}
2567static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2568 const char * buf, size_t count)
2569{
2570 int n;
2571
2572 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2573 scsi_debug_ptype = n;
2574 return count;
2575 }
2576 return -EINVAL;
2577}
2578DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2579
2580static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2581{
2582 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2583}
2584static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2585 const char * buf, size_t count)
2586{
2587 int n;
2588
2589 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2590 scsi_debug_dsense = n;
2591 return count;
2592 }
2593 return -EINVAL;
2594}
2595DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2596 sdebug_dsense_store);
2597
Douglas Gilbert23183912006-09-16 20:30:47 -04002598static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2599{
2600 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2601}
2602static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2603 const char * buf, size_t count)
2604{
2605 int n;
2606
2607 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2608 scsi_debug_fake_rw = n;
2609 return count;
2610 }
2611 return -EINVAL;
2612}
2613DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2614 sdebug_fake_rw_store);
2615
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002616static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2617{
2618 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2619}
2620static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2621 const char * buf, size_t count)
2622{
2623 int n;
2624
2625 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2626 scsi_debug_no_lun_0 = n;
2627 return count;
2628 }
2629 return -EINVAL;
2630}
2631DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2632 sdebug_no_lun_0_store);
2633
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2635{
2636 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2637}
2638static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2639 const char * buf, size_t count)
2640{
2641 int n;
2642
2643 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2644 scsi_debug_num_tgts = n;
2645 sdebug_max_tgts_luns();
2646 return count;
2647 }
2648 return -EINVAL;
2649}
2650DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2651 sdebug_num_tgts_store);
2652
2653static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2654{
2655 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2656}
2657DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2658
2659static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2660{
2661 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2662}
2663DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2664
2665static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2666{
2667 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2668}
2669static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2670 const char * buf, size_t count)
2671{
2672 int nth;
2673
2674 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2675 scsi_debug_every_nth = nth;
2676 scsi_debug_cmnd_count = 0;
2677 return count;
2678 }
2679 return -EINVAL;
2680}
2681DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2682 sdebug_every_nth_store);
2683
2684static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2685{
2686 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2687}
2688static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2689 const char * buf, size_t count)
2690{
2691 int n;
2692
2693 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2694 scsi_debug_max_luns = n;
2695 sdebug_max_tgts_luns();
2696 return count;
2697 }
2698 return -EINVAL;
2699}
2700DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2701 sdebug_max_luns_store);
2702
2703static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
2704{
2705 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
2706}
2707DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
2708
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002709static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2710{
2711 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2712}
2713static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2714 const char * buf, size_t count)
2715{
2716 int n;
2717
2718 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2719 scsi_debug_virtual_gb = n;
2720 if (scsi_debug_virtual_gb > 0) {
2721 sdebug_capacity = 2048 * 1024;
2722 sdebug_capacity *= scsi_debug_virtual_gb;
2723 } else
2724 sdebug_capacity = sdebug_store_sectors;
2725 return count;
2726 }
2727 return -EINVAL;
2728}
2729DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2730 sdebug_virtual_gb_store);
2731
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
2733{
2734 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
2735}
2736
2737static ssize_t sdebug_add_host_store(struct device_driver * ddp,
2738 const char * buf, size_t count)
2739{
2740 int delta_hosts;
2741 char work[20];
2742
2743 if (1 != sscanf(buf, "%10s", work))
2744 return -EINVAL;
2745 { /* temporary hack around sscanf() problem with -ve nums */
2746 int neg = 0;
2747
2748 if ('-' == *work)
2749 neg = 1;
2750 if (1 != sscanf(work + neg, "%d", &delta_hosts))
2751 return -EINVAL;
2752 if (neg)
2753 delta_hosts = -delta_hosts;
2754 }
2755 if (delta_hosts > 0) {
2756 do {
2757 sdebug_add_adapter();
2758 } while (--delta_hosts);
2759 } else if (delta_hosts < 0) {
2760 do {
2761 sdebug_remove_adapter();
2762 } while (++delta_hosts);
2763 }
2764 return count;
2765}
2766DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
2767 sdebug_add_host_store);
2768
Douglas Gilbert23183912006-09-16 20:30:47 -04002769static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
2770 char * buf)
2771{
2772 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
2773}
2774static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
2775 const char * buf, size_t count)
2776{
2777 int n;
2778
2779 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2780 scsi_debug_vpd_use_hostno = n;
2781 return count;
2782 }
2783 return -EINVAL;
2784}
2785DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
2786 sdebug_vpd_use_hostno_store);
2787
2788/* Note: The following function creates attribute files in the
2789 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
2790 files (over those found in the /sys/module/scsi_debug/parameters
2791 directory) is that auxiliary actions can be triggered when an attribute
2792 is changed. For example see: sdebug_add_host_store() above.
2793 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002794static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002796 int ret;
2797
2798 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2799 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
2800 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2801 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2802 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04002803 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002804 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002805 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002806 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002807 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002808 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
2809 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
2810 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04002811 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
2812 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002813 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814}
2815
2816static void do_remove_driverfs_files(void)
2817{
Douglas Gilbert23183912006-09-16 20:30:47 -04002818 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
2819 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
2821 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
2822 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002824 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
2825 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002827 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
2829 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2830 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2831 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
2832 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2833}
2834
2835static int __init scsi_debug_init(void)
2836{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002837 unsigned int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 int host_to_add;
2839 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002840 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841
2842 if (scsi_debug_dev_size_mb < 1)
2843 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002844 sdebug_store_size = (unsigned int)scsi_debug_dev_size_mb * 1048576;
2845 sdebug_store_sectors = sdebug_store_size / SECT_SIZE;
2846 if (scsi_debug_virtual_gb > 0) {
2847 sdebug_capacity = 2048 * 1024;
2848 sdebug_capacity *= scsi_debug_virtual_gb;
2849 } else
2850 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851
2852 /* play around with geometry, don't waste too much on track 0 */
2853 sdebug_heads = 8;
2854 sdebug_sectors_per = 32;
2855 if (scsi_debug_dev_size_mb >= 16)
2856 sdebug_heads = 32;
2857 else if (scsi_debug_dev_size_mb >= 256)
2858 sdebug_heads = 64;
2859 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2860 (sdebug_sectors_per * sdebug_heads);
2861 if (sdebug_cylinders_per >= 1024) {
2862 /* other LLDs do this; implies >= 1GB ram disk ... */
2863 sdebug_heads = 255;
2864 sdebug_sectors_per = 63;
2865 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2866 (sdebug_sectors_per * sdebug_heads);
2867 }
2868
2869 sz = sdebug_store_size;
2870 fake_storep = vmalloc(sz);
2871 if (NULL == fake_storep) {
2872 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
2873 return -ENOMEM;
2874 }
2875 memset(fake_storep, 0, sz);
2876 if (scsi_debug_num_parts > 0)
2877 sdebug_build_parts(fake_storep);
2878
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002879 ret = device_register(&pseudo_primary);
2880 if (ret < 0) {
2881 printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
2882 ret);
2883 goto free_vm;
2884 }
2885 ret = bus_register(&pseudo_lld_bus);
2886 if (ret < 0) {
2887 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
2888 ret);
2889 goto dev_unreg;
2890 }
2891 ret = driver_register(&sdebug_driverfs_driver);
2892 if (ret < 0) {
2893 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
2894 ret);
2895 goto bus_unreg;
2896 }
2897 ret = do_create_driverfs_files();
2898 if (ret < 0) {
2899 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
2900 ret);
2901 goto del_files;
2902 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002904 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 host_to_add = scsi_debug_add_host;
2907 scsi_debug_add_host = 0;
2908
2909 for (k = 0; k < host_to_add; k++) {
2910 if (sdebug_add_adapter()) {
2911 printk(KERN_ERR "scsi_debug_init: "
2912 "sdebug_add_adapter failed k=%d\n", k);
2913 break;
2914 }
2915 }
2916
2917 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
2918 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
2919 scsi_debug_add_host);
2920 }
2921 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002922
2923del_files:
2924 do_remove_driverfs_files();
2925 driver_unregister(&sdebug_driverfs_driver);
2926bus_unreg:
2927 bus_unregister(&pseudo_lld_bus);
2928dev_unreg:
2929 device_unregister(&pseudo_primary);
2930free_vm:
2931 vfree(fake_storep);
2932
2933 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934}
2935
2936static void __exit scsi_debug_exit(void)
2937{
2938 int k = scsi_debug_add_host;
2939
2940 stop_all_queued();
2941 for (; k; k--)
2942 sdebug_remove_adapter();
2943 do_remove_driverfs_files();
2944 driver_unregister(&sdebug_driverfs_driver);
2945 bus_unregister(&pseudo_lld_bus);
2946 device_unregister(&pseudo_primary);
2947
2948 vfree(fake_storep);
2949}
2950
2951device_initcall(scsi_debug_init);
2952module_exit(scsi_debug_exit);
2953
Adrian Bunk52c1da32005-06-23 22:05:33 -07002954static void pseudo_0_release(struct device * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955{
2956 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2957 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
2958}
2959
2960static struct device pseudo_primary = {
2961 .bus_id = "pseudo_0",
2962 .release = pseudo_0_release,
2963};
2964
2965static int pseudo_lld_bus_match(struct device *dev,
2966 struct device_driver *dev_driver)
2967{
2968 return 1;
2969}
2970
2971static struct bus_type pseudo_lld_bus = {
2972 .name = "pseudo",
2973 .match = pseudo_lld_bus_match,
Russell Kingbbbe3a42006-01-05 14:44:46 +00002974 .probe = sdebug_driver_probe,
2975 .remove = sdebug_driver_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976};
2977
2978static void sdebug_release_adapter(struct device * dev)
2979{
2980 struct sdebug_host_info *sdbg_host;
2981
2982 sdbg_host = to_sdebug_host(dev);
2983 kfree(sdbg_host);
2984}
2985
2986static int sdebug_add_adapter(void)
2987{
2988 int k, devs_per_host;
2989 int error = 0;
2990 struct sdebug_host_info *sdbg_host;
2991 struct sdebug_dev_info *sdbg_devinfo;
2992 struct list_head *lh, *lh_sf;
2993
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002994 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 if (NULL == sdbg_host) {
2996 printk(KERN_ERR "%s: out of memory at line %d\n",
2997 __FUNCTION__, __LINE__);
2998 return -ENOMEM;
2999 }
3000
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
3002
3003 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
3004 for (k = 0; k < devs_per_host; k++) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003005 sdbg_devinfo = kzalloc(sizeof(*sdbg_devinfo),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 if (NULL == sdbg_devinfo) {
3007 printk(KERN_ERR "%s: out of memory at line %d\n",
3008 __FUNCTION__, __LINE__);
3009 error = -ENOMEM;
3010 goto clean;
3011 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 sdbg_devinfo->sdbg_host = sdbg_host;
3013 list_add_tail(&sdbg_devinfo->dev_list,
3014 &sdbg_host->dev_info_list);
3015 }
3016
3017 spin_lock(&sdebug_host_list_lock);
3018 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
3019 spin_unlock(&sdebug_host_list_lock);
3020
3021 sdbg_host->dev.bus = &pseudo_lld_bus;
3022 sdbg_host->dev.parent = &pseudo_primary;
3023 sdbg_host->dev.release = &sdebug_release_adapter;
3024 sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host);
3025
3026 error = device_register(&sdbg_host->dev);
3027
3028 if (error)
3029 goto clean;
3030
3031 ++scsi_debug_add_host;
3032 return error;
3033
3034clean:
3035 list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) {
3036 sdbg_devinfo = list_entry(lh, struct sdebug_dev_info,
3037 dev_list);
3038 list_del(&sdbg_devinfo->dev_list);
3039 kfree(sdbg_devinfo);
3040 }
3041
3042 kfree(sdbg_host);
3043 return error;
3044}
3045
3046static void sdebug_remove_adapter(void)
3047{
3048 struct sdebug_host_info * sdbg_host = NULL;
3049
3050 spin_lock(&sdebug_host_list_lock);
3051 if (!list_empty(&sdebug_host_list)) {
3052 sdbg_host = list_entry(sdebug_host_list.prev,
3053 struct sdebug_host_info, host_list);
3054 list_del(&sdbg_host->host_list);
3055 }
3056 spin_unlock(&sdebug_host_list_lock);
3057
3058 if (!sdbg_host)
3059 return;
3060
3061 device_unregister(&sdbg_host->dev);
3062 --scsi_debug_add_host;
3063}
3064
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09003065static struct scsi_host_template sdebug_driver_template = {
3066 .proc_info = scsi_debug_proc_info,
3067 .proc_name = sdebug_proc_name,
3068 .name = "SCSI DEBUG",
3069 .info = scsi_debug_info,
3070 .slave_alloc = scsi_debug_slave_alloc,
3071 .slave_configure = scsi_debug_slave_configure,
3072 .slave_destroy = scsi_debug_slave_destroy,
3073 .ioctl = scsi_debug_ioctl,
3074 .queuecommand = scsi_debug_queuecommand,
3075 .eh_abort_handler = scsi_debug_abort,
3076 .eh_bus_reset_handler = scsi_debug_bus_reset,
3077 .eh_device_reset_handler = scsi_debug_device_reset,
3078 .eh_host_reset_handler = scsi_debug_host_reset,
3079 .bios_param = scsi_debug_biosparam,
3080 .can_queue = SCSI_DEBUG_CANQUEUE,
3081 .this_id = 7,
3082 .sg_tablesize = 256,
3083 .cmd_per_lun = 16,
3084 .max_sectors = 0xffff,
3085 .use_clustering = DISABLE_CLUSTERING,
3086 .module = THIS_MODULE,
3087};
3088
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089static int sdebug_driver_probe(struct device * dev)
3090{
3091 int error = 0;
3092 struct sdebug_host_info *sdbg_host;
3093 struct Scsi_Host *hpnt;
3094
3095 sdbg_host = to_sdebug_host(dev);
3096
3097 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
3098 if (NULL == hpnt) {
3099 printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__);
3100 error = -ENODEV;
3101 return error;
3102 }
3103
3104 sdbg_host->shost = hpnt;
3105 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
3106 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
3107 hpnt->max_id = scsi_debug_num_tgts + 1;
3108 else
3109 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003110 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111
3112 error = scsi_add_host(hpnt, &sdbg_host->dev);
3113 if (error) {
3114 printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
3115 error = -ENODEV;
3116 scsi_host_put(hpnt);
3117 } else
3118 scsi_scan_host(hpnt);
3119
3120
3121 return error;
3122}
3123
3124static int sdebug_driver_remove(struct device * dev)
3125{
3126 struct list_head *lh, *lh_sf;
3127 struct sdebug_host_info *sdbg_host;
3128 struct sdebug_dev_info *sdbg_devinfo;
3129
3130 sdbg_host = to_sdebug_host(dev);
3131
3132 if (!sdbg_host) {
3133 printk(KERN_ERR "%s: Unable to locate host info\n",
3134 __FUNCTION__);
3135 return -ENODEV;
3136 }
3137
3138 scsi_remove_host(sdbg_host->shost);
3139
3140 list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) {
3141 sdbg_devinfo = list_entry(lh, struct sdebug_dev_info,
3142 dev_list);
3143 list_del(&sdbg_devinfo->dev_list);
3144 kfree(sdbg_devinfo);
3145 }
3146
3147 scsi_host_put(sdbg_host->shost);
3148 return 0;
3149}
3150
3151static void sdebug_max_tgts_luns(void)
3152{
3153 struct sdebug_host_info * sdbg_host;
3154 struct Scsi_Host *hpnt;
3155
3156 spin_lock(&sdebug_host_list_lock);
3157 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3158 hpnt = sdbg_host->shost;
3159 if ((hpnt->this_id >= 0) &&
3160 (scsi_debug_num_tgts > hpnt->this_id))
3161 hpnt->max_id = scsi_debug_num_tgts + 1;
3162 else
3163 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003164 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 }
3166 spin_unlock(&sdebug_host_list_lock);
3167}