root/drivers/scsi/in2000.c

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

DEFINITIONS

This source file includes following definitions.
  1. inw
  2. outw
  3. in2000_test_port
  4. in2000_txcnt
  5. in2000_fifo_out
  6. in2000_fifo_in
  7. in2000_intr_handle
  8. in2000_queuecommand
  9. internal_done
  10. in2000_command
  11. in2000_detect
  12. in2000_abort
  13. delay
  14. in2000_reset
  15. in2000_biosparam

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

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