home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / drivers / scsi / scsi_debug.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-01  |  15.4 KB  |  589 lines

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