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

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