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 / in2000.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-06  |  21.0 KB  |  720 lines

  1. /*
  2.  *  This file is in2000.c, written and
  3.  *  Copyright (C) 1993  Brad McLean
  4.  *    Last edit 1/19/95 TZ
  5.  * Disclaimer:
  6.  * Note:  This is ugly.  I know it, I wrote it, but my whole
  7.  * focus was on getting the damn thing up and out quickly.
  8.  * Future stuff that would be nice:  Command chaining, and
  9.  * a local queue of commands would speed stuff up considerably.
  10.  * Disconnection needs some supporting code.  All of this
  11.  * is beyond the scope of what I wanted to address, but if you
  12.  * have time and patience, more power to you.
  13.  * Also, there are some constants scattered throughout that
  14.  * should have defines, and I should have built functions to
  15.  * address the registers on the WD chip.
  16.  * Oh well, I'm out of time for this project.
  17.  * The one good thing to be said is that you can use the card.
  18.  */
  19.  
  20. /*
  21.  * This module was updated by Shaun Savage first on 5-13-93
  22.  * At that time the write was fixed, irq detection, and some
  23.  * timing stuff.  since that time other problems were fixed.
  24.  * On 7-20-93 this file was updated for patch level 11
  25.  * There are still problems with it but it work on 95% of
  26.  * the machines.  There are still problems with it working with
  27.  * IDE drives, as swap drive and HD that support reselection.
  28.  * But for most people it will work.
  29.  */
  30. /* More changes by Bill Earnest, wde@aluxpo.att.com
  31.  * through 4/07/94. Includes rewrites of FIFO routines,
  32.  * length-limited commands to make swap partitions work.
  33.  * Merged the changes released by Larry Doolittle, based on input
  34.  * from Jon Luckey, Roger Sunshine, John Shifflett. The FAST_FIFO
  35.  * doesn't work for me. Scatter-gather code from Eric. The change to
  36.  * an IF stmt. in the interrupt routine finally made it stable.
  37.  * Limiting swap request size patch to ll_rw_blk.c not needed now.
  38.  * Please ignore the clutter of debug stmts., pretty can come later.
  39.  */
  40. /* Merged code from Matt Postiff improving the auto-sense validation
  41.  * for all I/O addresses. Some reports of problems still come in, but
  42.  * have been unable to reproduce or localize the cause. Some are from
  43.  * LUN > 0 problems, but that is not host specific. Now 6/6/94.
  44.  */
  45. /* Changes for 1.1.28 kernel made 7/19/94, code not affected. (WDE)
  46.  */
  47. /* Changes for 1.1.43+ kernels made 8/25/94, code added to check for
  48.  * new BIOS version, derived by jshiffle@netcom.com. (WDE)
  49.  *
  50.  * 1/7/95 Fix from Peter Lu (swift@world.std.com) for datalen vs. dataptr
  51.  * logic, much more stable under load.
  52.  *
  53.  * 1/19/95 (zerucha@shell.portal.com) Added module and biosparam support for
  54.  * larger SCSI hard drives (untested).
  55.  */
  56.  
  57. #include <linux/kernel.h>
  58. #include <linux/head.h>
  59. #include <linux/types.h>
  60. #include <linux/string.h>
  61.  
  62. #include <linux/sched.h>
  63. #include <asm/dma.h>
  64.  
  65. #include <asm/system.h>
  66. #include <asm/io.h>
  67. #include "../block/blk.h"
  68. #include "scsi.h"
  69. #include "hosts.h"
  70. #include "sd.h"
  71.  
  72. #include "in2000.h"
  73.  
  74. /*#define FAST_FIFO_IO*/
  75.  
  76. /*#define DEBUG*/
  77. #ifdef DEBUG
  78. #define DEB(x) x
  79. #else
  80. #define DEB(x)
  81. #endif
  82.  
  83. /* These functions are based on include/asm/io.h */
  84. #ifndef inw
  85. inline static unsigned short inw( unsigned short port )
  86. {
  87.    unsigned short _v;
  88.    
  89.    __asm__ volatile ("inw %1,%0"
  90.              :"=a" (_v):"d" ((unsigned short) port));
  91.    return _v;
  92. }
  93. #endif
  94.  
  95. #ifndef outw
  96. inline static void outw( unsigned short value, unsigned short port )
  97. {
  98.    __asm__ volatile ("outw %0,%1"
  99.             : /* no outputs */
  100.             :"a" ((unsigned short) value),
  101.             "d" ((unsigned short) port));
  102. }
  103. #endif
  104.  
  105. /* These functions are lifted from drivers/block/hd.c */
  106.  
  107. #define port_read(port,buf,nr) \
  108. __asm__("cld;rep;insw": :"d" (port),"D" (buf),"c" (nr):"cx","di")
  109.  
  110. #define port_write(port,buf,nr) \
  111. __asm__("cld;rep;outsw": :"d" (port),"S" (buf),"c" (nr):"cx","si")
  112.  
  113. static unsigned int base;
  114. static unsigned int ficmsk;
  115. static unsigned char irq_level;
  116. static int in2000_datalen;
  117. static unsigned int in2000_nsegment;
  118. static unsigned int in2000_current_segment;
  119. static unsigned short *in2000_dataptr;
  120. static char    in2000_datawrite;
  121. static struct scatterlist * in2000_scatter;
  122. static Scsi_Cmnd *in2000_SCptr = 0;
  123.  
  124. static void (*in2000_done)(Scsi_Cmnd *);
  125.  
  126. static int in2000_test_port(int index)
  127. {
  128.     static const int *bios_tab[] = {
  129.     (int *) 0xc8000, (int *) 0xd0000, (int *) 0xd8000 };
  130.     int    i;
  131.     char    tmp;
  132.  
  133.     tmp = inb(INFLED);
  134.     /* First, see if the DIP switch values are valid */
  135.     /* The test of B7 may fail on some early boards, mine works. */
  136.     if ( ((~tmp & 0x3) != index ) || (tmp & 0x80) || !(tmp & 0x4) )
  137.         return 0;
  138.     printk("IN-2000 probe got dip setting of %02X\n", tmp);
  139.     tmp = inb(INVERS);
  140. /* Add some extra sanity checks here */
  141.     for(i=0; i < 3; i++)
  142.     if(*(bios_tab[i]+0x04) == 0x41564f4e ||
  143.         *(bios_tab[i]+0xc) == 0x61776c41) {
  144.       printk("IN-2000 probe found hdw. vers. %02x, BIOS at %06x\n",
  145.         tmp, (unsigned int)bios_tab[i]);
  146.         return 1;
  147.     }
  148.     printk("in2000 BIOS not found.\n");
  149.     return 0;
  150. }
  151.  
  152.  
  153. /*
  154.  * retrieve the current transaction counter from the WD
  155.  */
  156.  
  157. static unsigned in2000_txcnt(void)
  158. {
  159.     unsigned total=0;
  160.  
  161.     if(inb(INSTAT) & 0x20) return 0xffffff;    /* not readable now */
  162.     outb(TXCNTH,INSTAT);    /* then autoincrement */
  163.     total =  (inb(INDATA) & 0xff) << 16;
  164.     outb(TXCNTM,INSTAT);
  165.     total += (inb(INDATA) & 0xff) << 8;
  166.     outb(TXCNTL,INSTAT);
  167.     total += (inb(INDATA) & 0xff);
  168.     return total;
  169. }
  170.  
  171. /*
  172.  * Note: the FIFO is screwy, and has a counter granularity of 16 bytes, so
  173.  * we have to reconcile the FIFO counter, the transaction byte count from the
  174.  * WD chip, and of course, our desired transaction size.  It may look strange,
  175.  * and could probably use improvement, but it works, for now.
  176.  */
  177.  
  178. static void in2000_fifo_out(void)    /* uses FIFOCNTR */
  179. {
  180.     unsigned count, infcnt, txcnt;
  181.  
  182.     infcnt = inb(INFCNT)& 0xfe;    /* FIFO counter */
  183.     do {
  184.     txcnt = in2000_txcnt();
  185. /*DEB(printk("FIw:%d %02x %d\n", in2000_datalen, infcnt, txcnt));*/
  186.     count = (infcnt << 3) - 32;    /* don't fill completely */
  187.     if ( count > in2000_datalen )
  188.         count = in2000_datalen;    /* limit to actual data on hand */
  189.     count >>= 1;        /* Words, not bytes */
  190. #ifdef FAST_FIFO_IO
  191.     if ( count ) {
  192.         port_write(INFIFO, in2000_dataptr, count);
  193.         in2000_datalen -= (count<<1);
  194.     }
  195. #else
  196.     while ( count-- )
  197.         {
  198.         outw(*in2000_dataptr++, INFIFO);
  199.         in2000_datalen -= 2;
  200.         }
  201. #endif
  202.     } while((in2000_datalen > 0) && ((infcnt = (inb(INFCNT)) & 0xfe) >= 0x20) );
  203.     /* If scatter-gather, go on to next segment */
  204.     if( !in2000_datalen && ++in2000_current_segment < in2000_nsegment)
  205.       {
  206.       in2000_scatter++;
  207.       in2000_datalen = in2000_scatter->length;
  208.       in2000_dataptr = (unsigned short*)in2000_scatter->address;
  209.       }
  210.     if ( in2000_datalen <= 0 )
  211.     {
  212.     ficmsk = 0;
  213.     count = 32;    /* Always says to use this much flush */
  214.     while ( count-- )
  215.         outw(0, INFIFO);
  216.     outb(2, ININTR); /* Mask FIFO Interrupts when done */
  217.     }
  218. }
  219.  
  220. static void in2000_fifo_in(void)    /* uses FIFOCNTR */
  221. {
  222.     unsigned fic, count, count2;
  223.  
  224.     count = inb(INFCNT) & 0xe1;
  225.     do{
  226.     count2 = count;
  227.     count = (fic = inb(INFCNT)) & 0xe1;
  228.     } while ( count != count2 );
  229. DEB(printk("FIir:%d %02x %08x\n", in2000_datalen,fic,(unsigned int )in2000_dataptr));
  230.     do {
  231.     count2 = in2000_txcnt();    /* bytes yet to come over SCSI bus */
  232. DEB(printk("FIr:%d %02x %08x %08x\n", in2000_datalen,fic,count2,(unsigned int)in2000_dataptr));
  233.     if(count2 > 65536) count2 = 0;
  234.     if(fic > 128) count = 1024;
  235.       else if(fic > 64) count = 512;
  236.         else if (fic > 32) count = 256;
  237.           else if ( count2 < in2000_datalen ) /* if drive has < what we want */
  238.             count = in2000_datalen - count2;    /* FIFO has the rest */
  239.     if ( count > in2000_datalen )    /* count2 is lesser of FIFO & rqst */
  240.         count2 = in2000_datalen >> 1;    /* converted to word count */
  241.     else
  242.         count2 = count >> 1;
  243.     count >>= 1;        /* also to words */
  244.     count -= count2;    /* extra left over in FIFO */
  245. #ifdef FAST_FIFO_IO
  246.     if ( count2 ) {
  247.         port_read(INFIFO, in2000_dataptr, count2);
  248.         in2000_datalen -= (count2<<1);
  249.     }
  250. #else
  251.     while ( count2-- )
  252.     {
  253.         *in2000_dataptr++ = inw(INFIFO);
  254.         in2000_datalen -=2;
  255.     }
  256. #endif
  257.     } while((in2000_datalen > 0) && (fic = inb(INFCNT)) );
  258. DEB(printk("FIer:%d %02x %08x\n", in2000_datalen,fic,(unsigned int )in2000_dataptr));
  259. /*    while ( count-- )
  260.         inw(INFIFO);*/    /* Throw away some extra stuff */
  261.     if( !in2000_datalen && ++in2000_current_segment < in2000_nsegment)
  262.       {
  263.       in2000_scatter++;
  264.       in2000_datalen = in2000_scatter->length;
  265.       in2000_dataptr = (unsigned short*)in2000_scatter->address;
  266.       }
  267.     if ( ! in2000_datalen ){
  268.     outb(2, ININTR); /* Mask FIFO Interrupts when done */
  269.     ficmsk = 0;}
  270. }
  271.  
  272. static void in2000_intr_handle(int irq, struct pt_regs *regs)
  273. {
  274.     int result=0;
  275.     unsigned int count,auxstatus,scsistatus,cmdphase,scsibyte;
  276.     int action=0;
  277.     Scsi_Cmnd *SCptr;
  278.  
  279.   DEB(printk("INT:%d %02x %08x\n", in2000_datalen, inb(INFCNT),(unsigned int)in2000_dataptr));
  280.  
  281.     if (( (ficmsk & (count = inb(INFCNT))) == 0xfe ) ||
  282.         ( (inb(INSTAT) & 0x8c) == 0x80))
  283.     {    /* FIFO interrupt or WD interrupt */
  284.        auxstatus = inb(INSTAT);    /* need to save now */
  285.        outb(SCSIST,INSTAT);
  286.        scsistatus = inb(INDATA); /* This clears the WD intrpt bit */
  287.        outb(TARGETU,INSTAT);    /* then autoincrement */
  288.        scsibyte = inb(INDATA);    /* Get the scsi status byte */
  289.        outb(CMDPHAS,INSTAT);
  290.        cmdphase = inb(INDATA);
  291.        DEB(printk("(int2000:%02x %02x %02x %02x %02x)\n",count,auxstatus,
  292.         scsistatus,cmdphase,scsibyte));
  293.  
  294.     /* Why do we assume that we need to send more data here??? ERY */
  295.        if ( in2000_datalen )    /* data xfer pending */
  296.            {
  297.            if ( in2000_dataptr == NULL )
  298.         printk("int2000: dataptr=NULL datalen=%d\n",
  299.             in2000_datalen);
  300.         else if ( in2000_datawrite )
  301.         in2000_fifo_out();
  302.         else
  303.         in2000_fifo_in();
  304.            } 
  305.     if ( (auxstatus & 0x8c) == 0x80 )
  306.         {    /* There is a WD Chip interrupt & register read good */
  307.         outb(2,ININTR);    /* Disable fifo interrupts */
  308.         ficmsk = 0;
  309.         result = DID_OK << 16;
  310.         /* 16=Select & transfer complete, 85=got disconnect */
  311.         if ((scsistatus != 0x16) && (scsistatus != 0x85)
  312.         && (scsistatus != 0x42)){
  313. /*           printk("(WDi2000:%02x %02x %02x %02x %02x)\n",count,auxstatus,
  314.             scsistatus,cmdphase,scsibyte);*/
  315. /*        printk("QDAT:%d %08x %02x\n",
  316.         in2000_datalen,(unsigned int)in2000_dataptr,ficmsk);*/
  317.         ;
  318.         }
  319.         switch ( scsistatus & 0xf0 )
  320.             {
  321.             case    0x00:    /* Card Reset Completed */
  322.             action = 3;
  323.             break;
  324.             case    0x10:    /* Successful Command Completion */
  325.             if ( scsistatus & 0x8 )
  326.                     action = 1;
  327.             break;
  328.             case    0x20:    /* Command Paused or Aborted */
  329.             if ( (scsistatus & 0x8) )
  330.                     action = 1;
  331.             else if ( (scsistatus & 7) < 2 )
  332.                     action = 2;
  333.                  else
  334.                     result = DID_ABORT << 16;
  335.             break;
  336.             case    0x40:    /* Terminated early */
  337.             if ( scsistatus & 0x8 )
  338.                      action = 1;
  339.             else if ( (scsistatus & 7) > 2 )
  340.                      action = 2;
  341.                  else
  342.                     result = DID_TIME_OUT << 16;
  343.             break;
  344.             case    0x80:    /* Service Required from SCSI bus */
  345.             if ( scsistatus & 0x8 )
  346.                 action = 1;
  347.             else
  348.                 action = 2;
  349.             break;
  350.             }        /* end switch(scsistatus) */
  351.         outb(0,INFLED);
  352.         switch ( action )
  353.             {
  354.             case    0x02:    /* Issue an abort */
  355.             outb(COMMAND,INSTAT);
  356.             outb(1,INDATA);     /* ABORT COMMAND */
  357.             result = DID_ABORT << 16;
  358.             case    0x00:    /* Basically all done */
  359.             if ( ! in2000_SCptr )
  360.                 return;
  361.             in2000_SCptr->result = result | scsibyte;
  362.             SCptr = in2000_SCptr;
  363.             in2000_SCptr = 0;
  364.             if ( in2000_done )
  365.                      (*in2000_done)(SCptr);
  366.             break;
  367.             case    0x01:    /* We need to reissue a command */
  368.             outb(CMDPHAS,INSTAT);
  369.             switch ( scsistatus & 7 )
  370.                 {
  371.                 case    0:    /* Data out phase */
  372.                     case    1:    /* Data in phase */
  373.                     case    4:    /* Unspec info out phase */
  374.                     case    5:    /* Unspec info in phase */
  375.                     case    6:    /* Message in phase */
  376.                     case    7:    /* Message in phase */
  377.                 outb(0x41,INDATA); /* rdy to disconn */
  378.                 break;
  379.                     case    2:    /* command phase */
  380.                 outb(0x30,INDATA); /* rdy to send cmd bytes */
  381.                 break;
  382.                     case    3:    /* status phase */
  383.                 outb(0x45,INDATA); /* To go to status phase,*/
  384.                 outb(TXCNTH,INSTAT); /* elim. data, autoinc */
  385.                 outb(0,INDATA);
  386.                 outb(0,INDATA);
  387.                 outb(0,INDATA);
  388.                 in2000_datalen = 0;
  389.                 in2000_dataptr = 0;
  390.                 break;
  391.                 }    /* end switch(scsistatus) */
  392.             outb(COMMAND,INSTAT);
  393.             outb(8,INDATA);     /* RESTART THE COMMAND */
  394.             break;
  395.             case    0x03:    /* Finish up a Card Reset */
  396.             outb(TIMEOUT,INSTAT);    /* I got these values */
  397.                         /* by reverse Engineering */
  398.             outb(IN2000_TMOUT,INDATA); /* the Always' bios. */
  399.             outb(CONTROL,INSTAT);
  400.             outb(0,INDATA);
  401.             outb(SYNCTXR,INSTAT);
  402.             outb(0x40,INDATA);    /* async, 4 cyc xfer per. */
  403.             break;
  404.             }        /* end switch(action) */
  405.         }            /* end if auxstatus for WD int */
  406.     }            /* end while intrpt active */
  407. }
  408.  
  409. int in2000_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
  410. {
  411.     unchar direction;
  412.     unchar *cmd = (unchar *) SCpnt->cmnd;
  413.     unchar target = SCpnt->target;
  414.     void *buff = SCpnt->request_buffer;
  415.     unsigned long flags;
  416.     int bufflen = SCpnt->request_bufflen;
  417.     int timeout, size, loop;
  418.     int i;
  419.  
  420.     /*
  421.      * This SCSI command has no data phase, but unfortunately the mid-level
  422.      * SCSI drivers ask for 256 bytes of data xfer.  Our card hangs if you
  423.      * do this, so we protect against it here.  It would be nice if the mid-
  424.      * level could be changed, but who knows if that would break other host
  425.      * adapter drivers.
  426.      */
  427.     if ( *cmd == TEST_UNIT_READY )
  428.     bufflen = 0;
  429.  
  430.     /*
  431.      * What it looks like.  Boy did I get tired of reading its output.
  432.      */
  433.     if (*cmd == READ_10 || *cmd == WRITE_10) {
  434.     i = xscsi2int((cmd+1));
  435.     } else if (*cmd == READ_6 || *cmd == WRITE_6) {
  436.     i = scsi2int((cmd+1));
  437.     } else {
  438.     i = -1;
  439.     }
  440. #ifdef DEBUG
  441.     printk("in2000qcmd: pos %d len %d ", i, bufflen);
  442.     printk("scsi cmd:");
  443.     for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]);
  444.     printk("\n");
  445. #endif
  446.     direction = 1;    /* assume for most commands */
  447.     if (*cmd == WRITE_10 || *cmd == WRITE_6)
  448.     direction = 0;
  449.     size = SCpnt->cmd_len;    /* CDB length */ 
  450.     /*
  451.      * Setup our current pointers
  452.      * This is where you would allocate a control structure in a queue,
  453.      * If you were going to upgrade this to do multiple issue.
  454.      * Note that datalen and dataptr exist because we can change the
  455.      * values during the course of the operation, while managing the
  456.      * FIFO.
  457.      * Note the nasty little first clause.  In theory, the mid-level
  458.      * drivers should never hand us more than one command at a time,
  459.      * but just in case someone gets cute in configuring the driver,
  460.      * we'll protect them, although not very politely.
  461.      */
  462.     if ( in2000_SCptr )
  463.     {
  464.     printk("in2000_queue_command waiting for free command block!\n");
  465.     while ( in2000_SCptr );
  466.     }
  467.     for ( timeout = jiffies + 5; timeout > jiffies; )
  468.     {
  469.     if ( ! ( inb(INSTAT) & 0xb0 ) )
  470.     {
  471.         timeout = 0;
  472.         break;
  473.     }
  474.     else
  475.     {
  476.         inb(INSTAT);
  477.         outb(SCSIST,INSTAT);
  478.         inb(INDATA);
  479.         outb(TARGETU,INSTAT);     /* then autoinc */
  480.         inb(INDATA);
  481.         inb(INDATA);
  482.     }
  483.     }
  484.     if ( timeout )
  485.     {
  486.     printk("in2000_queue_command timeout!\n");
  487.     SCpnt->result = DID_TIME_OUT << 16;
  488.     (*done)(SCpnt);
  489.     return 1;
  490.     }
  491.     /* Added for scatter-gather support */
  492.     in2000_nsegment = SCpnt->use_sg;
  493.     in2000_current_segment = 0;
  494.     if(SCpnt->use_sg){
  495.       in2000_scatter = (struct scatterlist *) buff;
  496.       in2000_datalen = in2000_scatter->length;
  497.       in2000_dataptr = (unsigned short*)in2000_scatter->address;
  498.     } else {
  499.       in2000_scatter = NULL;
  500.       in2000_datalen = bufflen;
  501.       in2000_dataptr = (unsigned short*) buff;
  502.     };
  503.     in2000_done = done;
  504.     in2000_SCptr = SCpnt;
  505.     /*
  506.      * Write the CDB to the card, then the LUN, the length, and the target.
  507.      */
  508.     outb(TOTSECT, INSTAT);    /* start here then autoincrement */
  509.     for ( loop=0; loop < size; loop++ )
  510.     outb(cmd[loop],INDATA);
  511.     outb(TARGETU,INSTAT);
  512.     outb(SCpnt->lun & 7,INDATA);
  513.     SCpnt->host_scribble = NULL;
  514.     outb(TXCNTH,INSTAT);    /* then autoincrement */
  515.     outb(bufflen>>16,INDATA);
  516.     outb(bufflen>>8,INDATA);
  517.     outb(bufflen,INDATA);
  518.     outb(target&7,INDATA);
  519.     /*
  520.      * Set up the FIFO
  521.      */
  522.     save_flags(flags);
  523.     cli();        /* so FIFO init waits till WD set */
  524.     outb(0,INFRST);
  525.     if ( direction == 1 )
  526.     {
  527.     in2000_datawrite = 0;
  528.     outb(0,INFWRT);
  529.     }
  530.     else
  531.     {
  532.     in2000_datawrite = 1;
  533.     for ( loop=16; --loop; ) /* preload the outgoing fifo */
  534.         {
  535.         outw(*in2000_dataptr++,INFIFO);
  536.         if(in2000_datalen > 0) in2000_datalen-=2;
  537.         }
  538.     }
  539.     ficmsk = 0xff;
  540.     /*
  541.      * Start it up
  542.      */
  543.     outb(CONTROL,INSTAT);    /* WD BUS Mode */
  544.     outb(0x4C,INDATA);
  545.     if ( in2000_datalen )        /* if data xfer cmd */
  546.         outb(0,ININTR);        /* Enable FIFO intrpt some boards? */
  547.     outb(COMMAND,INSTAT);
  548.     outb(0,INNLED);
  549.     outb(8,INDATA);        /* Select w/ATN & Transfer */
  550.     restore_flags(flags);            /* let the intrpt rip */
  551.     return 0;
  552. }
  553.  
  554. static volatile int internal_done_flag = 0;
  555. static volatile int internal_done_errcode = 0;
  556.  
  557. static void internal_done(Scsi_Cmnd * SCpnt)
  558. {
  559.     internal_done_errcode = SCpnt->result;
  560.     ++internal_done_flag;
  561. }
  562.  
  563. int in2000_command(Scsi_Cmnd * SCpnt)
  564. {
  565.     in2000_queuecommand(SCpnt, internal_done);
  566.  
  567.     while (!internal_done_flag);
  568.     internal_done_flag = 0;
  569.     return internal_done_errcode;
  570. }
  571.  
  572. int in2000_detect(Scsi_Host_Template * tpnt)
  573. {
  574. /* Order chosen to reduce conflicts with some multi-port serial boards */
  575.     int base_tab[] = { 0x220,0x200,0x110,0x100 };
  576.     int int_tab[] = { 15,14,11,10 };
  577.     struct Scsi_Host * shpnt;
  578.     int loop, tmp;
  579.  
  580.     DEB(printk("in2000_detect: \n"));
  581.     
  582.     for ( loop=0; loop < 4; loop++ )
  583.     {
  584.     base = base_tab[loop];
  585.     if ( in2000_test_port(loop))  break;
  586.     }
  587.     if ( loop == 4 )
  588.     return 0;
  589.  
  590.   /* Read the dip switch values again for miscellaneous checking and
  591.      informative messages */
  592.   tmp = inb(INFLED);
  593.  
  594.   /* Bit 2 tells us if interrupts are disabled */
  595.   if ( (tmp & 0x4) == 0 ) {
  596.     printk("The IN-2000 is not configured for interrupt operation\n");
  597.     printk("Change the DIP switch settings to enable interrupt operation\n");
  598.   }
  599.  
  600.   /* Bit 6 tells us about floppy controller */
  601.   printk("IN-2000 probe found floppy controller on IN-2000 ");
  602.   if ( (tmp & 0x40) == 0)
  603.     printk("enabled\n");
  604.   else
  605.     printk("disabled\n");
  606.  
  607.   /* Bit 5 tells us about synch/asynch mode */
  608.   printk("IN-2000 probe found IN-2000 in ");
  609.   if ( (tmp & 0x20) == 0)
  610.     printk("synchronous mode\n");
  611.   else
  612.     printk("asynchronous mode\n");
  613.  
  614.     irq_level = int_tab [ ((~inb(INFLED)>>3)&0x3) ];
  615.  
  616.     printk("Configuring IN2000 at IO:%x, IRQ %d"
  617. #ifdef FAST_FIFO_IO
  618.         " (using fast FIFO I/O code)"
  619. #endif
  620.         "\n",base, irq_level);
  621.  
  622.     outb(2,ININTR);    /* Shut off the FIFO first, so it won't ask for data.*/
  623.     if (request_irq(irq_level,in2000_intr_handle, 0, "in2000"))
  624.     {
  625.     printk("in2000_detect: Unable to allocate IRQ.\n");
  626.     return 0;
  627.     }
  628.     outb(0,INFWRT);    /* read mode so WD can intrpt */
  629.     outb(SCSIST,INSTAT);
  630.     inb(INDATA);    /* free status reg, clear WD intrpt */
  631.     outb(OWNID,INSTAT);
  632.     outb(0x7,INDATA);    /* we use addr 7 */
  633.     outb(COMMAND,INSTAT);
  634.     outb(0,INDATA);    /* do chip reset */
  635.     shpnt = scsi_register(tpnt, 0);
  636.     /* Set these up so that we can unload the driver properly. */
  637.     shpnt->io_port = base;
  638.     shpnt->n_io_port = 12;
  639.     shpnt->irq = irq_level;
  640.     request_region(base, 12,"in2000");  /* Prevent other drivers from using this space */
  641.     return 1;
  642. }
  643.  
  644. int in2000_abort(Scsi_Cmnd * SCpnt)
  645. {
  646.     DEB(printk("in2000_abort\n"));
  647.     /*
  648.      * Ask no stupid questions, just order the abort.
  649.      */
  650.     outb(COMMAND,INSTAT);
  651.     outb(1,INDATA);    /* Abort Command */
  652.     return 0;
  653. }
  654.  
  655. static inline void delay( unsigned how_long )
  656. {
  657.     unsigned long time = jiffies + how_long;
  658.     while (jiffies < time) ;
  659. }
  660.  
  661. int in2000_reset(Scsi_Cmnd * SCpnt)
  662. {
  663.     DEB(printk("in2000_reset called\n"));
  664.     /*
  665.      * Note: this is finished off by an incoming interrupt
  666.      */
  667.     outb(0,INFWRT);    /* read mode so WD can intrpt */
  668.     outb(SCSIST,INSTAT);
  669.     inb(INDATA);
  670.     outb(OWNID,INSTAT);
  671.     outb(0x7,INDATA);    /* ID=7,noadv, no parity, clk div=2 (8-10Mhz clk) */
  672.     outb(COMMAND,INSTAT);
  673.     outb(0,INDATA);    /* reset WD chip */
  674.     delay(2);
  675. #ifdef SCSI_RESET_PENDING
  676.     return SCSI_RESET_PENDING;
  677. #else
  678.     if(SCpnt) SCpnt->flags |= NEEDS_JUMPSTART;
  679.     return 0;
  680. #endif
  681. }
  682.  
  683. int in2000_biosparam(Disk * disk, int dev, int* iinfo)
  684.     {
  685.       int size = disk->capacity;
  686.     DEB(printk("in2000_biosparam\n"));
  687.     iinfo[0] = 64;
  688.     iinfo[1] = 32;
  689.     iinfo[2] = size >> 11;
  690. /* This should approximate the large drive handling that the DOS ASPI manager
  691.    uses.  Drives very near the boundaries may not be handled correctly (i.e.
  692.    near 2.0 Gb and 4.0 Gb) */
  693.     if (iinfo[2] > 1024) {
  694.     iinfo[0] = 64;
  695.     iinfo[1] = 63;
  696.     iinfo[2] = disk->capacity / (iinfo[0] * iinfo[1]);
  697.     }
  698.     if (iinfo[2] > 1024) {
  699.     iinfo[0] = 128;
  700.     iinfo[1] = 63;
  701.     iinfo[2] = disk->capacity / (iinfo[0] * iinfo[1]);
  702.     }
  703.     if (iinfo[2] > 1024) {
  704.     iinfo[0] = 255;
  705.     iinfo[1] = 63;
  706.     iinfo[2] = disk->capacity / (iinfo[0] * iinfo[1]);
  707.     if (iinfo[2] > 1023)
  708.         iinfo[2] = 1023;
  709.     }
  710.     return 0;
  711.     }
  712.  
  713. #ifdef MODULE
  714. /* Eventually this will go into an include file, but this will be later */
  715. Scsi_Host_Template driver_template = IN2000;
  716.  
  717. #include "scsi_module.c"
  718. #endif
  719.  
  720.