1 /* $Id: scsi_debug.c,v 1.1 1992/07/24 06:27:38 root Exp root $
2 * linux/kernel/scsi_debug.c
4 * Copyright (C) 1992 Eric Youngdale
5 * Simulate a host adapter with 2 disks attached. Do a lot of checking
6 * to make sure that we are not getting blocks mixed up, and panic if
7 * anything out of the ordinary is seen.
10 #include <linux/config.h>
11 #include <linux/module.h>
13 #include <linux/kernel.h>
14 #include <linux/sched.h>
15 #include <linux/errno.h>
16 #include <linux/timer.h>
17 #include <linux/types.h>
18 #include <linux/string.h>
19 #include <linux/genhd.h>
21 #include <linux/proc_fs.h>
23 #include <asm/system.h>
26 #include <linux/blk.h>
32 #include<linux/stat.h>
34 /* A few options that we want selected */
36 #define NR_HOSTS_PRESENT 1
37 #define NR_FAKE_DISKS 3
40 #define N_CYLINDER 524
41 #define DISK_READONLY(TGT) (0)
42 #define DISK_REMOVEABLE(TGT) (1)
43 #define DEVICE_TYPE(TGT) (TGT == 2 ? TYPE_TAPE : TYPE_DISK);
45 /* Do not attempt to use a timer to simulate a real disk with latency */
46 /* Only use this in the actual kernel, not in the simulator. */
49 /* Skip some consistency checking. Good for benchmarking */
51 /* Read return zeros. Undefine for benchmarking */
54 /* Number of real scsi disks that will be detected ahead of time */
55 static int NR_REAL
= -1;
61 #define START_PARTITION 4
63 /* Time to wait before completing a command */
64 #define DISK_SPEED (HZ/10) /* 100ms */
65 #define CAPACITY (N_HEAD * N_SECTOR * N_CYLINDER)
66 #define SIZE(TGT) (TGT == 2 ? 2248 : 512)
70 N_HEAD
* N_SECTOR
, /* Single cylinder */
71 N_HEAD
* N_SECTOR
* 4,
75 #include "scsi_debug.h"
83 #define VERIFY1_DEBUG(RW)
84 #define VERIFY_DEBUG(RW)
87 #define VERIFY1_DEBUG(RW) \
88 if (bufflen != 1024) {printk("%d", bufflen); panic("(1)Bad bufflen");}; \
90 if ((MINOR(SCpnt->request.rq_dev) & 0xf) != 0) start = starts[(MINOR(SCpnt->request.rq_dev) & 0xf) - 1]; \
92 if (bh->b_size != 1024) panic ("Wrong bh size"); \
93 if ((bh->b_blocknr << 1) + start != block) \
94 { printk("Wrong bh block# %d %d ",bh->b_blocknr, block); \
95 panic ("Wrong bh block#"); \
97 if (bh->b_dev != SCpnt->request.rq_dev) \
98 panic ("Bad bh target"); \
101 #define VERIFY_DEBUG(RW) \
102 if (bufflen != 1024 && (!SCpnt->use_sg)) {printk("%x %d\n ",bufflen, SCpnt->use_sg); panic("Bad bufflen");}; \
104 if ((MINOR(SCpnt->request.rq_dev) & 0xf) > npart) panic ("Bad partition"); \
105 if ((MINOR(SCpnt->request.rq_dev) & 0xf) != 0) start = starts[(MINOR(SCpnt->request.rq_dev) & 0xf) - 1]; \
106 if (SCpnt->request.cmd != RW) panic ("Wrong operation"); \
107 if (SCpnt->request.sector + start != block) panic("Wrong block."); \
108 if (SCpnt->request.current_nr_sectors != 2 && (!SCpnt->use_sg)) panic ("Wrong # blocks"); \
109 if (SCpnt->request.bh){ \
110 if (SCpnt->request.bh->b_size != 1024) panic ("Wrong bh size"); \
111 if ((SCpnt->request.bh->b_blocknr << 1) + start != block) \
112 { printk("Wrong bh block# %d %d ",SCpnt->request.bh->b_blocknr, block); \
113 panic ("Wrong bh block#"); \
115 if (SCpnt->request.bh->b_dev != SCpnt->request.rq_dev) \
116 panic ("Bad bh target");\
120 typedef void (*done_fct_t
) (Scsi_Cmnd
*);
122 static volatile done_fct_t do_done
[SCSI_DEBUG_MAILBOXES
] =
125 struct Scsi_Host
* SHpnt
= NULL
;
127 static void scsi_debug_send_self_command(struct Scsi_Host
* shpnt
);
128 static void scsi_debug_intr_handle(unsigned long);
130 static struct timer_list timeout
[SCSI_DEBUG_MAILBOXES
];
132 Scsi_Cmnd
*SCint
[SCSI_DEBUG_MAILBOXES
] =
134 static char SCrst
[SCSI_DEBUG_MAILBOXES
] =
138 * Semaphore used to simulate bus lockups.
140 static int scsi_debug_lockup
= 0;
142 static char sense_buffer
[128] =
145 static void scsi_dump(Scsi_Cmnd
* SCpnt
, int flag
)
152 struct scatterlist
*sgpnt
= NULL
;
153 printk("use_sg: %d", SCpnt
->use_sg
);
155 sgpnt
= (struct scatterlist
*) SCpnt
->buffer
;
156 for (i
= 0; i
< SCpnt
->use_sg
; i
++) {
157 lpnt
= (int *) sgpnt
[i
].alt_address
;
158 printk(":%p %p %d\n", sgpnt
[i
].alt_address
, sgpnt
[i
].address
, sgpnt
[i
].length
);
160 printk(" (Alt %x) ", lpnt
[15]);
163 printk("nosg: %p %p %d\n", SCpnt
->request
.buffer
, SCpnt
->buffer
,
165 lpnt
= (int *) SCpnt
->request
.buffer
;
167 printk(" (Alt %x) ", lpnt
[15]);
169 lpnt
= (unsigned int *) SCpnt
;
170 for (i
= 0; i
< sizeof(Scsi_Cmnd
) / 4 + 1; i
++) {
173 printk("%x ", *lpnt
++);
178 lpnt
= (unsigned int *) sgpnt
[0].alt_address
;
179 for (i
= 0; i
< sizeof(Scsi_Cmnd
) / 4 + 1; i
++) {
182 printk("%x ", *lpnt
++);
186 lpnt
= (unsigned int *) sgpnt
[0].address
;
187 for (i
= 0; i
< sizeof(Scsi_Cmnd
) / 4 + 1; i
++) {
190 printk("%x ", *lpnt
++);
194 printk("DMA free %d sectors.\n", scsi_dma_free_sectors
);
197 int scsi_debug_queuecommand(Scsi_Cmnd
* SCpnt
, void (*done
) (Scsi_Cmnd
*))
199 unchar
*cmd
= (unchar
*) SCpnt
->cmnd
;
202 struct buffer_head
*bh
= NULL
;
205 int scsi_debug_errsts
;
206 struct scatterlist
*sgpnt
;
207 int target
= SCpnt
->target
;
208 int bufflen
= SCpnt
->request_bufflen
;
216 * The io_request_lock *must* be held at this point.
218 if( io_request_lock
.lock
== 0 )
220 printk("Warning - io_request_lock is not held in queuecommand\n");
225 * If we are being notified of the mid-level reposessing a command due to timeout,
231 DEB(if (target
>= NR_FAKE_DISKS
) {
232 SCpnt
->result
= DID_TIME_OUT
<< 16; done(SCpnt
); return 0;
236 buff
= (unsigned char *) SCpnt
->request_buffer
;
239 * If a command comes for the ID of the host itself, just print
240 * a silly message and return.
243 printk("How do you do!\n");
249 if (target
>= NR_FAKE_DISKS
|| SCpnt
->lun
!= 0) {
250 SCpnt
->result
= DID_NO_CONNECT
<< 16;
254 if (SCrst
[target
] != 0 && !scsi_debug_lockup
) {
256 memset(SCpnt
->sense_buffer
, 0, sizeof(SCpnt
->sense_buffer
));
257 SCpnt
->sense_buffer
[0] = 0x70;
258 SCpnt
->sense_buffer
[2] = UNIT_ATTENTION
;
259 SCpnt
->result
= (CHECK_CONDITION
<< 1);
264 SCSI_LOG_LLQUEUE(3, printk("Request sense...\n"));
268 printk("scsi_debug: Requesting sense buffer (%p %p %p %d):", SCpnt
, buff
, done
, bufflen
);
269 for (i
= 0; i
< 12; i
++)
270 printk("%d ", sense_buffer
[i
]);
274 memset(buff
, 0, bufflen
);
275 memcpy(buff
, sense_buffer
, bufflen
);
276 memset(sense_buffer
, 0, sizeof(sense_buffer
));
281 SCSI_LOG_LLQUEUE(3, printk("START_STOP\n"));
282 scsi_debug_errsts
= 0;
284 case ALLOW_MEDIUM_REMOVAL
:
286 SCSI_LOG_LLQUEUE(2, printk("Medium removal inhibited..."));
288 SCSI_LOG_LLQUEUE(2, printk("Medium removal enabled..."));
290 scsi_debug_errsts
= 0;
293 SCSI_LOG_LLQUEUE(3, printk("Inquiry...(%p %d)\n", buff
, bufflen
));
294 memset(buff
, 0, bufflen
);
295 buff
[0] = DEVICE_TYPE(target
);
296 buff
[1] = DISK_REMOVEABLE(target
) ? 0x80 : 0; /* Removable disk */
299 memcpy(&buff
[8], "Foo Inc", 7);
300 memcpy(&buff
[16], "XYZZY", 5);
301 memcpy(&buff
[32], "1", 1);
302 scsi_debug_errsts
= 0;
304 case TEST_UNIT_READY
:
305 SCSI_LOG_LLQUEUE(3, printk("Test unit ready(%p %d)\n", buff
, bufflen
));
307 memset(buff
, 0, bufflen
);
308 scsi_debug_errsts
= 0;
311 SCSI_LOG_LLQUEUE(3, printk("Read Capacity\n"));
314 NR_REAL
= (MINOR(SCpnt
->request
.rq_dev
) >> 4) & 0x0f;
315 memset(buff
, 0, bufflen
);
316 buff
[0] = (CAPACITY
>> 24);
317 buff
[1] = (CAPACITY
>> 16) & 0xff;
318 buff
[2] = (CAPACITY
>> 8) & 0xff;
319 buff
[3] = CAPACITY
& 0xff;
322 buff
[6] = (SIZE(target
) >> 8) & 0xff; /* 512 byte sectors */
323 buff
[7] = SIZE(target
) & 0xff;
325 scsi_debug_errsts
= 0;
332 if ((*cmd
) == READ_10
)
333 block
= cmd
[5] + (cmd
[4] << 8) + (cmd
[3] << 16) + (cmd
[2] << 24);
335 block
= cmd
[3] + (cmd
[2] << 8) + ((cmd
[1] & 0x1f) << 16);
337 #if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE)
339 int delay
= SCSI_SETUP_LATENCY
;
341 delay
+= SCpnt
->request
.nr_sectors
* SCSI_DATARATE
;
348 printk("(r%d)", SCpnt
->request
.nr_sectors
);
353 sgpnt
= (struct scatterlist
*) buff
;
354 buff
= sgpnt
[sgcount
].address
;
355 bufflen
= sgpnt
[sgcount
].length
;
356 bh
= SCpnt
->request
.bh
;
358 scsi_debug_errsts
= 0;
361 /* For the speedy test, we do not even want to fill the buffer with anything */
363 memset(buff
, 0, bufflen
);
365 /* If this is block 0, then we want to read the partition table for this
366 * device. Let's make one up */
369 memset(buff
, 0, bufflen
);
370 *((unsigned short *) (buff
+ 510)) = 0xAA55;
371 p
= (struct partition
*) (buff
+ 0x1be);
373 while (starts
[i
+ 1]) {
374 int start_cyl
, end_cyl
;
376 start_cyl
= starts
[i
] / N_HEAD
/ N_SECTOR
;
377 end_cyl
= (starts
[i
+ 1] - 1) / N_HEAD
/ N_SECTOR
;
380 p
->head
= (i
== 0 ? 1 : 0);
381 p
->sector
= 1 | ((start_cyl
>> 8) << 6);
382 p
->cyl
= (start_cyl
& 0xff);
384 p
->end_head
= N_HEAD
- 1;
385 p
->end_sector
= N_SECTOR
| ((end_cyl
>> 8) << 6);
386 p
->end_cyl
= (end_cyl
& 0xff);
388 p
->start_sect
= starts
[i
];
389 p
->nr_sects
= starts
[i
+ 1] - starts
[i
];
390 p
->sys_ind
= 0x81; /* Linux partition */
396 scsi_debug_errsts
= 0;
401 printk("Block %x (%d %d)\n", block
, SCpnt
->request
.nr_sectors
,
402 SCpnt
->request
.current_nr_sectors
);
406 /* Simulate a disk change */
407 if (block
== 0xfff0) {
408 sense_buffer
[0] = 0x70;
409 sense_buffer
[2] = UNIT_ATTENTION
;
417 printk("scsi_debug: Filling sense buffer:");
418 for (i
= 0; i
< 12; i
++)
419 printk("%d ", sense_buffer
[i
]);
423 scsi_debug_errsts
= (COMMAND_COMPLETE
<< 8) | (CHECK_CONDITION
<< 1);
425 } /* End phony disk change code */
429 memcpy(buff
, &target
, sizeof(target
));
430 memcpy(buff
+ sizeof(target
), cmd
, 24);
431 memcpy(buff
+ 60, &block
, sizeof(block
));
432 memcpy(buff
+ 64, SCpnt
, sizeof(Scsi_Cmnd
));
437 memcpy(buff
+ 128, bh
, sizeof(struct buffer_head
));
439 block
+= bufflen
>> 9;
444 panic("Too few blocks for linked request.");
445 buff
= sgpnt
[sgcount
].address
;
446 bufflen
= sgpnt
[sgcount
].length
;
455 if (SCpnt
->use_sg
&& !scsi_debug_errsts
)
464 if ((*cmd
) == WRITE_10
)
465 block
= cmd
[5] + (cmd
[4] << 8) + (cmd
[3] << 16) + (cmd
[2] << 24);
467 block
= cmd
[3] + (cmd
[2] << 8) + ((cmd
[1] & 0x1f) << 16);
469 /* printk("(w%d)",SCpnt->request.nr_sectors); */
471 if ((bufflen
>> 9) != SCpnt
->request
.nr_sectors
)
472 panic("Trying to write wrong number of blocks\n");
473 sgpnt
= (struct scatterlist
*) buff
;
474 buff
= sgpnt
[sgcount
].address
;
477 if (block
!= *((unsigned long *) (buff
+ 60))) {
478 printk("%x %x :", block
, *((unsigned long *) (buff
+ 60)));
480 panic("Bad block written.\n");
483 scsi_debug_errsts
= 0;
487 * Used to detect write protected status.
489 scsi_debug_errsts
= 0;
493 SCSI_LOG_LLQUEUE(3, printk("Unknown command %d\n", *cmd
));
494 SCpnt
->result
= DID_NO_CONNECT
<< 16;
501 for (i
= 0; i
< SCSI_DEBUG_MAILBOXES
; i
++) {
502 if (timeout
[i
].function
== NULL
)
507 * If all of the slots are full, just return 1. The new error handling scheme
508 * allows this, and the mid-level should queue things.
510 if (i
>= SCSI_DEBUG_MAILBOXES
|| timeout
[i
].function
!= 0) {
511 SCSI_LOG_LLQUEUE(1, printk("Command rejected - host busy\n"));
512 restore_flags(flags
);
515 SCSI_LOG_LLQUEUE(1, printk("Command accepted - slot %d\n", i
));
518 if (!scsi_debug_lockup
) {
519 SCpnt
->result
= scsi_debug_errsts
;
522 scsi_debug_intr_handle(i
); /* No timer - do this one right away */
524 restore_flags(flags
);
527 SCpnt
->result
= scsi_debug_errsts
;
528 timeout
[i
].function
= scsi_debug_intr_handle
;
530 timeout
[i
].expires
= jiffies
+ DISK_SPEED
;
534 restore_flags(flags
);
535 add_timer(&timeout
[i
]);
537 panic("scsi_debug_queuecommand: done can't be NULL\n");
540 printk("Sending command (%d %x %d %d)...", i
, done
, timeout
[i
].expires
, jiffies
);
547 static void scsi_debug_send_self_command(struct Scsi_Host
* shpnt
)
549 static unsigned char cmd
[6] =
550 {TEST_UNIT_READY
, 0, 0, 0, 0, 0};
555 printk("Allocating host dev\n");
556 sdev
= scsi_get_host_dev(shpnt
);
559 printk("Out of memory.\n");
563 printk("Got %p. Allocating command block\n", sdev
);
564 scp
= scsi_allocate_request(sdev
);
565 printk("Got %p\n", scp
);
569 printk("Out of memory.\n");
576 printk("Sending command\n");
577 scsi_wait_req (scp
, (void *) cmd
, (void *) NULL
,
580 printk("Releasing command\n");
581 scsi_release_request(scp
);
583 printk("Freeing device\n");
584 scsi_free_host_dev(sdev
);
587 /* A "high" level interrupt handler. This should be called once per jiffy
588 * to simulate a regular scsi disk. We use a timer to do this. */
590 static void scsi_debug_intr_handle(unsigned long indx
)
593 void (*my_done
) (Scsi_Cmnd
*);
599 del_timer(&timeout
[indx
]);
602 SCtmp
= (Scsi_Cmnd
*) SCint
[indx
];
603 my_done
= do_done
[indx
];
604 do_done
[indx
] = NULL
;
605 timeout
[indx
].function
= NULL
;
609 printk("scsi_debug_intr_handle: Unexpected interrupt\n");
613 printk("In intr_handle...");
614 printk("...done %d %x %d %d\n", i
, my_done
, to
, jiffies
);
615 printk("In intr_handle: %d %x %x\n", i
, SCtmp
, my_done
);
620 printk("Called done.\n");
625 int scsi_debug_detect(Scsi_Host_Template
* tpnt
)
629 for (i
= 0; i
< NR_HOSTS_PRESENT
; i
++) {
630 tpnt
->proc_name
= "scsi_debug"; /* Huh? In the loop??? */
631 scsi_register(tpnt
, 0);
633 return NR_HOSTS_PRESENT
;
636 int scsi_debug_abort(Scsi_Cmnd
* SCpnt
)
640 void (*my_done
) (Scsi_Cmnd
*);
644 DEB(printk("scsi_debug_abort\n"));
646 SCpnt
->result
= SCpnt
->abort_reason
<< 16;
647 for (j
= 0; j
< SCSI_DEBUG_MAILBOXES
; j
++) {
648 if (SCpnt
== SCint
[j
]) {
649 my_done
= do_done
[j
];
656 restore_flags(flags
);
660 return SCSI_ABORT_SNOOZE
;
663 int scsi_debug_biosparam(Disk
* disk
, kdev_t dev
, int *info
)
665 int size
= disk
->capacity
;
668 info
[2] = N_CYLINDER
;
674 int scsi_debug_reset(Scsi_Cmnd
* SCpnt
, unsigned int why
)
679 void (*my_done
) (Scsi_Cmnd
*);
680 printk("Bus unlocked by reset - %d\n", why
);
681 scsi_debug_lockup
= 0;
682 DEB(printk("scsi_debug_reset called\n"));
683 for (i
= 0; i
< SCSI_DEBUG_MAILBOXES
; i
++) {
684 if (SCint
[i
] == NULL
)
686 SCint
[i
]->result
= DID_RESET
<< 16;
687 my_done
= do_done
[i
];
693 timeout
[i
].function
= NULL
;
694 restore_flags(flags
);
696 return SCSI_RESET_SUCCESS
;
699 const char *scsi_debug_info(void)
701 static char buffer
[] = " "; /* looks nicer without anything here */
705 /* scsi_debug_proc_info
706 * Used if the driver currently has no own support for /proc/scsi
708 int scsi_debug_proc_info(char *buffer
, char **start
, off_t offset
,
709 int length
, int inode
, int inout
)
714 orig_length
= length
;
717 /* First check for the Signature */
718 if (length
>= 10 && strncmp(buffer
, "scsi_debug", 10) == 0) {
722 if (buffer
[length
- 1] == '\n') {
723 buffer
[length
- 1] = '\0';
727 * OK, we are getting some kind of command. Figure out
728 * what we are supposed to do here. Simulate bus lockups
729 * to test our reset capability.
731 if (length
== 4 && strncmp(buffer
, "test", length
) == 0) {
732 printk("Testing send self command %p\n", SHpnt
);
733 scsi_debug_send_self_command(SHpnt
);
736 if (length
== 6 && strncmp(buffer
, "lockup", length
) == 0) {
737 scsi_debug_lockup
= 1;
740 if (length
== 6 && strncmp(buffer
, "unlock", length
) == 0) {
741 scsi_debug_lockup
= 0;
744 printk("Unknown command:%s (%d)\n", buffer
, length
);
746 printk("Wrong Signature:%10s\n", (char *) buffer
);
752 pos
= len
= sprintf(buffer
,
753 "This driver is not a real scsi driver, but it plays one on TV.\n"
754 "It is very handy for debugging specific problems because you\n"
755 "can simulate a variety of error conditions\n");
760 *start
= buffer
+ (offset
- begin
); /* Start of wanted data */
761 len
-= (offset
- begin
);
768 #ifdef CONFIG_USER_DEBUG
770 * This is a hack for the user space emulator. It allows us to
771 * "insert" arbitrary numbers of additional drivers.
773 void *scsi_debug_get_handle(void)
775 static Scsi_Host_Template driver_copy
= SCSI_DEBUG
;
777 rtn
= kmalloc(sizeof(driver_copy
), GFP_ATOMIC
);
780 memcpy(rtn
, (void *) &driver_copy
, sizeof(driver_copy
));
785 /* Eventually this will go into an include file, but this will be later */
786 static Scsi_Host_Template driver_template
= SCSI_DEBUG
;
788 #include "scsi_module.c"
791 * Overrides for Emacs so that we almost follow Linus's tabbing style.
792 * Emacs will notice this stuff at the end of the file and automatically
793 * adjust the settings for this buffer only. This must remain at the end
795 * ---------------------------------------------------------------------------
798 * c-brace-imaginary-offset: 0
800 * c-argdecl-indent: 4
802 * c-continued-statement-offset: 4
803 * c-continued-brace-offset: 0
804 * indent-tabs-mode: nil