Merge with 2.3.99-pre1.
[linux-2.6/linux-mips.git] / drivers / scsi / scsi_debug.c
blob4bed377edbb9da2671bd1ad76cd9206aca53956d
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.
8 */
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>
20 #include <linux/fs.h>
21 #include <linux/proc_fs.h>
23 #include <asm/system.h>
24 #include <asm/io.h>
26 #include <linux/blk.h>
27 #include "scsi.h"
28 #include "hosts.h"
30 #include "sd.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
38 #define N_HEAD 255
39 #define N_SECTOR 63
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. */
47 #define IMMEDIATE
49 /* Skip some consistency checking. Good for benchmarking */
50 #define SPEEDY
51 /* Read return zeros. Undefine for benchmarking */
52 #define CLEAR
54 /* Number of real scsi disks that will be detected ahead of time */
55 static int NR_REAL = -1;
57 #define NR_BLK_DEV 12
58 #ifndef MAJOR_NR
59 #define MAJOR_NR 8
60 #endif
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)
68 static int starts[] =
69 {N_SECTOR,
70 N_HEAD * N_SECTOR, /* Single cylinder */
71 N_HEAD * N_SECTOR * 4,
72 CAPACITY, 0};
73 static int npart = 0;
75 #include "scsi_debug.h"
76 #ifdef DEBUG
77 #define DEB(x) x
78 #else
79 #define DEB(x)
80 #endif
82 #ifdef SPEEDY
83 #define VERIFY1_DEBUG(RW)
84 #define VERIFY_DEBUG(RW)
85 #else
87 #define VERIFY1_DEBUG(RW) \
88 if (bufflen != 1024) {printk("%d", bufflen); panic("(1)Bad bufflen");}; \
89 start = 0; \
90 if ((MINOR(SCpnt->request.rq_dev) & 0xf) != 0) start = starts[(MINOR(SCpnt->request.rq_dev) & 0xf) - 1]; \
91 if (bh){ \
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#"); \
96 }; \
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");}; \
103 start = 0; \
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#"); \
114 }; \
115 if (SCpnt->request.bh->b_dev != SCpnt->request.rq_dev) \
116 panic ("Bad bh target");\
118 #endif
120 typedef void (*done_fct_t) (Scsi_Cmnd *);
122 static volatile done_fct_t do_done[SCSI_DEBUG_MAILBOXES] =
123 {NULL,};
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] =
133 {NULL,};
134 static char SCrst[SCSI_DEBUG_MAILBOXES] =
135 {0,};
138 * Semaphore used to simulate bus lockups.
140 static int scsi_debug_lockup = 0;
142 static char sense_buffer[128] =
143 {0,};
145 static void scsi_dump(Scsi_Cmnd * SCpnt, int flag)
147 int i;
148 #if 0
149 unsigned char *pnt;
150 #endif
151 unsigned int *lpnt;
152 struct scatterlist *sgpnt = NULL;
153 printk("use_sg: %d", SCpnt->use_sg);
154 if (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);
159 if (lpnt)
160 printk(" (Alt %x) ", lpnt[15]);
162 } else {
163 printk("nosg: %p %p %d\n", SCpnt->request.buffer, SCpnt->buffer,
164 SCpnt->bufflen);
165 lpnt = (int *) SCpnt->request.buffer;
166 if (lpnt)
167 printk(" (Alt %x) ", lpnt[15]);
169 lpnt = (unsigned int *) SCpnt;
170 for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) {
171 if ((i & 7) == 0)
172 printk("\n");
173 printk("%x ", *lpnt++);
175 printk("\n");
176 if (flag == 0)
177 return;
178 lpnt = (unsigned int *) sgpnt[0].alt_address;
179 for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) {
180 if ((i & 7) == 0)
181 printk("\n");
182 printk("%x ", *lpnt++);
184 #if 0
185 printk("\n");
186 lpnt = (unsigned int *) sgpnt[0].address;
187 for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) {
188 if ((i & 7) == 0)
189 printk("\n");
190 printk("%x ", *lpnt++);
192 printk("\n");
193 #endif
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;
200 struct partition *p;
201 int block;
202 struct buffer_head *bh = NULL;
203 unsigned char *buff;
204 int nbytes, sgcount;
205 int scsi_debug_errsts;
206 struct scatterlist *sgpnt;
207 int target = SCpnt->target;
208 int bufflen = SCpnt->request_bufflen;
209 unsigned long flags;
210 int i;
211 sgcount = 0;
212 sgpnt = NULL;
214 #ifdef CONFIG_SMP
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");
222 #endif
225 * If we are being notified of the mid-level reposessing a command due to timeout,
226 * just return.
228 if (done == NULL) {
229 return 0;
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.
242 if( target == 7 ) {
243 printk("How do you do!\n");
244 SCpnt->result = 0;
245 done(SCpnt);
246 return 0;
249 if (target >= NR_FAKE_DISKS || SCpnt->lun != 0) {
250 SCpnt->result = DID_NO_CONNECT << 16;
251 done(SCpnt);
252 return 0;
254 if (SCrst[target] != 0 && !scsi_debug_lockup) {
255 SCrst[target] = 0;
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);
260 done(SCpnt);
262 switch (*cmd) {
263 case REQUEST_SENSE:
264 SCSI_LOG_LLQUEUE(3, printk("Request sense...\n"));
265 #ifndef DEBUG
267 int i;
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]);
271 printk("\n");
273 #endif
274 memset(buff, 0, bufflen);
275 memcpy(buff, sense_buffer, bufflen);
276 memset(sense_buffer, 0, sizeof(sense_buffer));
277 SCpnt->result = 0;
278 done(SCpnt);
279 return 0;
280 case START_STOP:
281 SCSI_LOG_LLQUEUE(3, printk("START_STOP\n"));
282 scsi_debug_errsts = 0;
283 break;
284 case ALLOW_MEDIUM_REMOVAL:
285 if (cmd[4]) {
286 SCSI_LOG_LLQUEUE(2, printk("Medium removal inhibited..."));
287 } else {
288 SCSI_LOG_LLQUEUE(2, printk("Medium removal enabled..."));
290 scsi_debug_errsts = 0;
291 break;
292 case INQUIRY:
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 */
297 buff[2] = 1;
298 buff[4] = 33 - 5;
299 memcpy(&buff[8], "Foo Inc", 7);
300 memcpy(&buff[16], "XYZZY", 5);
301 memcpy(&buff[32], "1", 1);
302 scsi_debug_errsts = 0;
303 break;
304 case TEST_UNIT_READY:
305 SCSI_LOG_LLQUEUE(3, printk("Test unit ready(%p %d)\n", buff, bufflen));
306 if (buff)
307 memset(buff, 0, bufflen);
308 scsi_debug_errsts = 0;
309 break;
310 case READ_CAPACITY:
311 SCSI_LOG_LLQUEUE(3, printk("Read Capacity\n"));
312 SHpnt = SCpnt->host;
313 if (NR_REAL < 0)
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;
320 buff[4] = 0;
321 buff[5] = 0;
322 buff[6] = (SIZE(target) >> 8) & 0xff; /* 512 byte sectors */
323 buff[7] = SIZE(target) & 0xff;
325 scsi_debug_errsts = 0;
326 break;
327 case READ_10:
328 case READ_6:
329 #ifdef DEBUG
330 printk("Read...");
331 #endif
332 if ((*cmd) == READ_10)
333 block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
334 else
335 block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
336 VERIFY_DEBUG(READ);
337 #if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE)
339 int delay = SCSI_SETUP_LATENCY;
341 delay += SCpnt->request.nr_sectors * SCSI_DATARATE;
342 if (delay)
343 usleep(delay);
345 #endif
347 #ifdef DEBUG
348 printk("(r%d)", SCpnt->request.nr_sectors);
349 #endif
350 nbytes = bufflen;
351 if (SCpnt->use_sg) {
352 sgcount = 0;
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;
359 do {
360 VERIFY1_DEBUG(READ);
361 /* For the speedy test, we do not even want to fill the buffer with anything */
362 #ifdef CLEAR
363 memset(buff, 0, bufflen);
364 #endif
365 /* If this is block 0, then we want to read the partition table for this
366 * device. Let's make one up */
367 if (block == 0) {
368 int i;
369 memset(buff, 0, bufflen);
370 *((unsigned short *) (buff + 510)) = 0xAA55;
371 p = (struct partition *) (buff + 0x1be);
372 i = 0;
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;
378 p->boot_ind = 0;
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 */
391 p++;
392 i++;
394 if (!npart)
395 npart = i;
396 scsi_debug_errsts = 0;
397 break;
399 #ifdef DEBUG
400 if (SCpnt->use_sg)
401 printk("Block %x (%d %d)\n", block, SCpnt->request.nr_sectors,
402 SCpnt->request.current_nr_sectors);
403 #endif
405 #if 0
406 /* Simulate a disk change */
407 if (block == 0xfff0) {
408 sense_buffer[0] = 0x70;
409 sense_buffer[2] = UNIT_ATTENTION;
410 starts[0] += 10;
411 starts[1] += 10;
412 starts[2] += 10;
414 #ifdef DEBUG
416 int i;
417 printk("scsi_debug: Filling sense buffer:");
418 for (i = 0; i < 12; i++)
419 printk("%d ", sense_buffer[i]);
420 printk("\n");
422 #endif
423 scsi_debug_errsts = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
424 break;
425 } /* End phony disk change code */
426 #endif
428 #ifdef CLEAR
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));
433 #endif
434 nbytes -= bufflen;
435 if (SCpnt->use_sg) {
436 #ifdef CLEAR
437 memcpy(buff + 128, bh, sizeof(struct buffer_head));
438 #endif
439 block += bufflen >> 9;
440 bh = bh->b_reqnext;
441 sgcount++;
442 if (nbytes) {
443 if (!bh)
444 panic("Too few blocks for linked request.");
445 buff = sgpnt[sgcount].address;
446 bufflen = sgpnt[sgcount].length;
449 } while (nbytes);
451 SCpnt->result = 0;
452 (done) (SCpnt);
453 return 0;
455 if (SCpnt->use_sg && !scsi_debug_errsts)
456 if (bh)
457 scsi_dump(SCpnt, 0);
458 break;
459 case WRITE_10:
460 case WRITE_6:
461 #ifdef DEBUG
462 printk("Write\n");
463 #endif
464 if ((*cmd) == WRITE_10)
465 block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
466 else
467 block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
468 VERIFY_DEBUG(WRITE);
469 /* printk("(w%d)",SCpnt->request.nr_sectors); */
470 if (SCpnt->use_sg) {
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;
476 #if 0
477 if (block != *((unsigned long *) (buff + 60))) {
478 printk("%x %x :", block, *((unsigned long *) (buff + 60)));
479 scsi_dump(SCpnt, 1);
480 panic("Bad block written.\n");
482 #endif
483 scsi_debug_errsts = 0;
484 break;
485 case MODE_SENSE:
487 * Used to detect write protected status.
489 scsi_debug_errsts = 0;
490 memset(buff, 0, 6);
491 break;
492 default:
493 SCSI_LOG_LLQUEUE(3, printk("Unknown command %d\n", *cmd));
494 SCpnt->result = DID_NO_CONNECT << 16;
495 done(SCpnt);
496 return 0;
499 save_flags(flags);
500 cli();
501 for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) {
502 if (timeout[i].function == NULL)
503 break;
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);
513 return 1;
515 SCSI_LOG_LLQUEUE(1, printk("Command accepted - slot %d\n", i));
517 #ifdef IMMEDIATE
518 if (!scsi_debug_lockup) {
519 SCpnt->result = scsi_debug_errsts;
520 SCint[i] = SCpnt;
521 do_done[i] = done;
522 scsi_debug_intr_handle(i); /* No timer - do this one right away */
524 restore_flags(flags);
525 #else
527 SCpnt->result = scsi_debug_errsts;
528 timeout[i].function = scsi_debug_intr_handle;
529 timeout[i].data = i;
530 timeout[i].expires = jiffies + DISK_SPEED;
531 SCint[i] = SCpnt;
532 do_done[i] = done;
534 restore_flags(flags);
535 add_timer(&timeout[i]);
536 if (!done)
537 panic("scsi_debug_queuecommand: done can't be NULL\n");
539 #if 0
540 printk("Sending command (%d %x %d %d)...", i, done, timeout[i].expires, jiffies);
541 #endif
542 #endif
544 return 0;
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};
552 Scsi_Request * scp;
553 Scsi_Device * sdev;
555 printk("Allocating host dev\n");
556 sdev = scsi_get_host_dev(shpnt);
557 printk("Got %p. Allocating command block\n", sdev);
558 scp = scsi_allocate_request(sdev);
559 printk("Got %p\n", scp);
561 scp->sr_cmd_len = 6;
562 scp->sr_use_sg = 0;
564 printk("Sending command\n");
565 scsi_wait_req (scp, (void *) cmd, (void *) NULL,
566 0, 100, 3);
568 printk("Releasing command\n");
569 scsi_release_request(scp);
570 printk("Freeing device\n");
571 scsi_free_host_dev(sdev);
574 /* A "high" level interrupt handler. This should be called once per jiffy
575 * to simulate a regular scsi disk. We use a timer to do this. */
577 static void scsi_debug_intr_handle(unsigned long indx)
579 Scsi_Cmnd *SCtmp;
580 void (*my_done) (Scsi_Cmnd *);
581 #ifdef DEBUG
582 int to;
583 #endif
585 #if 0
586 del_timer(&timeout[indx]);
587 #endif
589 SCtmp = (Scsi_Cmnd *) SCint[indx];
590 my_done = do_done[indx];
591 do_done[indx] = NULL;
592 timeout[indx].function = NULL;
593 SCint[indx] = NULL;
595 if (!my_done) {
596 printk("scsi_debug_intr_handle: Unexpected interrupt\n");
597 return;
599 #ifdef DEBUG
600 printk("In intr_handle...");
601 printk("...done %d %x %d %d\n", i, my_done, to, jiffies);
602 printk("In intr_handle: %d %x %x\n", i, SCtmp, my_done);
603 #endif
605 my_done(SCtmp);
606 #ifdef DEBUG
607 printk("Called done.\n");
608 #endif
612 int scsi_debug_detect(Scsi_Host_Template * tpnt)
614 int i;
616 for (i = 0; i < NR_HOSTS_PRESENT; i++) {
617 tpnt->proc_name = "scsi_debug"; /* Huh? In the loop??? */
618 scsi_register(tpnt, 0);
620 return NR_HOSTS_PRESENT;
623 int scsi_debug_abort(Scsi_Cmnd * SCpnt)
625 #if 0
626 int j;
627 void (*my_done) (Scsi_Cmnd *);
628 unsigned long flags;
629 #endif
631 DEB(printk("scsi_debug_abort\n"));
632 #if 0
633 SCpnt->result = SCpnt->abort_reason << 16;
634 for (j = 0; j < SCSI_DEBUG_MAILBOXES; j++) {
635 if (SCpnt == SCint[j]) {
636 my_done = do_done[j];
637 my_done(SCpnt);
638 save_flags(flags);
639 cli();
640 timeout[j] = 0;
641 SCint[j] = NULL;
642 do_done[j] = NULL;
643 restore_flags(flags);
646 #endif
647 return SCSI_ABORT_SNOOZE;
650 int scsi_debug_biosparam(Disk * disk, kdev_t dev, int *info)
652 int size = disk->capacity;
653 info[0] = N_HEAD;
654 info[1] = N_SECTOR;
655 info[2] = N_CYLINDER;
656 if (info[2] >= 1024)
657 info[2] = 1024;
658 return 0;
661 int scsi_debug_reset(Scsi_Cmnd * SCpnt, unsigned int why)
663 int i;
664 unsigned long flags;
666 void (*my_done) (Scsi_Cmnd *);
667 printk("Bus unlocked by reset - %d\n", why);
668 scsi_debug_lockup = 0;
669 DEB(printk("scsi_debug_reset called\n"));
670 for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) {
671 if (SCint[i] == NULL)
672 continue;
673 SCint[i]->result = DID_RESET << 16;
674 my_done = do_done[i];
675 my_done(SCint[i]);
676 save_flags(flags);
677 cli();
678 SCint[i] = NULL;
679 do_done[i] = NULL;
680 timeout[i].function = NULL;
681 restore_flags(flags);
683 return SCSI_RESET_SUCCESS;
686 const char *scsi_debug_info(void)
688 static char buffer[] = " "; /* looks nicer without anything here */
689 return buffer;
692 /* scsi_debug_proc_info
693 * Used if the driver currently has no own support for /proc/scsi
695 int scsi_debug_proc_info(char *buffer, char **start, off_t offset,
696 int length, int inode, int inout)
698 int len, pos, begin;
699 int orig_length;
701 orig_length = length;
703 if (inout == 1) {
704 /* First check for the Signature */
705 if (length >= 10 && strncmp(buffer, "scsi_debug", 10) == 0) {
706 buffer += 11;
707 length -= 11;
709 if (buffer[length - 1] == '\n') {
710 buffer[length - 1] = '\0';
711 length--;
714 * OK, we are getting some kind of command. Figure out
715 * what we are supposed to do here. Simulate bus lockups
716 * to test our reset capability.
718 if (length == 4 && strncmp(buffer, "test", length) == 0) {
719 printk("Testing send self command %p\n", SHpnt);
720 scsi_debug_send_self_command(SHpnt);
721 return orig_length;
723 if (length == 6 && strncmp(buffer, "lockup", length) == 0) {
724 scsi_debug_lockup = 1;
725 return orig_length;
727 if (length == 6 && strncmp(buffer, "unlock", length) == 0) {
728 scsi_debug_lockup = 0;
729 return orig_length;
731 printk("Unknown command:%s (%d)\n", buffer, length);
732 } else
733 printk("Wrong Signature:%10s\n", (char *) buffer);
735 return -EINVAL;
738 begin = 0;
739 pos = len = sprintf(buffer,
740 "This driver is not a real scsi driver, but it plays one on TV.\n"
741 "It is very handy for debugging specific problems because you\n"
742 "can simulate a variety of error conditions\n");
743 if (pos < offset) {
744 len = 0;
745 begin = pos;
747 *start = buffer + (offset - begin); /* Start of wanted data */
748 len -= (offset - begin);
749 if (len > length)
750 len = length;
752 return (len);
755 #ifdef CONFIG_USER_DEBUG
757 * This is a hack for the user space emulator. It allows us to
758 * "insert" arbitrary numbers of additional drivers.
760 void *scsi_debug_get_handle(void)
762 static Scsi_Host_Template driver_copy = SCSI_DEBUG;
763 void *rtn;
764 rtn = kmalloc(sizeof(driver_copy), GFP_ATOMIC);
765 memcpy(rtn, (void *) &driver_copy, sizeof(driver_copy));
766 return rtn;
768 #endif
770 #ifdef MODULE
771 /* Eventually this will go into an include file, but this will be later */
772 Scsi_Host_Template driver_template = SCSI_DEBUG;
774 #include "scsi_module.c"
775 #endif
778 * Overrides for Emacs so that we almost follow Linus's tabbing style.
779 * Emacs will notice this stuff at the end of the file and automatically
780 * adjust the settings for this buffer only. This must remain at the end
781 * of the file.
782 * ---------------------------------------------------------------------------
783 * Local variables:
784 * c-indent-level: 4
785 * c-brace-imaginary-offset: 0
786 * c-brace-offset: -4
787 * c-argdecl-indent: 4
788 * c-label-offset: -4
789 * c-continued-statement-offset: 4
790 * c-continued-brace-offset: 0
791 * indent-tabs-mode: nil
792 * tab-width: 8
793 * End: