blob: 681b591fc4c0623ca797b9bbc5d67ea109a058cb [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3 * Copyright (C) 1992 Eric Youngdale
4 * Simulate a host adapter with 2 disks attached. Do a lot of checking
5 * to make sure that we are not getting blocks mixed up, and PANIC if
6 * anything out of the ordinary is seen.
7 * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8 *
9 * This version is more generic, simulating a variable number of disk
Douglas Gilbert23183912006-09-16 20:30:47 -040010 * (or disk like devices) sharing a common amount of RAM. To be more
11 * realistic, the simulated devices have the transport attributes of
12 * SAS disks.
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 *
14 *
15 * For documentation see http://www.torque.net/sg/sdebug26.html
16 *
17 * D. Gilbert (dpg) work for Magneto-Optical device test [20010421]
18 * dpg: work for devfs large number of disks [20010809]
19 * forked for lk 2.5 series [20011216, 20020101]
20 * use vmalloc() more inquiry+mode_sense [20020302]
21 * add timers for delayed responses [20020721]
22 * Patrick Mansfield <patmans@us.ibm.com> max_luns+scsi_level [20021031]
23 * Mike Anderson <andmike@us.ibm.com> sysfs work [20021118]
24 * dpg: change style of boot options to "scsi_debug.num_tgts=2" and
25 * module options to "modprobe scsi_debug num_tgts=2" [20021221]
26 */
27
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/module.h>
29
30#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/errno.h>
32#include <linux/timer.h>
33#include <linux/types.h>
34#include <linux/string.h>
35#include <linux/genhd.h>
36#include <linux/fs.h>
37#include <linux/init.h>
38#include <linux/proc_fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <linux/vmalloc.h>
40#include <linux/moduleparam.h>
Jens Axboe852e0342007-07-16 10:19:24 +020041#include <linux/scatterlist.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <linux/blkdev.h>
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090043
44#include <scsi/scsi.h>
45#include <scsi/scsi_cmnd.h>
46#include <scsi/scsi_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <scsi/scsi_host.h>
48#include <scsi/scsicam.h>
49
50#include <linux/stat.h>
51
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include "scsi_logging.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050054#define SCSI_DEBUG_VERSION "1.81"
55static const char * scsi_debug_version_date = "20070104";
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050057/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040058#define NO_ADDITIONAL_SENSE 0x0
59#define LOGICAL_UNIT_NOT_READY 0x4
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040061#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#define INVALID_OPCODE 0x20
63#define ADDR_OUT_OF_RANGE 0x21
64#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040065#define INVALID_FIELD_IN_PARAM_LIST 0x26
Linus Torvalds1da177e2005-04-16 15:20:36 -070066#define POWERON_RESET 0x29
67#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050068#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040069#define THRESHOLD_EXCEEDED 0x5d
70#define LOW_POWER_COND_ON 0x5e
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050072/* Additional Sense Code Qualifier (ASCQ) */
73#define ACK_NAK_TO 0x3
74
Linus Torvalds1da177e2005-04-16 15:20:36 -070075#define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
76
77/* Default values for driver parameters */
78#define DEF_NUM_HOST 1
79#define DEF_NUM_TGTS 1
80#define DEF_MAX_LUNS 1
81/* With these defaults, this driver will make 1 host with 1 target
82 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
83 */
84#define DEF_DELAY 1
85#define DEF_DEV_SIZE_MB 8
86#define DEF_EVERY_NTH 0
87#define DEF_NUM_PARTS 0
88#define DEF_OPTS 0
89#define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */
90#define DEF_PTYPE 0
91#define DEF_D_SENSE 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -040092#define DEF_NO_LUN_0 0
93#define DEF_VIRTUAL_GB 0
Douglas Gilbert23183912006-09-16 20:30:47 -040094#define DEF_FAKE_RW 0
95#define DEF_VPD_USE_HOSTNO 1
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
97/* bit mask values for scsi_debug_opts */
98#define SCSI_DEBUG_OPT_NOISE 1
99#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
100#define SCSI_DEBUG_OPT_TIMEOUT 4
101#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500102#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103/* When "every_nth" > 0 then modulo "every_nth" commands:
104 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
105 * - a RECOVERED_ERROR is simulated on successful read and write
106 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500107 * - a TRANSPORT_ERROR is simulated on successful read and write
108 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 *
110 * When "every_nth" < 0 then after "- every_nth" commands:
111 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
112 * - a RECOVERED_ERROR is simulated on successful read and write
113 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500114 * - a TRANSPORT_ERROR is simulated on successful read and write
115 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 * This will continue until some other action occurs (e.g. the user
117 * writing a new value (other than -1 or 1) to every_nth via sysfs).
118 */
119
120/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
121 * sector on read commands: */
122#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
123
124/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
125 * or "peripheral device" addressing (value 0) */
126#define SAM2_LUN_ADDRESS_METHOD 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400127#define SAM2_WLUN_REPORT_LUNS 0xc101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128
129static int scsi_debug_add_host = DEF_NUM_HOST;
130static int scsi_debug_delay = DEF_DELAY;
131static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
132static int scsi_debug_every_nth = DEF_EVERY_NTH;
133static int scsi_debug_max_luns = DEF_MAX_LUNS;
134static int scsi_debug_num_parts = DEF_NUM_PARTS;
135static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
136static int scsi_debug_opts = DEF_OPTS;
137static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
138static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
139static int scsi_debug_dsense = DEF_D_SENSE;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400140static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
141static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
Douglas Gilbert23183912006-09-16 20:30:47 -0400142static int scsi_debug_fake_rw = DEF_FAKE_RW;
143static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
145static int scsi_debug_cmnd_count = 0;
146
147#define DEV_READONLY(TGT) (0)
148#define DEV_REMOVEABLE(TGT) (0)
149
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400150static unsigned int sdebug_store_size; /* in bytes */
151static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152static sector_t sdebug_capacity; /* in sectors */
153
154/* old BIOS stuff, kernel may get rid of them but some mode sense pages
155 may still need them */
156static int sdebug_heads; /* heads per disk */
157static int sdebug_cylinders_per; /* cylinders per surface */
158static int sdebug_sectors_per; /* sectors per cylinder */
159
160/* default sector size is 512 bytes, 2**9 bytes */
161#define POW2_SECT_SIZE 9
162#define SECT_SIZE (1 << POW2_SECT_SIZE)
163#define SECT_SIZE_PER(TGT) SECT_SIZE
164
165#define SDEBUG_MAX_PARTS 4
166
167#define SDEBUG_SENSE_LEN 32
168
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +0900169#define SCSI_DEBUG_CANQUEUE 255
170#define SCSI_DEBUG_MAX_CMD_LEN 16
171
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172struct sdebug_dev_info {
173 struct list_head dev_list;
174 unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */
175 unsigned int channel;
176 unsigned int target;
177 unsigned int lun;
178 struct sdebug_host_info *sdbg_host;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400179 unsigned int wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 char reset;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400181 char stopped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 char used;
183};
184
185struct sdebug_host_info {
186 struct list_head host_list;
187 struct Scsi_Host *shost;
188 struct device dev;
189 struct list_head dev_info_list;
190};
191
192#define to_sdebug_host(d) \
193 container_of(d, struct sdebug_host_info, dev)
194
195static LIST_HEAD(sdebug_host_list);
196static DEFINE_SPINLOCK(sdebug_host_list_lock);
197
198typedef void (* done_funct_t) (struct scsi_cmnd *);
199
200struct sdebug_queued_cmd {
201 int in_use;
202 struct timer_list cmnd_timer;
203 done_funct_t done_funct;
204 struct scsi_cmnd * a_cmnd;
205 int scsi_result;
206};
207static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
208
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209static unsigned char * fake_storep; /* ramdisk storage */
210
211static int num_aborts = 0;
212static int num_dev_resets = 0;
213static int num_bus_resets = 0;
214static int num_host_resets = 0;
215
216static DEFINE_SPINLOCK(queued_arr_lock);
217static DEFINE_RWLOCK(atomic_rw);
218
219static char sdebug_proc_name[] = "scsi_debug";
220
221static int sdebug_driver_probe(struct device *);
222static int sdebug_driver_remove(struct device *);
223static struct bus_type pseudo_lld_bus;
224
225static struct device_driver sdebug_driverfs_driver = {
226 .name = sdebug_proc_name,
227 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228};
229
230static const int check_condition_result =
231 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
232
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400233static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
234 0, 0, 0x2, 0x4b};
235static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
236 0, 0, 0x0, 0x0};
237
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238/* function declarations */
239static int resp_inquiry(struct scsi_cmnd * SCpnt, int target,
240 struct sdebug_dev_info * devip);
241static int resp_requests(struct scsi_cmnd * SCpnt,
242 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400243static int resp_start_stop(struct scsi_cmnd * scp,
244 struct sdebug_dev_info * devip);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200245static int resp_report_tgtpgs(struct scsi_cmnd * scp,
246 struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247static int resp_readcap(struct scsi_cmnd * SCpnt,
248 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400249static int resp_readcap16(struct scsi_cmnd * SCpnt,
250 struct sdebug_dev_info * devip);
251static int resp_mode_sense(struct scsi_cmnd * scp, int target,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400253static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
254 struct sdebug_dev_info * devip);
255static int resp_log_sense(struct scsi_cmnd * scp,
256 struct sdebug_dev_info * devip);
257static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
258 unsigned int num, struct sdebug_dev_info * devip);
259static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
260 unsigned int num, struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261static int resp_report_luns(struct scsi_cmnd * SCpnt,
262 struct sdebug_dev_info * devip);
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900263static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
264 unsigned int num, struct sdebug_dev_info *devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
266 int arr_len);
267static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
268 int max_arr_len);
269static void timer_intr_handler(unsigned long);
270static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev);
271static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
272 int asc, int asq);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400273static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
274 struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275static int schedule_resp(struct scsi_cmnd * cmnd,
276 struct sdebug_dev_info * devip,
277 done_funct_t done, int scsi_result, int delta_jiff);
278static void __init sdebug_build_parts(unsigned char * ramp);
279static void __init init_all_queued(void);
280static void stop_all_queued(void);
281static int stop_queued_cmnd(struct scsi_cmnd * cmnd);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200282static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
283 int target_dev_id, int dev_id_num,
284 const char * dev_id_str, int dev_id_str_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400285static int inquiry_evpd_88(unsigned char * arr, int target_dev_id);
Randy Dunlap6ecaff72006-07-11 20:53:22 -0700286static int do_create_driverfs_files(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287static void do_remove_driverfs_files(void);
288
289static int sdebug_add_adapter(void);
290static void sdebug_remove_adapter(void);
291static void sdebug_max_tgts_luns(void);
292
293static struct device pseudo_primary;
294static struct bus_type pseudo_lld_bus;
295
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900296static void get_data_transfer_info(unsigned char *cmd,
297 unsigned long long *lba, unsigned int *num)
298{
299 int i;
300
301 switch (*cmd) {
302 case WRITE_16:
303 case READ_16:
304 for (*lba = 0, i = 0; i < 8; ++i) {
305 if (i > 0)
306 *lba <<= 8;
307 *lba += cmd[2 + i];
308 }
309 *num = cmd[13] + (cmd[12] << 8) +
310 (cmd[11] << 16) + (cmd[10] << 24);
311 break;
312 case WRITE_12:
313 case READ_12:
314 *lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
315 *num = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
316 break;
317 case WRITE_10:
318 case READ_10:
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900319 case XDWRITEREAD_10:
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900320 *lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
321 *num = cmd[8] + (cmd[7] << 8);
322 break;
323 case WRITE_6:
324 case READ_6:
325 *lba = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
326 *num = (0 == cmd[4]) ? 256 : cmd[4];
327 break;
328 default:
329 break;
330 }
331}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
333static
334int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
335{
336 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900337 int len, k;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400338 unsigned int num;
339 unsigned long long lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 int errsts = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400341 int target = SCpnt->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 struct sdebug_dev_info * devip = NULL;
343 int inj_recovered = 0;
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500344 int inj_transport = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400345 int delay_override = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
Boaz Harroshc73961e2007-09-07 06:50:20 +0900347 scsi_set_resid(SCpnt, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
349 printk(KERN_INFO "scsi_debug: cmd ");
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400350 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 printk("%02x ", (int)cmd[k]);
352 printk("\n");
353 }
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +0900354
355 if (target == SCpnt->device->host->hostt->this_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 printk(KERN_INFO "scsi_debug: initiator's id used as "
357 "target!\n");
358 return schedule_resp(SCpnt, NULL, done,
359 DID_NO_CONNECT << 16, 0);
360 }
361
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400362 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
363 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 return schedule_resp(SCpnt, NULL, done,
365 DID_NO_CONNECT << 16, 0);
366 devip = devInfoReg(SCpnt->device);
367 if (NULL == devip)
368 return schedule_resp(SCpnt, NULL, done,
369 DID_NO_CONNECT << 16, 0);
370
371 if ((scsi_debug_every_nth != 0) &&
372 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
373 scsi_debug_cmnd_count = 0;
374 if (scsi_debug_every_nth < -1)
375 scsi_debug_every_nth = -1;
376 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
377 return 0; /* ignore command causing timeout */
378 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
379 inj_recovered = 1; /* to reads and writes below */
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500380 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
381 inj_transport = 1; /* to reads and writes below */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 }
383
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400384 if (devip->wlun) {
385 switch (*cmd) {
386 case INQUIRY:
387 case REQUEST_SENSE:
388 case TEST_UNIT_READY:
389 case REPORT_LUNS:
390 break; /* only allowable wlun commands */
391 default:
392 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
393 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
394 "not supported for wlun\n", *cmd);
395 mk_sense_buffer(devip, ILLEGAL_REQUEST,
396 INVALID_OPCODE, 0);
397 errsts = check_condition_result;
398 return schedule_resp(SCpnt, devip, done, errsts,
399 0);
400 }
401 }
402
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 switch (*cmd) {
404 case INQUIRY: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400405 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 errsts = resp_inquiry(SCpnt, target, devip);
407 break;
408 case REQUEST_SENSE: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400409 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 errsts = resp_requests(SCpnt, devip);
411 break;
412 case REZERO_UNIT: /* actually this is REWIND for SSC */
413 case START_STOP:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400414 errsts = resp_start_stop(SCpnt, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 break;
416 case ALLOW_MEDIUM_REMOVAL:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400417 if ((errsts = check_readiness(SCpnt, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 break;
419 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
420 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
421 cmd[4] ? "inhibited" : "enabled");
422 break;
423 case SEND_DIAGNOSTIC: /* mandatory */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400424 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 break;
426 case TEST_UNIT_READY: /* mandatory */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400427 delay_override = 1;
428 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 break;
430 case RESERVE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400431 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 break;
433 case RESERVE_10:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400434 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 break;
436 case RELEASE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400437 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 break;
439 case RELEASE_10:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400440 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 break;
442 case READ_CAPACITY:
443 errsts = resp_readcap(SCpnt, devip);
444 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400445 case SERVICE_ACTION_IN:
446 if (SAI_READ_CAPACITY_16 != cmd[1]) {
447 mk_sense_buffer(devip, ILLEGAL_REQUEST,
448 INVALID_OPCODE, 0);
449 errsts = check_condition_result;
450 break;
451 }
452 errsts = resp_readcap16(SCpnt, devip);
453 break;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200454 case MAINTENANCE_IN:
455 if (MI_REPORT_TARGET_PGS != cmd[1]) {
456 mk_sense_buffer(devip, ILLEGAL_REQUEST,
457 INVALID_OPCODE, 0);
458 errsts = check_condition_result;
459 break;
460 }
461 errsts = resp_report_tgtpgs(SCpnt, devip);
462 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 case READ_16:
464 case READ_12:
465 case READ_10:
466 case READ_6:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400467 if ((errsts = check_readiness(SCpnt, 0, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 break;
Douglas Gilbert23183912006-09-16 20:30:47 -0400469 if (scsi_debug_fake_rw)
470 break;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900471 get_data_transfer_info(cmd, &lba, &num);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400472 errsts = resp_read(SCpnt, lba, num, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 if (inj_recovered && (0 == errsts)) {
474 mk_sense_buffer(devip, RECOVERED_ERROR,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400475 THRESHOLD_EXCEEDED, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 errsts = check_condition_result;
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500477 } else if (inj_transport && (0 == errsts)) {
478 mk_sense_buffer(devip, ABORTED_COMMAND,
479 TRANSPORT_PROBLEM, ACK_NAK_TO);
480 errsts = check_condition_result;
481 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 break;
483 case REPORT_LUNS: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400484 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 errsts = resp_report_luns(SCpnt, devip);
486 break;
487 case VERIFY: /* 10 byte SBC-2 command */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400488 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 break;
490 case WRITE_16:
491 case WRITE_12:
492 case WRITE_10:
493 case WRITE_6:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400494 if ((errsts = check_readiness(SCpnt, 0, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 break;
Douglas Gilbert23183912006-09-16 20:30:47 -0400496 if (scsi_debug_fake_rw)
497 break;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900498 get_data_transfer_info(cmd, &lba, &num);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400499 errsts = resp_write(SCpnt, lba, num, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 if (inj_recovered && (0 == errsts)) {
501 mk_sense_buffer(devip, RECOVERED_ERROR,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400502 THRESHOLD_EXCEEDED, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 errsts = check_condition_result;
504 }
505 break;
506 case MODE_SENSE:
507 case MODE_SENSE_10:
508 errsts = resp_mode_sense(SCpnt, target, devip);
509 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400510 case MODE_SELECT:
511 errsts = resp_mode_select(SCpnt, 1, devip);
512 break;
513 case MODE_SELECT_10:
514 errsts = resp_mode_select(SCpnt, 0, devip);
515 break;
516 case LOG_SENSE:
517 errsts = resp_log_sense(SCpnt, devip);
518 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 case SYNCHRONIZE_CACHE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400520 delay_override = 1;
521 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 break;
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500523 case WRITE_BUFFER:
524 errsts = check_readiness(SCpnt, 1, devip);
525 break;
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900526 case XDWRITEREAD_10:
527 if (!scsi_bidi_cmnd(SCpnt)) {
528 mk_sense_buffer(devip, ILLEGAL_REQUEST,
529 INVALID_FIELD_IN_CDB, 0);
530 errsts = check_condition_result;
531 break;
532 }
533
534 errsts = check_readiness(SCpnt, 0, devip);
535 if (errsts)
536 break;
537 if (scsi_debug_fake_rw)
538 break;
539 get_data_transfer_info(cmd, &lba, &num);
540 errsts = resp_read(SCpnt, lba, num, devip);
541 if (errsts)
542 break;
543 errsts = resp_write(SCpnt, lba, num, devip);
544 if (errsts)
545 break;
546 errsts = resp_xdwriteread(SCpnt, lba, num, devip);
547 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 default:
549 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
550 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
551 "supported\n", *cmd);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400552 if ((errsts = check_readiness(SCpnt, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 break; /* Unit attention takes precedence */
554 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
555 errsts = check_condition_result;
556 break;
557 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400558 return schedule_resp(SCpnt, devip, done, errsts,
559 (delay_override ? 0 : scsi_debug_delay));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560}
561
562static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
563{
564 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
565 printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
566 }
567 return -EINVAL;
568 /* return -ENOTTY; // correct return but upsets fdisk */
569}
570
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400571static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
572 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573{
574 if (devip->reset) {
575 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
576 printk(KERN_INFO "scsi_debug: Reporting Unit "
577 "attention: power on reset\n");
578 devip->reset = 0;
579 mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
580 return check_condition_result;
581 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400582 if ((0 == reset_only) && devip->stopped) {
583 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
584 printk(KERN_INFO "scsi_debug: Reporting Not "
585 "ready: initializing command required\n");
586 mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
587 0x2);
588 return check_condition_result;
589 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 return 0;
591}
592
593/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900594static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 int arr_len)
596{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900597 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900598 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900600 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900602 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 return (DID_ERROR << 16);
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900604
605 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
606 arr, arr_len);
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900607 if (sdb->resid)
608 sdb->resid -= act_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400609 else
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900610 sdb->resid = scsi_bufflen(scp) - act_len;
611
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 return 0;
613}
614
615/* Returns number of bytes fetched into 'arr' or -1 if error. */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900616static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
617 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900619 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900621 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900623
624 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625}
626
627
628static const char * inq_vendor_id = "Linux ";
629static const char * inq_product_id = "scsi_debug ";
630static const char * inq_product_rev = "0004";
631
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200632static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
633 int target_dev_id, int dev_id_num,
634 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400635 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400637 int num, port_a;
638 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400640 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 /* T10 vendor identifier field format (faked) */
642 arr[0] = 0x2; /* ASCII */
643 arr[1] = 0x1;
644 arr[2] = 0x0;
645 memcpy(&arr[4], inq_vendor_id, 8);
646 memcpy(&arr[12], inq_product_id, 16);
647 memcpy(&arr[28], dev_id_str, dev_id_str_len);
648 num = 8 + 16 + dev_id_str_len;
649 arr[3] = num;
650 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400651 if (dev_id_num >= 0) {
652 /* NAA-5, Logical unit identifier (binary) */
653 arr[num++] = 0x1; /* binary (not necessarily sas) */
654 arr[num++] = 0x3; /* PIV=0, lu, naa */
655 arr[num++] = 0x0;
656 arr[num++] = 0x8;
657 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
658 arr[num++] = 0x33;
659 arr[num++] = 0x33;
660 arr[num++] = 0x30;
661 arr[num++] = (dev_id_num >> 24);
662 arr[num++] = (dev_id_num >> 16) & 0xff;
663 arr[num++] = (dev_id_num >> 8) & 0xff;
664 arr[num++] = dev_id_num & 0xff;
665 /* Target relative port number */
666 arr[num++] = 0x61; /* proto=sas, binary */
667 arr[num++] = 0x94; /* PIV=1, target port, rel port */
668 arr[num++] = 0x0; /* reserved */
669 arr[num++] = 0x4; /* length */
670 arr[num++] = 0x0; /* reserved */
671 arr[num++] = 0x0; /* reserved */
672 arr[num++] = 0x0;
673 arr[num++] = 0x1; /* relative port A */
674 }
675 /* NAA-5, Target port identifier */
676 arr[num++] = 0x61; /* proto=sas, binary */
677 arr[num++] = 0x93; /* piv=1, target port, naa */
678 arr[num++] = 0x0;
679 arr[num++] = 0x8;
680 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
681 arr[num++] = 0x22;
682 arr[num++] = 0x22;
683 arr[num++] = 0x20;
684 arr[num++] = (port_a >> 24);
685 arr[num++] = (port_a >> 16) & 0xff;
686 arr[num++] = (port_a >> 8) & 0xff;
687 arr[num++] = port_a & 0xff;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200688 /* NAA-5, Target port group identifier */
689 arr[num++] = 0x61; /* proto=sas, binary */
690 arr[num++] = 0x95; /* piv=1, target port group id */
691 arr[num++] = 0x0;
692 arr[num++] = 0x4;
693 arr[num++] = 0;
694 arr[num++] = 0;
695 arr[num++] = (port_group_id >> 8) & 0xff;
696 arr[num++] = port_group_id & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400697 /* NAA-5, Target device identifier */
698 arr[num++] = 0x61; /* proto=sas, binary */
699 arr[num++] = 0xa3; /* piv=1, target device, naa */
700 arr[num++] = 0x0;
701 arr[num++] = 0x8;
702 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
703 arr[num++] = 0x22;
704 arr[num++] = 0x22;
705 arr[num++] = 0x20;
706 arr[num++] = (target_dev_id >> 24);
707 arr[num++] = (target_dev_id >> 16) & 0xff;
708 arr[num++] = (target_dev_id >> 8) & 0xff;
709 arr[num++] = target_dev_id & 0xff;
710 /* SCSI name string: Target device identifier */
711 arr[num++] = 0x63; /* proto=sas, UTF-8 */
712 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
713 arr[num++] = 0x0;
714 arr[num++] = 24;
715 memcpy(arr + num, "naa.52222220", 12);
716 num += 12;
717 snprintf(b, sizeof(b), "%08X", target_dev_id);
718 memcpy(arr + num, b, 8);
719 num += 8;
720 memset(arr + num, 0, 4);
721 num += 4;
722 return num;
723}
724
725
726static unsigned char vpd84_data[] = {
727/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
728 0x22,0x22,0x22,0x0,0xbb,0x1,
729 0x22,0x22,0x22,0x0,0xbb,0x2,
730};
731
732static int inquiry_evpd_84(unsigned char * arr)
733{
734 memcpy(arr, vpd84_data, sizeof(vpd84_data));
735 return sizeof(vpd84_data);
736}
737
738static int inquiry_evpd_85(unsigned char * arr)
739{
740 int num = 0;
741 const char * na1 = "https://www.kernel.org/config";
742 const char * na2 = "http://www.kernel.org/log";
743 int plen, olen;
744
745 arr[num++] = 0x1; /* lu, storage config */
746 arr[num++] = 0x0; /* reserved */
747 arr[num++] = 0x0;
748 olen = strlen(na1);
749 plen = olen + 1;
750 if (plen % 4)
751 plen = ((plen / 4) + 1) * 4;
752 arr[num++] = plen; /* length, null termianted, padded */
753 memcpy(arr + num, na1, olen);
754 memset(arr + num + olen, 0, plen - olen);
755 num += plen;
756
757 arr[num++] = 0x4; /* lu, logging */
758 arr[num++] = 0x0; /* reserved */
759 arr[num++] = 0x0;
760 olen = strlen(na2);
761 plen = olen + 1;
762 if (plen % 4)
763 plen = ((plen / 4) + 1) * 4;
764 arr[num++] = plen; /* length, null terminated, padded */
765 memcpy(arr + num, na2, olen);
766 memset(arr + num + olen, 0, plen - olen);
767 num += plen;
768
769 return num;
770}
771
772/* SCSI ports VPD page */
773static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
774{
775 int num = 0;
776 int port_a, port_b;
777
778 port_a = target_dev_id + 1;
779 port_b = port_a + 1;
780 arr[num++] = 0x0; /* reserved */
781 arr[num++] = 0x0; /* reserved */
782 arr[num++] = 0x0;
783 arr[num++] = 0x1; /* relative port 1 (primary) */
784 memset(arr + num, 0, 6);
785 num += 6;
786 arr[num++] = 0x0;
787 arr[num++] = 12; /* length tp descriptor */
788 /* naa-5 target port identifier (A) */
789 arr[num++] = 0x61; /* proto=sas, binary */
790 arr[num++] = 0x93; /* PIV=1, target port, NAA */
791 arr[num++] = 0x0; /* reserved */
792 arr[num++] = 0x8; /* length */
793 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
794 arr[num++] = 0x22;
795 arr[num++] = 0x22;
796 arr[num++] = 0x20;
797 arr[num++] = (port_a >> 24);
798 arr[num++] = (port_a >> 16) & 0xff;
799 arr[num++] = (port_a >> 8) & 0xff;
800 arr[num++] = port_a & 0xff;
801
802 arr[num++] = 0x0; /* reserved */
803 arr[num++] = 0x0; /* reserved */
804 arr[num++] = 0x0;
805 arr[num++] = 0x2; /* relative port 2 (secondary) */
806 memset(arr + num, 0, 6);
807 num += 6;
808 arr[num++] = 0x0;
809 arr[num++] = 12; /* length tp descriptor */
810 /* naa-5 target port identifier (B) */
811 arr[num++] = 0x61; /* proto=sas, binary */
812 arr[num++] = 0x93; /* PIV=1, target port, NAA */
813 arr[num++] = 0x0; /* reserved */
814 arr[num++] = 0x8; /* length */
815 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
816 arr[num++] = 0x22;
817 arr[num++] = 0x22;
818 arr[num++] = 0x20;
819 arr[num++] = (port_b >> 24);
820 arr[num++] = (port_b >> 16) & 0xff;
821 arr[num++] = (port_b >> 8) & 0xff;
822 arr[num++] = port_b & 0xff;
823
824 return num;
825}
826
827
828static unsigned char vpd89_data[] = {
829/* from 4th byte */ 0,0,0,0,
830'l','i','n','u','x',' ',' ',' ',
831'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
832'1','2','3','4',
8330x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
8340xec,0,0,0,
8350x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
8360,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
8370x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
8380x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
8390x53,0x41,
8400x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
8410x20,0x20,
8420x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
8430x10,0x80,
8440,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
8450x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
8460x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
8470,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
8480x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
8490x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
8500,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
8510,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8520,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8530,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8540x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
8550,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
8560xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
8570,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
8580,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8590,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8600,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8610,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8620,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8630,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8640,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8650,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8660,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8670,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8680,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8690,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
870};
871
872static int inquiry_evpd_89(unsigned char * arr)
873{
874 memcpy(arr, vpd89_data, sizeof(vpd89_data));
875 return sizeof(vpd89_data);
876}
877
878
879static unsigned char vpdb0_data[] = {
880 /* from 4th byte */ 0,0,0,4,
881 0,0,0x4,0,
882 0,0,0,64,
883};
884
885static int inquiry_evpd_b0(unsigned char * arr)
886{
887 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
888 if (sdebug_store_sectors > 0x400) {
889 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
890 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
891 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
892 arr[7] = sdebug_store_sectors & 0xff;
893 }
894 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895}
896
897
898#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400899#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900
901static int resp_inquiry(struct scsi_cmnd * scp, int target,
902 struct sdebug_dev_info * devip)
903{
904 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200905 unsigned char * arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 unsigned char *cmd = (unsigned char *)scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200907 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908
909 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500910 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
911 if (! arr)
912 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400913 if (devip->wlun)
914 pq_pdt = 0x1e; /* present, wlun */
915 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
916 pq_pdt = 0x7f; /* not present, no device type */
917 else
918 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 arr[0] = pq_pdt;
920 if (0x2 & cmd[1]) { /* CMDDT bit set */
921 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
922 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200923 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 return check_condition_result;
925 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200926 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400927 char lu_id_str[6];
928 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200930 port_group_id = (((host_no + 1) & 0x7f) << 8) +
931 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -0400932 if (0 == scsi_debug_vpd_use_hostno)
933 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400934 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
935 (devip->target * 1000) + devip->lun);
936 target_dev_id = ((host_no + 1) * 2000) +
937 (devip->target * 1000) - 3;
938 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400940 arr[1] = cmd[2]; /*sanity */
941 n = 4;
942 arr[n++] = 0x0; /* this page */
943 arr[n++] = 0x80; /* unit serial number */
944 arr[n++] = 0x83; /* device identification */
945 arr[n++] = 0x84; /* software interface ident. */
946 arr[n++] = 0x85; /* management network addresses */
947 arr[n++] = 0x86; /* extended inquiry */
948 arr[n++] = 0x87; /* mode page policy */
949 arr[n++] = 0x88; /* SCSI ports */
950 arr[n++] = 0x89; /* ATA information */
951 arr[n++] = 0xb0; /* Block limits (SBC) */
952 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400954 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400956 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400958 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200959 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
960 target_dev_id, lu_id_num,
961 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400962 } else if (0x84 == cmd[2]) { /* Software interface ident. */
963 arr[1] = cmd[2]; /*sanity */
964 arr[3] = inquiry_evpd_84(&arr[4]);
965 } else if (0x85 == cmd[2]) { /* Management network addresses */
966 arr[1] = cmd[2]; /*sanity */
967 arr[3] = inquiry_evpd_85(&arr[4]);
968 } else if (0x86 == cmd[2]) { /* extended inquiry */
969 arr[1] = cmd[2]; /*sanity */
970 arr[3] = 0x3c; /* number of following entries */
971 arr[4] = 0x0; /* no protection stuff */
972 arr[5] = 0x7; /* head of q, ordered + simple q's */
973 } else if (0x87 == cmd[2]) { /* mode page policy */
974 arr[1] = cmd[2]; /*sanity */
975 arr[3] = 0x8; /* number of following entries */
976 arr[4] = 0x2; /* disconnect-reconnect mp */
977 arr[6] = 0x80; /* mlus, shared */
978 arr[8] = 0x18; /* protocol specific lu */
979 arr[10] = 0x82; /* mlus, per initiator port */
980 } else if (0x88 == cmd[2]) { /* SCSI Ports */
981 arr[1] = cmd[2]; /*sanity */
982 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
983 } else if (0x89 == cmd[2]) { /* ATA information */
984 arr[1] = cmd[2]; /*sanity */
985 n = inquiry_evpd_89(&arr[4]);
986 arr[2] = (n >> 8);
987 arr[3] = (n & 0xff);
988 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
989 arr[1] = cmd[2]; /*sanity */
990 arr[3] = inquiry_evpd_b0(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 } else {
992 /* Illegal request, invalid field in cdb */
993 mk_sense_buffer(devip, ILLEGAL_REQUEST,
994 INVALID_FIELD_IN_CDB, 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200995 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 return check_condition_result;
997 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400998 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200999 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001000 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001001 kfree(arr);
1002 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 }
1004 /* drops through here for a standard inquiry */
1005 arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
1006 arr[2] = scsi_debug_scsi_level;
1007 arr[3] = 2; /* response_data_format==2 */
1008 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001009 if (0 == scsi_debug_vpd_use_hostno)
1010 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001011 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001013 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 memcpy(&arr[8], inq_vendor_id, 8);
1015 memcpy(&arr[16], inq_product_id, 16);
1016 memcpy(&arr[32], inq_product_rev, 4);
1017 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001018 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
1019 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
1020 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001022 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001024 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001026 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001027 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001029 kfree(arr);
1030 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031}
1032
1033static int resp_requests(struct scsi_cmnd * scp,
1034 struct sdebug_dev_info * devip)
1035{
1036 unsigned char * sbuff;
1037 unsigned char *cmd = (unsigned char *)scp->cmnd;
1038 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001039 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 int len = 18;
1041
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001042 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001044 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
1045 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001047 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1048 if (want_dsense) {
1049 arr[0] = 0x72;
1050 arr[1] = 0x0; /* NO_SENSE in sense_key */
1051 arr[2] = THRESHOLD_EXCEEDED;
1052 arr[3] = 0xff; /* TEST set and MRIE==6 */
1053 } else {
1054 arr[0] = 0x70;
1055 arr[2] = 0x0; /* NO_SENSE in sense_key */
1056 arr[7] = 0xa; /* 18 byte sense buffer */
1057 arr[12] = THRESHOLD_EXCEEDED;
1058 arr[13] = 0xff; /* TEST set and MRIE==6 */
1059 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001060 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001062 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
1063 /* DESC bit set and sense_buff in fixed format */
1064 memset(arr, 0, sizeof(arr));
1065 arr[0] = 0x72;
1066 arr[1] = sbuff[2]; /* sense key */
1067 arr[2] = sbuff[12]; /* asc */
1068 arr[3] = sbuff[13]; /* ascq */
1069 len = 8;
1070 }
1071 }
1072 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 return fill_from_dev_buffer(scp, arr, len);
1074}
1075
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001076static int resp_start_stop(struct scsi_cmnd * scp,
1077 struct sdebug_dev_info * devip)
1078{
1079 unsigned char *cmd = (unsigned char *)scp->cmnd;
1080 int power_cond, errsts, start;
1081
1082 if ((errsts = check_readiness(scp, 1, devip)))
1083 return errsts;
1084 power_cond = (cmd[4] & 0xf0) >> 4;
1085 if (power_cond) {
1086 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1087 0);
1088 return check_condition_result;
1089 }
1090 start = cmd[4] & 1;
1091 if (start == devip->stopped)
1092 devip->stopped = !start;
1093 return 0;
1094}
1095
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096#define SDEBUG_READCAP_ARR_SZ 8
1097static int resp_readcap(struct scsi_cmnd * scp,
1098 struct sdebug_dev_info * devip)
1099{
1100 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001101 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 int errsts;
1103
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001104 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001106 /* following just in case virtual_gb changed */
1107 if (scsi_debug_virtual_gb > 0) {
1108 sdebug_capacity = 2048 * 1024;
1109 sdebug_capacity *= scsi_debug_virtual_gb;
1110 } else
1111 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001113 if (sdebug_capacity < 0xffffffff) {
1114 capac = (unsigned int)sdebug_capacity - 1;
1115 arr[0] = (capac >> 24);
1116 arr[1] = (capac >> 16) & 0xff;
1117 arr[2] = (capac >> 8) & 0xff;
1118 arr[3] = capac & 0xff;
1119 } else {
1120 arr[0] = 0xff;
1121 arr[1] = 0xff;
1122 arr[2] = 0xff;
1123 arr[3] = 0xff;
1124 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1126 arr[7] = SECT_SIZE_PER(target) & 0xff;
1127 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1128}
1129
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001130#define SDEBUG_READCAP16_ARR_SZ 32
1131static int resp_readcap16(struct scsi_cmnd * scp,
1132 struct sdebug_dev_info * devip)
1133{
1134 unsigned char *cmd = (unsigned char *)scp->cmnd;
1135 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1136 unsigned long long capac;
1137 int errsts, k, alloc_len;
1138
1139 if ((errsts = check_readiness(scp, 1, devip)))
1140 return errsts;
1141 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1142 + cmd[13]);
1143 /* following just in case virtual_gb changed */
1144 if (scsi_debug_virtual_gb > 0) {
1145 sdebug_capacity = 2048 * 1024;
1146 sdebug_capacity *= scsi_debug_virtual_gb;
1147 } else
1148 sdebug_capacity = sdebug_store_sectors;
1149 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1150 capac = sdebug_capacity - 1;
1151 for (k = 0; k < 8; ++k, capac >>= 8)
1152 arr[7 - k] = capac & 0xff;
1153 arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff;
1154 arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff;
1155 arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1156 arr[11] = SECT_SIZE_PER(target) & 0xff;
1157 return fill_from_dev_buffer(scp, arr,
1158 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1159}
1160
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001161#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1162
1163static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1164 struct sdebug_dev_info * devip)
1165{
1166 unsigned char *cmd = (unsigned char *)scp->cmnd;
1167 unsigned char * arr;
1168 int host_no = devip->sdbg_host->shost->host_no;
1169 int n, ret, alen, rlen;
1170 int port_group_a, port_group_b, port_a, port_b;
1171
1172 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
1173 + cmd[9]);
1174
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001175 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1176 if (! arr)
1177 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001178 /*
1179 * EVPD page 0x88 states we have two ports, one
1180 * real and a fake port with no device connected.
1181 * So we create two port groups with one port each
1182 * and set the group with port B to unavailable.
1183 */
1184 port_a = 0x1; /* relative port A */
1185 port_b = 0x2; /* relative port B */
1186 port_group_a = (((host_no + 1) & 0x7f) << 8) +
1187 (devip->channel & 0x7f);
1188 port_group_b = (((host_no + 1) & 0x7f) << 8) +
1189 (devip->channel & 0x7f) + 0x80;
1190
1191 /*
1192 * The asymmetric access state is cycled according to the host_id.
1193 */
1194 n = 4;
1195 if (0 == scsi_debug_vpd_use_hostno) {
1196 arr[n++] = host_no % 3; /* Asymm access state */
1197 arr[n++] = 0x0F; /* claim: all states are supported */
1198 } else {
1199 arr[n++] = 0x0; /* Active/Optimized path */
1200 arr[n++] = 0x01; /* claim: only support active/optimized paths */
1201 }
1202 arr[n++] = (port_group_a >> 8) & 0xff;
1203 arr[n++] = port_group_a & 0xff;
1204 arr[n++] = 0; /* Reserved */
1205 arr[n++] = 0; /* Status code */
1206 arr[n++] = 0; /* Vendor unique */
1207 arr[n++] = 0x1; /* One port per group */
1208 arr[n++] = 0; /* Reserved */
1209 arr[n++] = 0; /* Reserved */
1210 arr[n++] = (port_a >> 8) & 0xff;
1211 arr[n++] = port_a & 0xff;
1212 arr[n++] = 3; /* Port unavailable */
1213 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1214 arr[n++] = (port_group_b >> 8) & 0xff;
1215 arr[n++] = port_group_b & 0xff;
1216 arr[n++] = 0; /* Reserved */
1217 arr[n++] = 0; /* Status code */
1218 arr[n++] = 0; /* Vendor unique */
1219 arr[n++] = 0x1; /* One port per group */
1220 arr[n++] = 0; /* Reserved */
1221 arr[n++] = 0; /* Reserved */
1222 arr[n++] = (port_b >> 8) & 0xff;
1223 arr[n++] = port_b & 0xff;
1224
1225 rlen = n - 4;
1226 arr[0] = (rlen >> 24) & 0xff;
1227 arr[1] = (rlen >> 16) & 0xff;
1228 arr[2] = (rlen >> 8) & 0xff;
1229 arr[3] = rlen & 0xff;
1230
1231 /*
1232 * Return the smallest value of either
1233 * - The allocated length
1234 * - The constructed command length
1235 * - The maximum array size
1236 */
1237 rlen = min(alen,n);
1238 ret = fill_from_dev_buffer(scp, arr,
1239 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1240 kfree(arr);
1241 return ret;
1242}
1243
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244/* <<Following mode page info copied from ST318451LW>> */
1245
1246static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1247{ /* Read-Write Error Recovery page for mode_sense */
1248 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1249 5, 0, 0xff, 0xff};
1250
1251 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1252 if (1 == pcontrol)
1253 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1254 return sizeof(err_recov_pg);
1255}
1256
1257static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1258{ /* Disconnect-Reconnect page for mode_sense */
1259 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1260 0, 0, 0, 0, 0, 0, 0, 0};
1261
1262 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1263 if (1 == pcontrol)
1264 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1265 return sizeof(disconnect_pg);
1266}
1267
1268static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1269{ /* Format device page for mode_sense */
1270 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1271 0, 0, 0, 0, 0, 0, 0, 0,
1272 0, 0, 0, 0, 0x40, 0, 0, 0};
1273
1274 memcpy(p, format_pg, sizeof(format_pg));
1275 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1276 p[11] = sdebug_sectors_per & 0xff;
1277 p[12] = (SECT_SIZE >> 8) & 0xff;
1278 p[13] = SECT_SIZE & 0xff;
1279 if (DEV_REMOVEABLE(target))
1280 p[20] |= 0x20; /* should agree with INQUIRY */
1281 if (1 == pcontrol)
1282 memset(p + 2, 0, sizeof(format_pg) - 2);
1283 return sizeof(format_pg);
1284}
1285
1286static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1287{ /* Caching page for mode_sense */
1288 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1289 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1290
1291 memcpy(p, caching_pg, sizeof(caching_pg));
1292 if (1 == pcontrol)
1293 memset(p + 2, 0, sizeof(caching_pg) - 2);
1294 return sizeof(caching_pg);
1295}
1296
1297static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1298{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001299 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1300 0, 0, 0, 0};
1301 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 0, 0, 0x2, 0x4b};
1303
1304 if (scsi_debug_dsense)
1305 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001306 else
1307 ctrl_m_pg[2] &= ~0x4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1309 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001310 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1311 else if (2 == pcontrol)
1312 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 return sizeof(ctrl_m_pg);
1314}
1315
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001316
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1318{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001319 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1320 0, 0, 0x0, 0x0};
1321 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1322 0, 0, 0x0, 0x0};
1323
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1325 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001326 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1327 else if (2 == pcontrol)
1328 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 return sizeof(iec_m_pg);
1330}
1331
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001332static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1333{ /* SAS SSP mode page - short format for mode_sense */
1334 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1335 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1336
1337 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1338 if (1 == pcontrol)
1339 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1340 return sizeof(sas_sf_m_pg);
1341}
1342
1343
1344static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1345 int target_dev_id)
1346{ /* SAS phy control and discover mode page for mode_sense */
1347 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1348 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1349 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1350 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1351 0x2, 0, 0, 0, 0, 0, 0, 0,
1352 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1353 0, 0, 0, 0, 0, 0, 0, 0,
1354 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1355 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1356 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1357 0x3, 0, 0, 0, 0, 0, 0, 0,
1358 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1359 0, 0, 0, 0, 0, 0, 0, 0,
1360 };
1361 int port_a, port_b;
1362
1363 port_a = target_dev_id + 1;
1364 port_b = port_a + 1;
1365 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1366 p[20] = (port_a >> 24);
1367 p[21] = (port_a >> 16) & 0xff;
1368 p[22] = (port_a >> 8) & 0xff;
1369 p[23] = port_a & 0xff;
1370 p[48 + 20] = (port_b >> 24);
1371 p[48 + 21] = (port_b >> 16) & 0xff;
1372 p[48 + 22] = (port_b >> 8) & 0xff;
1373 p[48 + 23] = port_b & 0xff;
1374 if (1 == pcontrol)
1375 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1376 return sizeof(sas_pcd_m_pg);
1377}
1378
1379static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1380{ /* SAS SSP shared protocol specific port mode subpage */
1381 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1382 0, 0, 0, 0, 0, 0, 0, 0,
1383 };
1384
1385 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1386 if (1 == pcontrol)
1387 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1388 return sizeof(sas_sha_m_pg);
1389}
1390
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391#define SDEBUG_MAX_MSENSE_SZ 256
1392
1393static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1394 struct sdebug_dev_info * devip)
1395{
Douglas Gilbert23183912006-09-16 20:30:47 -04001396 unsigned char dbd, llbaa;
1397 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001399 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 unsigned char * ap;
1401 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1402 unsigned char *cmd = (unsigned char *)scp->cmnd;
1403
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001404 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001406 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 pcontrol = (cmd[2] & 0xc0) >> 6;
1408 pcode = cmd[2] & 0x3f;
1409 subpcode = cmd[3];
1410 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001411 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1412 if ((0 == scsi_debug_ptype) && (0 == dbd))
1413 bd_len = llbaa ? 16 : 8;
1414 else
1415 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1417 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1418 if (0x3 == pcontrol) { /* Saving values not supported */
1419 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1420 0);
1421 return check_condition_result;
1422 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001423 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1424 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001425 /* set DPOFUA bit for disks */
1426 if (0 == scsi_debug_ptype)
1427 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1428 else
1429 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 if (msense_6) {
1431 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001432 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 offset = 4;
1434 } else {
1435 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001436 if (16 == bd_len)
1437 arr[4] = 0x1; /* set LONGLBA bit */
1438 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 offset = 8;
1440 }
1441 ap = arr + offset;
Douglas Gilbert23183912006-09-16 20:30:47 -04001442 if ((bd_len > 0) && (0 == sdebug_capacity)) {
1443 if (scsi_debug_virtual_gb > 0) {
1444 sdebug_capacity = 2048 * 1024;
1445 sdebug_capacity *= scsi_debug_virtual_gb;
1446 } else
1447 sdebug_capacity = sdebug_store_sectors;
1448 }
1449 if (8 == bd_len) {
1450 if (sdebug_capacity > 0xfffffffe) {
1451 ap[0] = 0xff;
1452 ap[1] = 0xff;
1453 ap[2] = 0xff;
1454 ap[3] = 0xff;
1455 } else {
1456 ap[0] = (sdebug_capacity >> 24) & 0xff;
1457 ap[1] = (sdebug_capacity >> 16) & 0xff;
1458 ap[2] = (sdebug_capacity >> 8) & 0xff;
1459 ap[3] = sdebug_capacity & 0xff;
1460 }
1461 ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1462 ap[7] = SECT_SIZE_PER(target) & 0xff;
1463 offset += bd_len;
1464 ap = arr + offset;
1465 } else if (16 == bd_len) {
1466 unsigned long long capac = sdebug_capacity;
1467
1468 for (k = 0; k < 8; ++k, capac >>= 8)
1469 ap[7 - k] = capac & 0xff;
1470 ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff;
1471 ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff;
1472 ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1473 ap[15] = SECT_SIZE_PER(target) & 0xff;
1474 offset += bd_len;
1475 ap = arr + offset;
1476 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001478 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1479 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1481 0);
1482 return check_condition_result;
1483 }
1484 switch (pcode) {
1485 case 0x1: /* Read-Write error recovery page, direct access */
1486 len = resp_err_recov_pg(ap, pcontrol, target);
1487 offset += len;
1488 break;
1489 case 0x2: /* Disconnect-Reconnect page, all devices */
1490 len = resp_disconnect_pg(ap, pcontrol, target);
1491 offset += len;
1492 break;
1493 case 0x3: /* Format device page, direct access */
1494 len = resp_format_pg(ap, pcontrol, target);
1495 offset += len;
1496 break;
1497 case 0x8: /* Caching page, direct access */
1498 len = resp_caching_pg(ap, pcontrol, target);
1499 offset += len;
1500 break;
1501 case 0xa: /* Control Mode page, all devices */
1502 len = resp_ctrl_m_pg(ap, pcontrol, target);
1503 offset += len;
1504 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001505 case 0x19: /* if spc==1 then sas phy, control+discover */
1506 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1507 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1508 INVALID_FIELD_IN_CDB, 0);
1509 return check_condition_result;
1510 }
1511 len = 0;
1512 if ((0x0 == subpcode) || (0xff == subpcode))
1513 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1514 if ((0x1 == subpcode) || (0xff == subpcode))
1515 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1516 target_dev_id);
1517 if ((0x2 == subpcode) || (0xff == subpcode))
1518 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1519 offset += len;
1520 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 case 0x1c: /* Informational Exceptions Mode page, all devices */
1522 len = resp_iec_m_pg(ap, pcontrol, target);
1523 offset += len;
1524 break;
1525 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001526 if ((0 == subpcode) || (0xff == subpcode)) {
1527 len = resp_err_recov_pg(ap, pcontrol, target);
1528 len += resp_disconnect_pg(ap + len, pcontrol, target);
1529 len += resp_format_pg(ap + len, pcontrol, target);
1530 len += resp_caching_pg(ap + len, pcontrol, target);
1531 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1532 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1533 if (0xff == subpcode) {
1534 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1535 target, target_dev_id);
1536 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1537 }
1538 len += resp_iec_m_pg(ap + len, pcontrol, target);
1539 } else {
1540 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1541 INVALID_FIELD_IN_CDB, 0);
1542 return check_condition_result;
1543 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 offset += len;
1545 break;
1546 default:
1547 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1548 0);
1549 return check_condition_result;
1550 }
1551 if (msense_6)
1552 arr[0] = offset - 1;
1553 else {
1554 arr[0] = ((offset - 2) >> 8) & 0xff;
1555 arr[1] = (offset - 2) & 0xff;
1556 }
1557 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1558}
1559
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001560#define SDEBUG_MAX_MSELECT_SZ 512
1561
1562static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1563 struct sdebug_dev_info * devip)
1564{
1565 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1566 int param_len, res, errsts, mpage;
1567 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1568 unsigned char *cmd = (unsigned char *)scp->cmnd;
1569
1570 if ((errsts = check_readiness(scp, 1, devip)))
1571 return errsts;
1572 memset(arr, 0, sizeof(arr));
1573 pf = cmd[1] & 0x10;
1574 sp = cmd[1] & 0x1;
1575 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1576 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1577 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1578 INVALID_FIELD_IN_CDB, 0);
1579 return check_condition_result;
1580 }
1581 res = fetch_to_dev_buffer(scp, arr, param_len);
1582 if (-1 == res)
1583 return (DID_ERROR << 16);
1584 else if ((res < param_len) &&
1585 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1586 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1587 " IO sent=%d bytes\n", param_len, res);
1588 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1589 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001590 if (md_len > 2) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001591 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1592 INVALID_FIELD_IN_PARAM_LIST, 0);
1593 return check_condition_result;
1594 }
1595 off = bd_len + (mselect6 ? 4 : 8);
1596 mpage = arr[off] & 0x3f;
1597 ps = !!(arr[off] & 0x80);
1598 if (ps) {
1599 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1600 INVALID_FIELD_IN_PARAM_LIST, 0);
1601 return check_condition_result;
1602 }
1603 spf = !!(arr[off] & 0x40);
1604 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1605 (arr[off + 1] + 2);
1606 if ((pg_len + off) > param_len) {
1607 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1608 PARAMETER_LIST_LENGTH_ERR, 0);
1609 return check_condition_result;
1610 }
1611 switch (mpage) {
1612 case 0xa: /* Control Mode page */
1613 if (ctrl_m_pg[1] == arr[off + 1]) {
1614 memcpy(ctrl_m_pg + 2, arr + off + 2,
1615 sizeof(ctrl_m_pg) - 2);
1616 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1617 return 0;
1618 }
1619 break;
1620 case 0x1c: /* Informational Exceptions Mode page */
1621 if (iec_m_pg[1] == arr[off + 1]) {
1622 memcpy(iec_m_pg + 2, arr + off + 2,
1623 sizeof(iec_m_pg) - 2);
1624 return 0;
1625 }
1626 break;
1627 default:
1628 break;
1629 }
1630 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1631 INVALID_FIELD_IN_PARAM_LIST, 0);
1632 return check_condition_result;
1633}
1634
1635static int resp_temp_l_pg(unsigned char * arr)
1636{
1637 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1638 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1639 };
1640
1641 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1642 return sizeof(temp_l_pg);
1643}
1644
1645static int resp_ie_l_pg(unsigned char * arr)
1646{
1647 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1648 };
1649
1650 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1651 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1652 arr[4] = THRESHOLD_EXCEEDED;
1653 arr[5] = 0xff;
1654 }
1655 return sizeof(ie_l_pg);
1656}
1657
1658#define SDEBUG_MAX_LSENSE_SZ 512
1659
1660static int resp_log_sense(struct scsi_cmnd * scp,
1661 struct sdebug_dev_info * devip)
1662{
Douglas Gilbert23183912006-09-16 20:30:47 -04001663 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001664 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1665 unsigned char *cmd = (unsigned char *)scp->cmnd;
1666
1667 if ((errsts = check_readiness(scp, 1, devip)))
1668 return errsts;
1669 memset(arr, 0, sizeof(arr));
1670 ppc = cmd[1] & 0x2;
1671 sp = cmd[1] & 0x1;
1672 if (ppc || sp) {
1673 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1674 INVALID_FIELD_IN_CDB, 0);
1675 return check_condition_result;
1676 }
1677 pcontrol = (cmd[2] & 0xc0) >> 6;
1678 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001679 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001680 alloc_len = (cmd[7] << 8) + cmd[8];
1681 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001682 if (0 == subpcode) {
1683 switch (pcode) {
1684 case 0x0: /* Supported log pages log page */
1685 n = 4;
1686 arr[n++] = 0x0; /* this page */
1687 arr[n++] = 0xd; /* Temperature */
1688 arr[n++] = 0x2f; /* Informational exceptions */
1689 arr[3] = n - 4;
1690 break;
1691 case 0xd: /* Temperature log page */
1692 arr[3] = resp_temp_l_pg(arr + 4);
1693 break;
1694 case 0x2f: /* Informational exceptions log page */
1695 arr[3] = resp_ie_l_pg(arr + 4);
1696 break;
1697 default:
1698 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1699 INVALID_FIELD_IN_CDB, 0);
1700 return check_condition_result;
1701 }
1702 } else if (0xff == subpcode) {
1703 arr[0] |= 0x40;
1704 arr[1] = subpcode;
1705 switch (pcode) {
1706 case 0x0: /* Supported log pages and subpages log page */
1707 n = 4;
1708 arr[n++] = 0x0;
1709 arr[n++] = 0x0; /* 0,0 page */
1710 arr[n++] = 0x0;
1711 arr[n++] = 0xff; /* this page */
1712 arr[n++] = 0xd;
1713 arr[n++] = 0x0; /* Temperature */
1714 arr[n++] = 0x2f;
1715 arr[n++] = 0x0; /* Informational exceptions */
1716 arr[3] = n - 4;
1717 break;
1718 case 0xd: /* Temperature subpages */
1719 n = 4;
1720 arr[n++] = 0xd;
1721 arr[n++] = 0x0; /* Temperature */
1722 arr[3] = n - 4;
1723 break;
1724 case 0x2f: /* Informational exceptions subpages */
1725 n = 4;
1726 arr[n++] = 0x2f;
1727 arr[n++] = 0x0; /* Informational exceptions */
1728 arr[3] = n - 4;
1729 break;
1730 default:
1731 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1732 INVALID_FIELD_IN_CDB, 0);
1733 return check_condition_result;
1734 }
1735 } else {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001736 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1737 INVALID_FIELD_IN_CDB, 0);
1738 return check_condition_result;
1739 }
1740 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1741 return fill_from_dev_buffer(scp, arr,
1742 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1743}
1744
1745static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
1746 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747{
1748 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001749 unsigned int block, from_bottom;
1750 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 int ret;
1752
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001753 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1755 0);
1756 return check_condition_result;
1757 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001758 /* transfer length excessive (tie in to block limits VPD page) */
1759 if (num > sdebug_store_sectors) {
1760 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1761 0);
1762 return check_condition_result;
1763 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001765 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1766 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1767 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1769 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001770 /* set info field and valid bit for fixed descriptor */
1771 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1772 devip->sense_buff[0] |= 0x80; /* Valid bit */
1773 ret = OPT_MEDIUM_ERR_ADDR;
1774 devip->sense_buff[3] = (ret >> 24) & 0xff;
1775 devip->sense_buff[4] = (ret >> 16) & 0xff;
1776 devip->sense_buff[5] = (ret >> 8) & 0xff;
1777 devip->sense_buff[6] = ret & 0xff;
1778 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 return check_condition_result;
1780 }
1781 read_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001782 if ((lba + num) <= sdebug_store_sectors)
1783 ret = fill_from_dev_buffer(SCpnt,
1784 fake_storep + (lba * SECT_SIZE),
1785 num * SECT_SIZE);
1786 else {
1787 /* modulo when one arg is 64 bits needs do_div() */
1788 u = lba;
1789 block = do_div(u, sdebug_store_sectors);
1790 from_bottom = 0;
1791 if ((block + num) > sdebug_store_sectors)
1792 from_bottom = (block + num) - sdebug_store_sectors;
1793 ret = fill_from_dev_buffer(SCpnt,
1794 fake_storep + (block * SECT_SIZE),
1795 (num - from_bottom) * SECT_SIZE);
1796 if ((0 == ret) && (from_bottom > 0))
1797 ret = fill_from_dev_buffer(SCpnt, fake_storep,
1798 from_bottom * SECT_SIZE);
1799 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 read_unlock_irqrestore(&atomic_rw, iflags);
1801 return ret;
1802}
1803
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001804static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
1805 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806{
1807 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001808 unsigned int block, to_bottom;
1809 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 int res;
1811
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001812 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1814 0);
1815 return check_condition_result;
1816 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001817 /* transfer length excessive (tie in to block limits VPD page) */
1818 if (num > sdebug_store_sectors) {
1819 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1820 0);
1821 return check_condition_result;
1822 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823
1824 write_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001825 if ((lba + num) <= sdebug_store_sectors)
1826 res = fetch_to_dev_buffer(SCpnt,
1827 fake_storep + (lba * SECT_SIZE),
1828 num * SECT_SIZE);
1829 else {
1830 /* modulo when one arg is 64 bits needs do_div() */
1831 u = lba;
1832 block = do_div(u, sdebug_store_sectors);
1833 to_bottom = 0;
1834 if ((block + num) > sdebug_store_sectors)
1835 to_bottom = (block + num) - sdebug_store_sectors;
1836 res = fetch_to_dev_buffer(SCpnt,
1837 fake_storep + (block * SECT_SIZE),
1838 (num - to_bottom) * SECT_SIZE);
1839 if ((0 == res) && (to_bottom > 0))
1840 res = fetch_to_dev_buffer(SCpnt, fake_storep,
1841 to_bottom * SECT_SIZE);
1842 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 write_unlock_irqrestore(&atomic_rw, iflags);
1844 if (-1 == res)
1845 return (DID_ERROR << 16);
1846 else if ((res < (num * SECT_SIZE)) &&
1847 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001848 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 " IO sent=%d bytes\n", num * SECT_SIZE, res);
1850 return 0;
1851}
1852
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001853#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854
1855static int resp_report_luns(struct scsi_cmnd * scp,
1856 struct sdebug_dev_info * devip)
1857{
1858 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001859 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 unsigned char *cmd = (unsigned char *)scp->cmnd;
1861 int select_report = (int)cmd[2];
1862 struct scsi_lun *one_lun;
1863 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001864 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865
1866 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001867 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1869 0);
1870 return check_condition_result;
1871 }
1872 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
1873 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
1874 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001875 if (1 == select_report)
1876 lun_cnt = 0;
1877 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
1878 --lun_cnt;
1879 wlun = (select_report > 0) ? 1 : 0;
1880 num = lun_cnt + wlun;
1881 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
1882 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
1883 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
1884 sizeof(struct scsi_lun)), num);
1885 if (n < num) {
1886 wlun = 0;
1887 lun_cnt = n;
1888 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001890 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
1891 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
1892 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
1893 i++, lun++) {
1894 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 if (upper)
1896 one_lun[i].scsi_lun[0] =
1897 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001898 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001900 if (wlun) {
1901 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
1902 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
1903 i++;
1904 }
1905 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 return fill_from_dev_buffer(scp, arr,
1907 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
1908}
1909
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001910static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
1911 unsigned int num, struct sdebug_dev_info *devip)
1912{
1913 int i, j, ret = -1;
1914 unsigned char *kaddr, *buf;
1915 unsigned int offset;
1916 struct scatterlist *sg;
1917 struct scsi_data_buffer *sdb = scsi_in(scp);
1918
1919 /* better not to use temporary buffer. */
1920 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
1921 if (!buf)
1922 return ret;
1923
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001924 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001925
1926 offset = 0;
1927 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
1928 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
1929 if (!kaddr)
1930 goto out;
1931
1932 for (j = 0; j < sg->length; j++)
1933 *(kaddr + sg->offset + j) ^= *(buf + offset + j);
1934
1935 offset += sg->length;
1936 kunmap_atomic(kaddr, KM_USER0);
1937 }
1938 ret = 0;
1939out:
1940 kfree(buf);
1941
1942 return ret;
1943}
1944
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945/* When timer goes off this function is called. */
1946static void timer_intr_handler(unsigned long indx)
1947{
1948 struct sdebug_queued_cmd * sqcp;
1949 unsigned long iflags;
1950
1951 if (indx >= SCSI_DEBUG_CANQUEUE) {
1952 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
1953 "large\n");
1954 return;
1955 }
1956 spin_lock_irqsave(&queued_arr_lock, iflags);
1957 sqcp = &queued_arr[(int)indx];
1958 if (! sqcp->in_use) {
1959 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
1960 "interrupt\n");
1961 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1962 return;
1963 }
1964 sqcp->in_use = 0;
1965 if (sqcp->done_funct) {
1966 sqcp->a_cmnd->result = sqcp->scsi_result;
1967 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
1968 }
1969 sqcp->done_funct = NULL;
1970 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1971}
1972
1973static int scsi_debug_slave_alloc(struct scsi_device * sdp)
1974{
1975 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001976 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
1977 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001978 set_bit(QUEUE_FLAG_BIDI, &sdp->request_queue->queue_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 return 0;
1980}
1981
1982static int scsi_debug_slave_configure(struct scsi_device * sdp)
1983{
1984 struct sdebug_dev_info * devip;
1985
1986 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001987 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
1988 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
1990 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
1991 devip = devInfoReg(sdp);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001992 if (NULL == devip)
1993 return 1; /* no resources, will be marked offline */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 sdp->hostdata = devip;
1995 if (sdp->host->cmd_per_lun)
1996 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
1997 sdp->host->cmd_per_lun);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001998 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 return 0;
2000}
2001
2002static void scsi_debug_slave_destroy(struct scsi_device * sdp)
2003{
2004 struct sdebug_dev_info * devip =
2005 (struct sdebug_dev_info *)sdp->hostdata;
2006
2007 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002008 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
2009 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 if (devip) {
2011 /* make this slot avaliable for re-use */
2012 devip->used = 0;
2013 sdp->hostdata = NULL;
2014 }
2015}
2016
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002017struct sdebug_dev_info *sdebug_device_create(struct sdebug_host_info *sdbg_host,
2018 gfp_t flags)
2019{
2020 struct sdebug_dev_info *devip;
2021
2022 devip = kzalloc(sizeof(*devip), flags);
2023 if (devip) {
2024 devip->sdbg_host = sdbg_host;
2025 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
2026 }
2027 return devip;
2028}
2029
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
2031{
2032 struct sdebug_host_info * sdbg_host;
2033 struct sdebug_dev_info * open_devip = NULL;
2034 struct sdebug_dev_info * devip =
2035 (struct sdebug_dev_info *)sdev->hostdata;
2036
2037 if (devip)
2038 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002039 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
2040 if (!sdbg_host) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 printk(KERN_ERR "Host info NULL\n");
2042 return NULL;
2043 }
2044 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
2045 if ((devip->used) && (devip->channel == sdev->channel) &&
2046 (devip->target == sdev->id) &&
2047 (devip->lun == sdev->lun))
2048 return devip;
2049 else {
2050 if ((!devip->used) && (!open_devip))
2051 open_devip = devip;
2052 }
2053 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002054 if (!open_devip) { /* try and make a new one */
2055 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
2056 if (!open_devip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 printk(KERN_ERR "%s: out of memory at line %d\n",
2058 __FUNCTION__, __LINE__);
2059 return NULL;
2060 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09002062
2063 open_devip->channel = sdev->channel;
2064 open_devip->target = sdev->id;
2065 open_devip->lun = sdev->lun;
2066 open_devip->sdbg_host = sdbg_host;
2067 open_devip->reset = 1;
2068 open_devip->used = 1;
2069 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
2070 if (scsi_debug_dsense)
2071 open_devip->sense_buff[0] = 0x72;
2072 else {
2073 open_devip->sense_buff[0] = 0x70;
2074 open_devip->sense_buff[7] = 0xa;
2075 }
2076 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2077 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
2078
2079 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080}
2081
2082static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
2083 int asc, int asq)
2084{
2085 unsigned char * sbuff;
2086
2087 sbuff = devip->sense_buff;
2088 memset(sbuff, 0, SDEBUG_SENSE_LEN);
2089 if (scsi_debug_dsense) {
2090 sbuff[0] = 0x72; /* descriptor, current */
2091 sbuff[1] = key;
2092 sbuff[2] = asc;
2093 sbuff[3] = asq;
2094 } else {
2095 sbuff[0] = 0x70; /* fixed, current */
2096 sbuff[2] = key;
2097 sbuff[7] = 0xa; /* implies 18 byte sense buffer */
2098 sbuff[12] = asc;
2099 sbuff[13] = asq;
2100 }
2101 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2102 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
2103 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
2104}
2105
2106static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
2107{
2108 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2109 printk(KERN_INFO "scsi_debug: abort\n");
2110 ++num_aborts;
2111 stop_queued_cmnd(SCpnt);
2112 return SUCCESS;
2113}
2114
2115static int scsi_debug_biosparam(struct scsi_device *sdev,
2116 struct block_device * bdev, sector_t capacity, int *info)
2117{
2118 int res;
2119 unsigned char *buf;
2120
2121 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2122 printk(KERN_INFO "scsi_debug: biosparam\n");
2123 buf = scsi_bios_ptable(bdev);
2124 if (buf) {
2125 res = scsi_partsize(buf, capacity,
2126 &info[2], &info[0], &info[1]);
2127 kfree(buf);
2128 if (! res)
2129 return res;
2130 }
2131 info[0] = sdebug_heads;
2132 info[1] = sdebug_sectors_per;
2133 info[2] = sdebug_cylinders_per;
2134 return 0;
2135}
2136
2137static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
2138{
2139 struct sdebug_dev_info * devip;
2140
2141 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2142 printk(KERN_INFO "scsi_debug: device_reset\n");
2143 ++num_dev_resets;
2144 if (SCpnt) {
2145 devip = devInfoReg(SCpnt->device);
2146 if (devip)
2147 devip->reset = 1;
2148 }
2149 return SUCCESS;
2150}
2151
2152static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
2153{
2154 struct sdebug_host_info *sdbg_host;
2155 struct sdebug_dev_info * dev_info;
2156 struct scsi_device * sdp;
2157 struct Scsi_Host * hp;
2158
2159 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2160 printk(KERN_INFO "scsi_debug: bus_reset\n");
2161 ++num_bus_resets;
2162 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002163 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 if (sdbg_host) {
2165 list_for_each_entry(dev_info,
2166 &sdbg_host->dev_info_list,
2167 dev_list)
2168 dev_info->reset = 1;
2169 }
2170 }
2171 return SUCCESS;
2172}
2173
2174static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
2175{
2176 struct sdebug_host_info * sdbg_host;
2177 struct sdebug_dev_info * dev_info;
2178
2179 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2180 printk(KERN_INFO "scsi_debug: host_reset\n");
2181 ++num_host_resets;
2182 spin_lock(&sdebug_host_list_lock);
2183 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
2184 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
2185 dev_list)
2186 dev_info->reset = 1;
2187 }
2188 spin_unlock(&sdebug_host_list_lock);
2189 stop_all_queued();
2190 return SUCCESS;
2191}
2192
2193/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
2194static int stop_queued_cmnd(struct scsi_cmnd * cmnd)
2195{
2196 unsigned long iflags;
2197 int k;
2198 struct sdebug_queued_cmd * sqcp;
2199
2200 spin_lock_irqsave(&queued_arr_lock, iflags);
2201 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2202 sqcp = &queued_arr[k];
2203 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
2204 del_timer_sync(&sqcp->cmnd_timer);
2205 sqcp->in_use = 0;
2206 sqcp->a_cmnd = NULL;
2207 break;
2208 }
2209 }
2210 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2211 return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
2212}
2213
2214/* Deletes (stops) timers of all queued commands */
2215static void stop_all_queued(void)
2216{
2217 unsigned long iflags;
2218 int k;
2219 struct sdebug_queued_cmd * sqcp;
2220
2221 spin_lock_irqsave(&queued_arr_lock, iflags);
2222 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2223 sqcp = &queued_arr[k];
2224 if (sqcp->in_use && sqcp->a_cmnd) {
2225 del_timer_sync(&sqcp->cmnd_timer);
2226 sqcp->in_use = 0;
2227 sqcp->a_cmnd = NULL;
2228 }
2229 }
2230 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2231}
2232
2233/* Initializes timers in queued array */
2234static void __init init_all_queued(void)
2235{
2236 unsigned long iflags;
2237 int k;
2238 struct sdebug_queued_cmd * sqcp;
2239
2240 spin_lock_irqsave(&queued_arr_lock, iflags);
2241 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2242 sqcp = &queued_arr[k];
2243 init_timer(&sqcp->cmnd_timer);
2244 sqcp->in_use = 0;
2245 sqcp->a_cmnd = NULL;
2246 }
2247 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2248}
2249
2250static void __init sdebug_build_parts(unsigned char * ramp)
2251{
2252 struct partition * pp;
2253 int starts[SDEBUG_MAX_PARTS + 2];
2254 int sectors_per_part, num_sectors, k;
2255 int heads_by_sects, start_sec, end_sec;
2256
2257 /* assume partition table already zeroed */
2258 if ((scsi_debug_num_parts < 1) || (sdebug_store_size < 1048576))
2259 return;
2260 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
2261 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
2262 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
2263 "partitions to %d\n", SDEBUG_MAX_PARTS);
2264 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002265 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 sectors_per_part = (num_sectors - sdebug_sectors_per)
2267 / scsi_debug_num_parts;
2268 heads_by_sects = sdebug_heads * sdebug_sectors_per;
2269 starts[0] = sdebug_sectors_per;
2270 for (k = 1; k < scsi_debug_num_parts; ++k)
2271 starts[k] = ((k * sectors_per_part) / heads_by_sects)
2272 * heads_by_sects;
2273 starts[scsi_debug_num_parts] = num_sectors;
2274 starts[scsi_debug_num_parts + 1] = 0;
2275
2276 ramp[510] = 0x55; /* magic partition markings */
2277 ramp[511] = 0xAA;
2278 pp = (struct partition *)(ramp + 0x1be);
2279 for (k = 0; starts[k + 1]; ++k, ++pp) {
2280 start_sec = starts[k];
2281 end_sec = starts[k + 1] - 1;
2282 pp->boot_ind = 0;
2283
2284 pp->cyl = start_sec / heads_by_sects;
2285 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2286 / sdebug_sectors_per;
2287 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2288
2289 pp->end_cyl = end_sec / heads_by_sects;
2290 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2291 / sdebug_sectors_per;
2292 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2293
2294 pp->start_sect = start_sec;
2295 pp->nr_sects = end_sec - start_sec + 1;
2296 pp->sys_ind = 0x83; /* plain Linux partition */
2297 }
2298}
2299
2300static int schedule_resp(struct scsi_cmnd * cmnd,
2301 struct sdebug_dev_info * devip,
2302 done_funct_t done, int scsi_result, int delta_jiff)
2303{
2304 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2305 if (scsi_result) {
2306 struct scsi_device * sdp = cmnd->device;
2307
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002308 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2309 "non-zero result=0x%x\n", sdp->host->host_no,
2310 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311 }
2312 }
2313 if (cmnd && devip) {
2314 /* simulate autosense by this driver */
2315 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2316 memcpy(cmnd->sense_buffer, devip->sense_buff,
2317 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2318 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2319 }
2320 if (delta_jiff <= 0) {
2321 if (cmnd)
2322 cmnd->result = scsi_result;
2323 if (done)
2324 done(cmnd);
2325 return 0;
2326 } else {
2327 unsigned long iflags;
2328 int k;
2329 struct sdebug_queued_cmd * sqcp = NULL;
2330
2331 spin_lock_irqsave(&queued_arr_lock, iflags);
2332 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2333 sqcp = &queued_arr[k];
2334 if (! sqcp->in_use)
2335 break;
2336 }
2337 if (k >= SCSI_DEBUG_CANQUEUE) {
2338 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2339 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2340 return 1; /* report busy to mid level */
2341 }
2342 sqcp->in_use = 1;
2343 sqcp->a_cmnd = cmnd;
2344 sqcp->scsi_result = scsi_result;
2345 sqcp->done_funct = done;
2346 sqcp->cmnd_timer.function = timer_intr_handler;
2347 sqcp->cmnd_timer.data = k;
2348 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2349 add_timer(&sqcp->cmnd_timer);
2350 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2351 if (cmnd)
2352 cmnd->result = 0;
2353 return 0;
2354 }
2355}
2356
Douglas Gilbert23183912006-09-16 20:30:47 -04002357/* Note: The following macros create attribute files in the
2358 /sys/module/scsi_debug/parameters directory. Unfortunately this
2359 driver is unaware of a change and cannot trigger auxiliary actions
2360 as it can when the corresponding attribute in the
2361 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2362 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002363module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2364module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2365module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2366module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2367module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002368module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002369module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2370module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2371module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2372module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2373module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2374module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2375module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2376module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002377module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2378 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379
2380MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2381MODULE_DESCRIPTION("SCSI debug adapter driver");
2382MODULE_LICENSE("GPL");
2383MODULE_VERSION(SCSI_DEBUG_VERSION);
2384
2385MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2386MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002387MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2388MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07002389MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002390MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002391MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2392MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002394MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002395MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2397MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002398MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002399MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400
2401
2402static char sdebug_info[256];
2403
2404static const char * scsi_debug_info(struct Scsi_Host * shp)
2405{
2406 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2407 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2408 scsi_debug_version_date, scsi_debug_dev_size_mb,
2409 scsi_debug_opts);
2410 return sdebug_info;
2411}
2412
2413/* scsi_debug_proc_info
2414 * Used if the driver currently has no own support for /proc/scsi
2415 */
2416static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2417 int length, int inout)
2418{
2419 int len, pos, begin;
2420 int orig_length;
2421
2422 orig_length = length;
2423
2424 if (inout == 1) {
2425 char arr[16];
2426 int minLen = length > 15 ? 15 : length;
2427
2428 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2429 return -EACCES;
2430 memcpy(arr, buffer, minLen);
2431 arr[minLen] = '\0';
2432 if (1 != sscanf(arr, "%d", &pos))
2433 return -EINVAL;
2434 scsi_debug_opts = pos;
2435 if (scsi_debug_every_nth != 0)
2436 scsi_debug_cmnd_count = 0;
2437 return length;
2438 }
2439 begin = 0;
2440 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2441 "%s [%s]\n"
2442 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2443 "every_nth=%d(curr:%d)\n"
2444 "delay=%d, max_luns=%d, scsi_level=%d\n"
2445 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2446 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
2447 "host_resets=%d\n",
2448 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2449 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2450 scsi_debug_cmnd_count, scsi_debug_delay,
2451 scsi_debug_max_luns, scsi_debug_scsi_level,
2452 SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
2453 num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
2454 if (pos < offset) {
2455 len = 0;
2456 begin = pos;
2457 }
2458 *start = buffer + (offset - begin); /* Start of wanted data */
2459 len -= (offset - begin);
2460 if (len > length)
2461 len = length;
2462 return len;
2463}
2464
2465static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2466{
2467 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2468}
2469
2470static ssize_t sdebug_delay_store(struct device_driver * ddp,
2471 const char * buf, size_t count)
2472{
2473 int delay;
2474 char work[20];
2475
2476 if (1 == sscanf(buf, "%10s", work)) {
2477 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2478 scsi_debug_delay = delay;
2479 return count;
2480 }
2481 }
2482 return -EINVAL;
2483}
2484DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2485 sdebug_delay_store);
2486
2487static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2488{
2489 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2490}
2491
2492static ssize_t sdebug_opts_store(struct device_driver * ddp,
2493 const char * buf, size_t count)
2494{
2495 int opts;
2496 char work[20];
2497
2498 if (1 == sscanf(buf, "%10s", work)) {
2499 if (0 == strnicmp(work,"0x", 2)) {
2500 if (1 == sscanf(&work[2], "%x", &opts))
2501 goto opts_done;
2502 } else {
2503 if (1 == sscanf(work, "%d", &opts))
2504 goto opts_done;
2505 }
2506 }
2507 return -EINVAL;
2508opts_done:
2509 scsi_debug_opts = opts;
2510 scsi_debug_cmnd_count = 0;
2511 return count;
2512}
2513DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2514 sdebug_opts_store);
2515
2516static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2517{
2518 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2519}
2520static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2521 const char * buf, size_t count)
2522{
2523 int n;
2524
2525 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2526 scsi_debug_ptype = n;
2527 return count;
2528 }
2529 return -EINVAL;
2530}
2531DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2532
2533static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2534{
2535 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2536}
2537static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2538 const char * buf, size_t count)
2539{
2540 int n;
2541
2542 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2543 scsi_debug_dsense = n;
2544 return count;
2545 }
2546 return -EINVAL;
2547}
2548DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2549 sdebug_dsense_store);
2550
Douglas Gilbert23183912006-09-16 20:30:47 -04002551static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2552{
2553 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2554}
2555static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2556 const char * buf, size_t count)
2557{
2558 int n;
2559
2560 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2561 scsi_debug_fake_rw = n;
2562 return count;
2563 }
2564 return -EINVAL;
2565}
2566DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2567 sdebug_fake_rw_store);
2568
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002569static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2570{
2571 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2572}
2573static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2574 const char * buf, size_t count)
2575{
2576 int n;
2577
2578 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2579 scsi_debug_no_lun_0 = n;
2580 return count;
2581 }
2582 return -EINVAL;
2583}
2584DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2585 sdebug_no_lun_0_store);
2586
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2588{
2589 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2590}
2591static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2592 const char * buf, size_t count)
2593{
2594 int n;
2595
2596 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2597 scsi_debug_num_tgts = n;
2598 sdebug_max_tgts_luns();
2599 return count;
2600 }
2601 return -EINVAL;
2602}
2603DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2604 sdebug_num_tgts_store);
2605
2606static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2607{
2608 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2609}
2610DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2611
2612static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2613{
2614 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2615}
2616DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2617
2618static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2619{
2620 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2621}
2622static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2623 const char * buf, size_t count)
2624{
2625 int nth;
2626
2627 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2628 scsi_debug_every_nth = nth;
2629 scsi_debug_cmnd_count = 0;
2630 return count;
2631 }
2632 return -EINVAL;
2633}
2634DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2635 sdebug_every_nth_store);
2636
2637static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2638{
2639 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2640}
2641static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2642 const char * buf, size_t count)
2643{
2644 int n;
2645
2646 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2647 scsi_debug_max_luns = n;
2648 sdebug_max_tgts_luns();
2649 return count;
2650 }
2651 return -EINVAL;
2652}
2653DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2654 sdebug_max_luns_store);
2655
2656static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
2657{
2658 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
2659}
2660DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
2661
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002662static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2663{
2664 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2665}
2666static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2667 const char * buf, size_t count)
2668{
2669 int n;
2670
2671 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2672 scsi_debug_virtual_gb = n;
2673 if (scsi_debug_virtual_gb > 0) {
2674 sdebug_capacity = 2048 * 1024;
2675 sdebug_capacity *= scsi_debug_virtual_gb;
2676 } else
2677 sdebug_capacity = sdebug_store_sectors;
2678 return count;
2679 }
2680 return -EINVAL;
2681}
2682DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2683 sdebug_virtual_gb_store);
2684
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
2686{
2687 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
2688}
2689
2690static ssize_t sdebug_add_host_store(struct device_driver * ddp,
2691 const char * buf, size_t count)
2692{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002693 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002695 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 if (delta_hosts > 0) {
2698 do {
2699 sdebug_add_adapter();
2700 } while (--delta_hosts);
2701 } else if (delta_hosts < 0) {
2702 do {
2703 sdebug_remove_adapter();
2704 } while (++delta_hosts);
2705 }
2706 return count;
2707}
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002708DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 sdebug_add_host_store);
2710
Douglas Gilbert23183912006-09-16 20:30:47 -04002711static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
2712 char * buf)
2713{
2714 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
2715}
2716static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
2717 const char * buf, size_t count)
2718{
2719 int n;
2720
2721 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2722 scsi_debug_vpd_use_hostno = n;
2723 return count;
2724 }
2725 return -EINVAL;
2726}
2727DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
2728 sdebug_vpd_use_hostno_store);
2729
2730/* Note: The following function creates attribute files in the
2731 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
2732 files (over those found in the /sys/module/scsi_debug/parameters
2733 directory) is that auxiliary actions can be triggered when an attribute
2734 is changed. For example see: sdebug_add_host_store() above.
2735 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002736static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002738 int ret;
2739
2740 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2741 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
2742 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2743 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2744 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04002745 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002746 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002747 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002748 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002749 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002750 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
2751 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
2752 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04002753 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
2754 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002755 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756}
2757
2758static void do_remove_driverfs_files(void)
2759{
Douglas Gilbert23183912006-09-16 20:30:47 -04002760 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
2761 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
2763 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
2764 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002766 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
2767 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002769 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
2771 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2772 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2773 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
2774 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2775}
2776
2777static int __init scsi_debug_init(void)
2778{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002779 unsigned int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 int host_to_add;
2781 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002782 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783
2784 if (scsi_debug_dev_size_mb < 1)
2785 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002786 sdebug_store_size = (unsigned int)scsi_debug_dev_size_mb * 1048576;
2787 sdebug_store_sectors = sdebug_store_size / SECT_SIZE;
2788 if (scsi_debug_virtual_gb > 0) {
2789 sdebug_capacity = 2048 * 1024;
2790 sdebug_capacity *= scsi_debug_virtual_gb;
2791 } else
2792 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793
2794 /* play around with geometry, don't waste too much on track 0 */
2795 sdebug_heads = 8;
2796 sdebug_sectors_per = 32;
2797 if (scsi_debug_dev_size_mb >= 16)
2798 sdebug_heads = 32;
2799 else if (scsi_debug_dev_size_mb >= 256)
2800 sdebug_heads = 64;
2801 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2802 (sdebug_sectors_per * sdebug_heads);
2803 if (sdebug_cylinders_per >= 1024) {
2804 /* other LLDs do this; implies >= 1GB ram disk ... */
2805 sdebug_heads = 255;
2806 sdebug_sectors_per = 63;
2807 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2808 (sdebug_sectors_per * sdebug_heads);
2809 }
2810
2811 sz = sdebug_store_size;
2812 fake_storep = vmalloc(sz);
2813 if (NULL == fake_storep) {
2814 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
2815 return -ENOMEM;
2816 }
2817 memset(fake_storep, 0, sz);
2818 if (scsi_debug_num_parts > 0)
2819 sdebug_build_parts(fake_storep);
2820
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002821 ret = device_register(&pseudo_primary);
2822 if (ret < 0) {
2823 printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
2824 ret);
2825 goto free_vm;
2826 }
2827 ret = bus_register(&pseudo_lld_bus);
2828 if (ret < 0) {
2829 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
2830 ret);
2831 goto dev_unreg;
2832 }
2833 ret = driver_register(&sdebug_driverfs_driver);
2834 if (ret < 0) {
2835 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
2836 ret);
2837 goto bus_unreg;
2838 }
2839 ret = do_create_driverfs_files();
2840 if (ret < 0) {
2841 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
2842 ret);
2843 goto del_files;
2844 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002846 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 host_to_add = scsi_debug_add_host;
2849 scsi_debug_add_host = 0;
2850
2851 for (k = 0; k < host_to_add; k++) {
2852 if (sdebug_add_adapter()) {
2853 printk(KERN_ERR "scsi_debug_init: "
2854 "sdebug_add_adapter failed k=%d\n", k);
2855 break;
2856 }
2857 }
2858
2859 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
2860 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
2861 scsi_debug_add_host);
2862 }
2863 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002864
2865del_files:
2866 do_remove_driverfs_files();
2867 driver_unregister(&sdebug_driverfs_driver);
2868bus_unreg:
2869 bus_unregister(&pseudo_lld_bus);
2870dev_unreg:
2871 device_unregister(&pseudo_primary);
2872free_vm:
2873 vfree(fake_storep);
2874
2875 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876}
2877
2878static void __exit scsi_debug_exit(void)
2879{
2880 int k = scsi_debug_add_host;
2881
2882 stop_all_queued();
2883 for (; k; k--)
2884 sdebug_remove_adapter();
2885 do_remove_driverfs_files();
2886 driver_unregister(&sdebug_driverfs_driver);
2887 bus_unregister(&pseudo_lld_bus);
2888 device_unregister(&pseudo_primary);
2889
2890 vfree(fake_storep);
2891}
2892
2893device_initcall(scsi_debug_init);
2894module_exit(scsi_debug_exit);
2895
Adrian Bunk52c1da32005-06-23 22:05:33 -07002896static void pseudo_0_release(struct device * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897{
2898 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2899 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
2900}
2901
2902static struct device pseudo_primary = {
2903 .bus_id = "pseudo_0",
2904 .release = pseudo_0_release,
2905};
2906
2907static int pseudo_lld_bus_match(struct device *dev,
2908 struct device_driver *dev_driver)
2909{
2910 return 1;
2911}
2912
2913static struct bus_type pseudo_lld_bus = {
2914 .name = "pseudo",
2915 .match = pseudo_lld_bus_match,
Russell Kingbbbe3a42006-01-05 14:44:46 +00002916 .probe = sdebug_driver_probe,
2917 .remove = sdebug_driver_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918};
2919
2920static void sdebug_release_adapter(struct device * dev)
2921{
2922 struct sdebug_host_info *sdbg_host;
2923
2924 sdbg_host = to_sdebug_host(dev);
2925 kfree(sdbg_host);
2926}
2927
2928static int sdebug_add_adapter(void)
2929{
2930 int k, devs_per_host;
2931 int error = 0;
2932 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09002933 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002935 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 if (NULL == sdbg_host) {
2937 printk(KERN_ERR "%s: out of memory at line %d\n",
2938 __FUNCTION__, __LINE__);
2939 return -ENOMEM;
2940 }
2941
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
2943
2944 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
2945 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002946 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
2947 if (!sdbg_devinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948 printk(KERN_ERR "%s: out of memory at line %d\n",
2949 __FUNCTION__, __LINE__);
2950 error = -ENOMEM;
2951 goto clean;
2952 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953 }
2954
2955 spin_lock(&sdebug_host_list_lock);
2956 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
2957 spin_unlock(&sdebug_host_list_lock);
2958
2959 sdbg_host->dev.bus = &pseudo_lld_bus;
2960 sdbg_host->dev.parent = &pseudo_primary;
2961 sdbg_host->dev.release = &sdebug_release_adapter;
2962 sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host);
2963
2964 error = device_register(&sdbg_host->dev);
2965
2966 if (error)
2967 goto clean;
2968
2969 ++scsi_debug_add_host;
2970 return error;
2971
2972clean:
FUJITA Tomonori8b402282008-03-20 11:09:18 +09002973 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
2974 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 list_del(&sdbg_devinfo->dev_list);
2976 kfree(sdbg_devinfo);
2977 }
2978
2979 kfree(sdbg_host);
2980 return error;
2981}
2982
2983static void sdebug_remove_adapter(void)
2984{
2985 struct sdebug_host_info * sdbg_host = NULL;
2986
2987 spin_lock(&sdebug_host_list_lock);
2988 if (!list_empty(&sdebug_host_list)) {
2989 sdbg_host = list_entry(sdebug_host_list.prev,
2990 struct sdebug_host_info, host_list);
2991 list_del(&sdbg_host->host_list);
2992 }
2993 spin_unlock(&sdebug_host_list_lock);
2994
2995 if (!sdbg_host)
2996 return;
2997
2998 device_unregister(&sdbg_host->dev);
2999 --scsi_debug_add_host;
3000}
3001
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09003002static struct scsi_host_template sdebug_driver_template = {
3003 .proc_info = scsi_debug_proc_info,
3004 .proc_name = sdebug_proc_name,
3005 .name = "SCSI DEBUG",
3006 .info = scsi_debug_info,
3007 .slave_alloc = scsi_debug_slave_alloc,
3008 .slave_configure = scsi_debug_slave_configure,
3009 .slave_destroy = scsi_debug_slave_destroy,
3010 .ioctl = scsi_debug_ioctl,
3011 .queuecommand = scsi_debug_queuecommand,
3012 .eh_abort_handler = scsi_debug_abort,
3013 .eh_bus_reset_handler = scsi_debug_bus_reset,
3014 .eh_device_reset_handler = scsi_debug_device_reset,
3015 .eh_host_reset_handler = scsi_debug_host_reset,
3016 .bios_param = scsi_debug_biosparam,
3017 .can_queue = SCSI_DEBUG_CANQUEUE,
3018 .this_id = 7,
3019 .sg_tablesize = 256,
3020 .cmd_per_lun = 16,
3021 .max_sectors = 0xffff,
3022 .use_clustering = DISABLE_CLUSTERING,
3023 .module = THIS_MODULE,
3024};
3025
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026static int sdebug_driver_probe(struct device * dev)
3027{
3028 int error = 0;
3029 struct sdebug_host_info *sdbg_host;
3030 struct Scsi_Host *hpnt;
3031
3032 sdbg_host = to_sdebug_host(dev);
3033
3034 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
3035 if (NULL == hpnt) {
3036 printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__);
3037 error = -ENODEV;
3038 return error;
3039 }
3040
3041 sdbg_host->shost = hpnt;
3042 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
3043 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
3044 hpnt->max_id = scsi_debug_num_tgts + 1;
3045 else
3046 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003047 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048
3049 error = scsi_add_host(hpnt, &sdbg_host->dev);
3050 if (error) {
3051 printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
3052 error = -ENODEV;
3053 scsi_host_put(hpnt);
3054 } else
3055 scsi_scan_host(hpnt);
3056
3057
3058 return error;
3059}
3060
3061static int sdebug_driver_remove(struct device * dev)
3062{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09003064 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065
3066 sdbg_host = to_sdebug_host(dev);
3067
3068 if (!sdbg_host) {
3069 printk(KERN_ERR "%s: Unable to locate host info\n",
3070 __FUNCTION__);
3071 return -ENODEV;
3072 }
3073
3074 scsi_remove_host(sdbg_host->shost);
3075
FUJITA Tomonori8b402282008-03-20 11:09:18 +09003076 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
3077 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 list_del(&sdbg_devinfo->dev_list);
3079 kfree(sdbg_devinfo);
3080 }
3081
3082 scsi_host_put(sdbg_host->shost);
3083 return 0;
3084}
3085
3086static void sdebug_max_tgts_luns(void)
3087{
3088 struct sdebug_host_info * sdbg_host;
3089 struct Scsi_Host *hpnt;
3090
3091 spin_lock(&sdebug_host_list_lock);
3092 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3093 hpnt = sdbg_host->shost;
3094 if ((hpnt->this_id >= 0) &&
3095 (scsi_debug_num_tgts > hpnt->this_id))
3096 hpnt->max_id = scsi_debug_num_tgts + 1;
3097 else
3098 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003099 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100 }
3101 spin_unlock(&sdebug_host_list_lock);
3102}