root/drivers/scsi/scsi_debug.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. scsi_dump
  2. scsi_debug_queuecommand
  3. internal_done
  4. scsi_debug_command
  5. scsi_debug_intr_handle
  6. scsi_debug_detect
  7. scsi_debug_abort
  8. scsi_debug_biosparam
  9. scsi_debug_reset
  10. scsi_debug_info
  11. scsi_debug_proc_info

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

/* [previous][next][first][last][top][bottom][index][help] */