|
|
1.1 root 1: /* $Id: scsi_debug.c,v 1.1.1.1 1997/02/25 21:27:51 thomas Exp $
2: * linux/kernel/scsi_debug.c
3: *
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: */
9:
10: #include <linux/module.h>
11:
12: #include <linux/kernel.h>
13: #include <linux/sched.h>
14: #include <linux/errno.h>
15: #include <linux/timer.h>
16: #include <linux/head.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>
22:
23: #include <asm/system.h>
24: #include <asm/io.h>
25:
26: #ifdef MODULE
27: #include <linux/module.h>
28: #endif
29:
30: #include <linux/blk.h>
31: #include "scsi.h"
32: #include "hosts.h"
33:
34: #include "sd.h"
35:
36: #include<linux/stat.h>
37:
38: struct proc_dir_entry proc_scsi_scsi_debug = {
39: PROC_SCSI_SCSI_DEBUG, 10, "scsi_debug",
40: S_IFDIR | S_IRUGO | S_IXUGO, 2
41: };
42:
43:
44: /* A few options that we want selected */
45:
46: /* Do not attempt to use a timer to simulate a real disk with latency */
47: /* Only use this in the actual kernel, not in the simulator. */
48: #define IMMEDIATE
49:
50: /* Skip some consistency checking. Good for benchmarking */
51: #define SPEEDY
52:
53: /* Number of real scsi disks that will be detected ahead of time */
54: static int NR_REAL=-1;
55:
56: #define NR_BLK_DEV 12
57: #ifndef MAJOR_NR
58: #define MAJOR_NR 8
59: #endif
60: #define START_PARTITION 4
61: #define SCSI_DEBUG_TIMER 20
62: /* Number of jiffies to wait before completing a command */
63: #define DISK_SPEED 10
64: #define CAPACITY (0x80000)
65:
66: static int starts[] = {4, 1000, 50000, CAPACITY, 0};
67: static int npart = 0;
68:
69: #include "scsi_debug.h"
70: #ifdef DEBUG
71: #define DEB(x) x
72: #else
73: #define DEB(x)
74: #endif
75:
76: #ifdef SPEEDY
77: #define VERIFY1_DEBUG(RW) 1
78: #define VERIFY_DEBUG(RW) 1
79: #else
80:
81: #define VERIFY1_DEBUG(RW) \
82: if (bufflen != 1024) {printk("%d", bufflen); panic("(1)Bad bufflen");}; \
83: start = 0; \
84: if ((MINOR(SCpnt->request.rq_dev) & 0xf) != 0) start = starts[(MINOR(SCpnt->request.rq_dev) & 0xf) - 1]; \
85: if (bh){ \
86: if (bh->b_size != 1024) panic ("Wrong bh size"); \
87: if ((bh->b_blocknr << 1) + start != block) \
88: { printk("Wrong bh block# %d %d ",bh->b_blocknr, block); \
89: panic ("Wrong bh block#"); \
90: }; \
91: if (bh->b_dev != SCpnt->request.rq_dev) \
92: panic ("Bad bh target"); \
93: };
94:
95: #define VERIFY_DEBUG(RW) \
96: if (bufflen != 1024 && (!SCpnt->use_sg)) {printk("%x %d\n ",bufflen, SCpnt->use_sg); panic("Bad bufflen");}; \
97: start = 0; \
98: if ((MINOR(SCpnt->request.rq_dev) & 0xf) > npart) panic ("Bad partition"); \
99: if ((MINOR(SCpnt->request.rq_dev) & 0xf) != 0) start = starts[(MINOR(SCpnt->request.rq_dev) & 0xf) - 1]; \
100: if (SCpnt->request.cmd != RW) panic ("Wrong operation"); \
101: if (SCpnt->request.sector + start != block) panic("Wrong block."); \
102: if (SCpnt->request.current_nr_sectors != 2 && (!SCpnt->use_sg)) panic ("Wrong # blocks"); \
103: if (SCpnt->request.bh){ \
104: if (SCpnt->request.bh->b_size != 1024) panic ("Wrong bh size"); \
105: if ((SCpnt->request.bh->b_blocknr << 1) + start != block) \
106: { printk("Wrong bh block# %d %d ",SCpnt->request.bh->b_blocknr, block); \
107: panic ("Wrong bh block#"); \
108: }; \
109: if (SCpnt->request.bh->b_dev != SCpnt->request.rq_dev) \
110: panic ("Bad bh target");\
111: };
112: #endif
113:
114: static volatile void (*do_done[SCSI_DEBUG_MAILBOXES])(Scsi_Cmnd *) = {NULL, };
115: extern void scsi_debug_interrupt();
116:
117: volatile Scsi_Cmnd * SCint[SCSI_DEBUG_MAILBOXES] = {NULL,};
118: static char SCrst[SCSI_DEBUG_MAILBOXES] = {0,};
119: static volatile unsigned int timeout[8] ={0,};
120:
121: /*
122: * Semaphore used to simulate bus lockups.
123: */
124: static int scsi_debug_lockup = 0;
125:
126: static char sense_buffer[128] = {0,};
127:
128: static void scsi_dump(Scsi_Cmnd * SCpnt, int flag){
129: int i;
130: #if 0
131: unsigned char * pnt;
132: #endif
133: unsigned int * lpnt;
134: struct scatterlist * sgpnt = NULL;
135: printk("use_sg: %d",SCpnt->use_sg);
136: if (SCpnt->use_sg){
137: sgpnt = (struct scatterlist *) SCpnt->buffer;
138: for(i=0; i<SCpnt->use_sg; i++) {
139: lpnt = (int *) sgpnt[i].alt_address;
140: printk(":%x %x %d\n",sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
141: if (lpnt) printk(" (Alt %x) ",lpnt[15]);
142: };
143: } else {
144: printk("nosg: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
145: SCpnt->bufflen);
146: lpnt = (int *) SCpnt->request.buffer;
147: if (lpnt) printk(" (Alt %x) ",lpnt[15]);
148: };
149: lpnt = (unsigned int *) SCpnt;
150: for (i=0;i<sizeof(Scsi_Cmnd)/4+1; i++) {
151: if ((i & 7) == 0) printk("\n");
152: printk("%x ",*lpnt++);
153: };
154: printk("\n");
155: if (flag == 0) return;
156: lpnt = (unsigned int *) sgpnt[0].alt_address;
157: for (i=0;i<sizeof(Scsi_Cmnd)/4+1; i++) {
158: if ((i & 7) == 0) printk("\n");
159: printk("%x ",*lpnt++);
160: };
161: #if 0
162: printk("\n");
163: lpnt = (unsigned int *) sgpnt[0].address;
164: for (i=0;i<sizeof(Scsi_Cmnd)/4+1; i++) {
165: if ((i & 7) == 0) printk("\n");
166: printk("%x ",*lpnt++);
167: };
168: printk("\n");
169: #endif
170: printk("DMA free %d sectors.\n", dma_free_sectors);
171: }
172:
173: int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
174: {
175: unchar *cmd = (unchar *) SCpnt->cmnd;
176: struct partition * p;
177: int block, start;
178: struct buffer_head * bh = NULL;
179: unsigned char * buff;
180: int nbytes, sgcount;
181: int scsi_debug_errsts;
182: struct scatterlist * sgpnt;
183: int target = SCpnt->target;
184: int bufflen = SCpnt->request_bufflen;
185: unsigned long flags;
186: int i;
187: sgcount = 0;
188: sgpnt = NULL;
189:
190: DEB(if (target > 1) { SCpnt->result = DID_TIME_OUT << 16;done(SCpnt);return 0;});
191:
192: buff = (unsigned char *) SCpnt->request_buffer;
193:
194: if(target>=1 || SCpnt->lun != 0) {
195: SCpnt->result = DID_NO_CONNECT << 16;
196: done(SCpnt);
197: return 0;
198: };
199:
200: if( SCrst[target] != 0 && !scsi_debug_lockup )
201: {
202: SCrst[target] = 0;
203: memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
204: SCpnt->sense_buffer[0] = 0x70;
205: SCpnt->sense_buffer[2] = UNIT_ATTENTION;
206: SCpnt->result = (CHECK_CONDITION << 1);
207: done(SCpnt);
208: }
209: switch(*cmd){
210: case REQUEST_SENSE:
211: printk("Request sense...\n");
212: #ifndef DEBUG
213: {
214: int i;
215: printk("scsi_debug: Requesting sense buffer (%x %x %x %d):", SCpnt, buff, done, bufflen);
216: for(i=0;i<12;i++) printk("%d ",sense_buffer[i]);
217: printk("\n");
218: };
219: #endif
220: memset(buff, 0, bufflen);
221: memcpy(buff, sense_buffer, bufflen);
222: memset(sense_buffer, 0, sizeof(sense_buffer));
223: SCpnt->result = 0;
224: done(SCpnt);
225: return 0;
226: case ALLOW_MEDIUM_REMOVAL:
227: if(cmd[4]) printk("Medium removal inhibited...");
228: else printk("Medium removal enabled...");
229: scsi_debug_errsts = 0;
230: break;
231: case INQUIRY:
232: printk("Inquiry...(%x %d)\n", buff, bufflen);
233: memset(buff, 0, bufflen);
234: buff[0] = TYPE_DISK;
235: buff[1] = 0x80; /* Removable disk */
236: buff[2] = 1;
237: buff[4] = 33 - 5;
238: memcpy(&buff[8],"Foo Inc",7);
239: memcpy(&buff[16],"XYZZY",5);
240: memcpy(&buff[32],"1",1);
241: scsi_debug_errsts = 0;
242: break;
243: case TEST_UNIT_READY:
244: printk("Test unit ready(%x %d)\n", buff, bufflen);
245: if (buff)
246: memset(buff, 0, bufflen);
247: scsi_debug_errsts = 0;
248: break;
249: case READ_CAPACITY:
250: printk("Read Capacity\n");
251: if(NR_REAL < 0) NR_REAL = (MINOR(SCpnt->request.rq_dev) >> 4) & 0x0f;
252: memset(buff, 0, bufflen);
253: buff[0] = (CAPACITY >> 24);
254: buff[1] = (CAPACITY >> 16) & 0xff;
255: buff[2] = (CAPACITY >> 8) & 0xff;
256: buff[3] = CAPACITY & 0xff;
257: buff[6] = 2; /* 512 byte sectors */
258: scsi_debug_errsts = 0;
259: break;
260: case READ_10:
261: case READ_6:
262: #ifdef DEBUG
263: printk("Read...");
264: #endif
265: if ((*cmd) == READ_10)
266: block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
267: else
268: block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
269: VERIFY_DEBUG(READ);
270: #if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE)
271: {
272: int delay = SCSI_SETUP_LATENCY;
273: double usec;
274:
275: usec = 0.0;
276: usec = (SCpnt->request.nr_sectors << 9) * 1.0e6 / SCSI_DATARATE;
277: delay += usec;
278: if(delay) usleep(delay);
279: };
280: #endif
281:
282: #ifdef DEBUG
283: printk("(r%d)",SCpnt->request.nr_sectors);
284: #endif
285: nbytes = bufflen;
286: if(SCpnt->use_sg){
287: sgcount = 0;
288: sgpnt = (struct scatterlist *) buff;
289: buff = sgpnt[sgcount].address;
290: bufflen = sgpnt[sgcount].length;
291: bh = SCpnt->request.bh;
292: };
293: scsi_debug_errsts = 0;
294: do{
295: VERIFY1_DEBUG(READ);
296: /* For the speedy test, we do not even want to fill the buffer with anything */
297: #ifndef SPEEDY
298: memset(buff, 0, bufflen);
299: #endif
300: /* If this is block 0, then we want to read the partition table for this
301: * device. Let's make one up */
302: if(block == 0 && target == 0) {
303: memset(buff, 0, bufflen);
304: *((unsigned short *) (buff+510)) = 0xAA55;
305: p = (struct partition* ) (buff + 0x1be);
306: npart = 0;
307: while(starts[npart+1]){
308: p->start_sect = starts[npart];
309: p->nr_sects = starts[npart+1] - starts [npart];
310: p->sys_ind = 0x81; /* Linux partition */
311: p++;
312: npart++;
313: };
314: scsi_debug_errsts = 0;
315: break;
316: };
317: #ifdef DEBUG
318: if (SCpnt->use_sg) printk("Block %x (%d %d)\n",block, SCpnt->request.nr_sectors,
319: SCpnt->request.current_nr_sectors);
320: #endif
321:
322: #if 0
323: /* Simulate a disk change */
324: if(block == 0xfff0) {
325: sense_buffer[0] = 0x70;
326: sense_buffer[2] = UNIT_ATTENTION;
327: starts[0] += 10;
328: starts[1] += 10;
329: starts[2] += 10;
330:
331: #ifdef DEBUG
332: {
333: int i;
334: printk("scsi_debug: Filling sense buffer:");
335: for(i=0;i<12;i++) printk("%d ",sense_buffer[i]);
336: printk("\n");
337: };
338: #endif
339: scsi_debug_errsts = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
340: break;
341: } /* End phony disk change code */
342: #endif
343:
344: #ifndef SPEEDY
345: memcpy(buff, &target, sizeof(target));
346: memcpy(buff+sizeof(target), cmd, 24);
347: memcpy(buff+60, &block, sizeof(block));
348: memcpy(buff+64, SCpnt, sizeof(Scsi_Cmnd));
349: #endif
350: nbytes -= bufflen;
351: if(SCpnt->use_sg){
352: #ifndef SPEEDY
353: memcpy(buff+128, bh, sizeof(struct buffer_head));
354: #endif
355: block += bufflen >> 9;
356: bh = bh->b_reqnext;
357: sgcount++;
358: if (nbytes) {
359: if(!bh) panic("Too few blocks for linked request.");
360: buff = sgpnt[sgcount].address;
361: bufflen = sgpnt[sgcount].length;
362: };
363: }
364: } while(nbytes);
365:
366: SCpnt->result = 0;
367: (done)(SCpnt);
368: return;
369:
370: if (SCpnt->use_sg && !scsi_debug_errsts)
371: if(bh) scsi_dump(SCpnt, 0);
372: break;
373: case WRITE_10:
374: case WRITE_6:
375: #ifdef DEBUG
376: printk("Write\n");
377: #endif
378: if ((*cmd) == WRITE_10)
379: block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
380: else
381: block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
382: VERIFY_DEBUG(WRITE);
383: /* printk("(w%d)",SCpnt->request.nr_sectors); */
384: if (SCpnt->use_sg){
385: if ((bufflen >> 9) != SCpnt->request.nr_sectors)
386: panic ("Trying to write wrong number of blocks\n");
387: sgpnt = (struct scatterlist *) buff;
388: buff = sgpnt[sgcount].address;
389: };
390: #if 0
391: if (block != *((unsigned long *) (buff+60))) {
392: printk("%x %x :",block, *((unsigned long *) (buff+60)));
393: scsi_dump(SCpnt,1);
394: panic("Bad block written.\n");
395: };
396: #endif
397: scsi_debug_errsts = 0;
398: break;
399: default:
400: printk("Unknown command %d\n",*cmd);
401: SCpnt->result = DID_NO_CONNECT << 16;
402: done(SCpnt);
403: return 0;
404: };
405:
406: save_flags(flags);
407: cli();
408: for(i=0;i<SCSI_DEBUG_MAILBOXES; i++){
409: if (SCint[i] == 0) break;
410: };
411:
412: if (i >= SCSI_DEBUG_MAILBOXES || SCint[i] != 0)
413: panic("Unable to find empty SCSI_DEBUG command slot.\n");
414:
415: SCint[i] = SCpnt;
416:
417: if (done) {
418: DEB(printk("scsi_debug_queuecommand: now waiting for interrupt "););
419: if (do_done[i])
420: printk("scsi_debug_queuecommand: Two concurrent queuecommand?\n");
421: else
422: do_done[i] = done;
423: }
424: else
425: printk("scsi_debug_queuecommand: done cant be NULL\n");
426:
427: #ifdef IMMEDIATE
428: if( !scsi_debug_lockup )
429: {
430: SCpnt->result = scsi_debug_errsts;
431: scsi_debug_intr_handle(); /* No timer - do this one right away */
432: }
433: restore_flags(flags);
434: #else
435: timeout[i] = jiffies+DISK_SPEED;
436:
437: /* If no timers active, then set this one */
438: if ((timer_active & (1 << SCSI_DEBUG_TIMER)) == 0) {
439: timer_table[SCSI_DEBUG_TIMER].expires = timeout[i];
440: timer_active |= 1 << SCSI_DEBUG_TIMER;
441: };
442:
443: SCpnt->result = scsi_debug_errsts;
444: restore_flags(flags);
445:
446: #if 0
447: printk("Sending command (%d %x %d %d)...", i, done, timeout[i],jiffies);
448: #endif
449: #endif
450:
451: return 0;
452: }
453:
454: volatile static int internal_done_flag = 0;
455: volatile static int internal_done_errcode = 0;
456: static void internal_done(Scsi_Cmnd * SCpnt)
457: {
458: internal_done_errcode = SCpnt->result;
459: ++internal_done_flag;
460: }
461:
462: int scsi_debug_command(Scsi_Cmnd * SCpnt)
463: {
464: DEB(printk("scsi_debug_command: ..calling scsi_debug_queuecommand\n"));
465: scsi_debug_queuecommand(SCpnt, internal_done);
466:
467: while (!internal_done_flag);
468: internal_done_flag = 0;
469: return internal_done_errcode;
470: }
471:
472: /* A "high" level interrupt handler. This should be called once per jiffy
473: * to simulate a regular scsi disk. We use a timer to do this. */
474:
475: static void scsi_debug_intr_handle(void)
476: {
477: Scsi_Cmnd * SCtmp;
478: int i, pending;
479: void (*my_done)(Scsi_Cmnd *);
480: unsigned long flags;
481: int to;
482:
483: #ifndef IMMEDIATE
484: timer_table[SCSI_DEBUG_TIMER].expires = 0;
485: timer_active &= ~(1 << SCSI_DEBUG_TIMER);
486: #endif
487:
488: repeat:
489: save_flags(flags);
490: cli();
491: for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
492: if (SCint[i] == 0) continue;
493: #ifndef IMMEDIATE
494: if (timeout[i] == 0) continue;
495: if (timeout[i] <= jiffies) break;
496: #else
497: break;
498: #endif
499: };
500:
501: if(i == SCSI_DEBUG_MAILBOXES){
502: #ifndef IMMEDIATE
503: pending = INT_MAX;
504: for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
505: if (SCint[i] == 0) continue;
506: if (timeout[i] == 0) continue;
507: if (timeout[i] <= jiffies) {restore_flags(flags); goto repeat;};
508: if (timeout[i] > jiffies) {
509: if (pending > timeout[i]) pending = timeout[i];
510: continue;
511: };
512: };
513: if (pending && pending != INT_MAX) {
514: timer_table[SCSI_DEBUG_TIMER].expires =
515: (pending <= jiffies ? jiffies+1 : pending);
516: timer_active |= 1 << SCSI_DEBUG_TIMER;
517: };
518: restore_flags(flags);
519: #endif
520: return;
521: };
522:
523: if(i < SCSI_DEBUG_MAILBOXES){
524: timeout[i] = 0;
525: my_done = do_done[i];
526: do_done[i] = NULL;
527: to = timeout[i];
528: timeout[i] = 0;
529: SCtmp = (Scsi_Cmnd *) SCint[i];
530: SCint[i] = NULL;
531: restore_flags(flags);
532:
533: if (!my_done) {
534: printk("scsi_debug_intr_handle: Unexpected interrupt\n");
535: return;
536: }
537:
538: #ifdef DEBUG
539: printk("In intr_handle...");
540: printk("...done %d %x %d %d\n",i , my_done, to, jiffies);
541: printk("In intr_handle: %d %x %x\n",i, SCtmp, my_done);
542: #endif
543:
544: my_done(SCtmp);
545: #ifdef DEBUG
546: printk("Called done.\n");
547: #endif
548: };
549: goto repeat;
550: }
551:
552:
553: int scsi_debug_detect(Scsi_Host_Template * tpnt)
554: {
555: tpnt->proc_dir = &proc_scsi_scsi_debug;
556: #ifndef IMMEDIATE
557: timer_table[SCSI_DEBUG_TIMER].fn = scsi_debug_intr_handle;
558: timer_table[SCSI_DEBUG_TIMER].expires = 0;
559: #endif
560: return 1;
561: }
562:
563: int scsi_debug_abort(Scsi_Cmnd * SCpnt)
564: {
565: int j;
566: void (*my_done)(Scsi_Cmnd *);
567: unsigned long flags;
568:
569: DEB(printk("scsi_debug_abort\n"));
570: #if 0
571: SCpnt->result = SCpnt->abort_reason << 16;
572: for(j=0;j<SCSI_DEBUG_MAILBOXES; j++) {
573: if(SCpnt == SCint[j]) {
574: my_done = do_done[j];
575: my_done(SCpnt);
576: save_flags(flags);
577: cli();
578: timeout[j] = 0;
579: SCint[j] = NULL;
580: do_done[j] = NULL;
581: restore_flags(flags);
582: };
583: };
584: #endif
585: return SCSI_ABORT_SNOOZE;
586: }
587:
588: int scsi_debug_biosparam(Disk * disk, kdev_t dev, int* info){
589: int size = disk->capacity;
590: info[0] = 32;
591: info[1] = 64;
592: info[2] = (size + 2047) >> 11;
593: if (info[2] >= 1024) info[2] = 1024;
594: return 0;
595: }
596:
597: int scsi_debug_reset(Scsi_Cmnd * SCpnt)
598: {
599: int i;
600: unsigned long flags;
601:
602: void (*my_done)(Scsi_Cmnd *);
603: printk("Bus unlocked by reset(%d)\n", SCpnt->host->suggest_bus_reset);
604: scsi_debug_lockup = 0;
605: DEB(printk("scsi_debug_reset called\n"));
606: for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
607: if (SCint[i] == NULL) continue;
608: SCint[i]->result = DID_RESET << 16;
609: my_done = do_done[i];
610: my_done(SCint[i]);
611: save_flags(flags);
612: cli();
613: SCint[i] = NULL;
614: do_done[i] = NULL;
615: timeout[i] = 0;
616: restore_flags(flags);
617: }
618: return SCSI_RESET_SUCCESS;
619: }
620:
621: const char *scsi_debug_info(void)
622: {
623: static char buffer[] = " "; /* looks nicer without anything here */
624: return buffer;
625: }
626:
627: /* scsi_debug_proc_info
628: * Used if the driver currently has no own support for /proc/scsi
629: */
630: int scsi_debug_proc_info(char *buffer, char **start, off_t offset,
631: int length, int inode, int inout)
632: {
633: int len, pos, begin;
634: int orig_length;
635:
636: if(inout == 1)
637: {
638: /* First check for the Signature */
639: if (length >= 10 && strncmp(buffer, "scsi_debug", 10) == 0) {
640: buffer += 11;
641: length -= 11;
642: /*
643: * OK, we are getting some kind of command. Figure out
644: * what we are supposed to do here. Simulate bus lockups
645: * to test our reset capability.
646: */
647: if( length == 6 && strncmp(buffer, "lockup", length) == 0 )
648: {
649: scsi_debug_lockup = 1;
650: return length;
651: }
652:
653: if( length == 6 && strncmp(buffer, "unlock", length) == 0 )
654: {
655: scsi_debug_lockup = 0;
656: return length;
657: }
658:
659: printk("Unknown command:%s\n", buffer);
660: } else
661: printk("Wrong Signature:%10s\n", (char *) ((ulong)buffer-11));
662:
663: return -EINVAL;
664:
665: }
666:
667: begin = 0;
668: pos = len = sprintf(buffer,
669: "This driver is not a real scsi driver, but it plays one on TV.\n"
670: "It is very handy for debugging specific problems because you\n"
671: "can simulate a variety of error conditions\n");
672: if(pos < offset)
673: {
674: len = 0;
675: begin = pos;
676: }
677:
678: *start = buffer + (offset - begin); /* Start of wanted data */
679: len -= (offset - begin);
680: if(len > length)
681: len = length;
682:
683: return(len);
684: }
685:
686: #ifdef MODULE
687: /* Eventually this will go into an include file, but this will be later */
688: Scsi_Host_Template driver_template = SCSI_DEBUG;
689:
690: #include "scsi_module.c"
691: #endif
692:
693: /*
694: * Overrides for Emacs so that we almost follow Linus's tabbing style.
695: * Emacs will notice this stuff at the end of the file and automatically
696: * adjust the settings for this buffer only. This must remain at the end
697: * of the file.
698: * ---------------------------------------------------------------------------
699: * Local variables:
700: * c-indent-level: 4
701: * c-brace-imaginary-offset: 0
702: * c-brace-offset: -4
703: * c-argdecl-indent: 4
704: * c-label-offset: -4
705: * c-continued-statement-offset: 4
706: * c-continued-brace-offset: 0
707: * indent-tabs-mode: nil
708: * tab-width: 8
709: * End:
710: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.