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 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 )
     /* [previous][next][first][last][top][bottom][index][help] */
  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 )
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 */
     /* [previous][next][first][last][top][bottom][index][help] */
 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 */
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 *))
     /* [previous][next][first][last][top][bottom][index][help] */
 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             barrier();
 467     }
 468     for ( timeout = jiffies + 5; timeout > jiffies; )
 469     {
 470         if ( ! ( inb(INSTAT) & 0xb0 ) )
 471         {
 472             timeout = 0;
 473             break;
 474         }
 475         else
 476         {
 477             inb(INSTAT);
 478             outb(SCSIST,INSTAT);
 479             inb(INDATA);
 480             outb(TARGETU,INSTAT);       /* then autoinc */
 481             inb(INDATA);
 482             inb(INDATA);
 483         }
 484     }
 485     if ( timeout )
 486     {
 487         printk("in2000_queue_command timeout!\n");
 488         SCpnt->result = DID_TIME_OUT << 16;
 489         (*done)(SCpnt);
 490         return 1;
 491     }
 492     /* Added for scatter-gather support */
 493     in2000_nsegment = SCpnt->use_sg;
 494     in2000_current_segment = 0;
 495     if(SCpnt->use_sg){
 496       in2000_scatter = (struct scatterlist *) buff;
 497       in2000_datalen = in2000_scatter->length;
 498       in2000_dataptr = (unsigned short*)in2000_scatter->address;
 499     } else {
 500       in2000_scatter = NULL;
 501       in2000_datalen = bufflen;
 502       in2000_dataptr = (unsigned short*) buff;
 503     };
 504     in2000_done = done;
 505     in2000_SCptr = SCpnt;
 506     /*
 507      * Write the CDB to the card, then the LUN, the length, and the target.
 508      */
 509     outb(TOTSECT, INSTAT);      /* start here then autoincrement */
 510     for ( loop=0; loop < size; loop++ )
 511         outb(cmd[loop],INDATA);
 512     outb(TARGETU,INSTAT);
 513     outb(SCpnt->lun & 7,INDATA);
 514     SCpnt->host_scribble = NULL;
 515     outb(TXCNTH,INSTAT);        /* then autoincrement */
 516     outb(bufflen>>16,INDATA);
 517     outb(bufflen>>8,INDATA);
 518     outb(bufflen,INDATA);
 519     outb(target&7,INDATA);
 520     /*
 521      * Set up the FIFO
 522      */
 523     save_flags(flags);
 524     cli();              /* so FIFO init waits till WD set */
 525     outb(0,INFRST);
 526     if ( direction == 1 )
 527     {
 528         in2000_datawrite = 0;
 529         outb(0,INFWRT);
 530     }
 531     else
 532     {
 533         in2000_datawrite = 1;
 534         for ( loop=16; --loop; ) /* preload the outgoing fifo */
 535             {
 536                 outw(*in2000_dataptr++,INFIFO);
 537                 if(in2000_datalen > 0) in2000_datalen-=2;
 538             }
 539     }
 540     ficmsk = 0xff;
 541     /*
 542      * Start it up
 543      */
 544     outb(CONTROL,INSTAT);       /* WD BUS Mode */
 545     outb(0x4C,INDATA);
 546     if ( in2000_datalen )               /* if data xfer cmd */
 547         outb(0,ININTR);         /* Enable FIFO intrpt some boards? */
 548     outb(COMMAND,INSTAT);
 549     outb(0,INNLED);
 550     outb(8,INDATA);             /* Select w/ATN & Transfer */
 551     restore_flags(flags);                       /* let the intrpt rip */
 552     return 0;
 553 }
 554 
 555 static volatile int internal_done_flag = 0;
 556 static volatile int internal_done_errcode = 0;
 557 
 558 static void internal_done(Scsi_Cmnd * SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 559 {
 560     internal_done_errcode = SCpnt->result;
 561     ++internal_done_flag;
 562 }
 563 
 564 int in2000_command(Scsi_Cmnd * SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 565 {
 566     in2000_queuecommand(SCpnt, internal_done);
 567 
 568     while (!internal_done_flag);
 569     internal_done_flag = 0;
 570     return internal_done_errcode;
 571 }
 572 
 573 int in2000_detect(Scsi_Host_Template * tpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 574 {
 575 /* Order chosen to reduce conflicts with some multi-port serial boards */
 576     int base_tab[] = { 0x220,0x200,0x110,0x100 };
 577     int int_tab[] = { 15,14,11,10 };
 578     struct Scsi_Host * shpnt;
 579     int loop, tmp;
 580 
 581     DEB(printk("in2000_detect: \n"));
 582     
 583     for ( loop=0; loop < 4; loop++ )
 584     {
 585         base = base_tab[loop];
 586         if ( in2000_test_port(loop))  break;
 587     }
 588     if ( loop == 4 )
 589         return 0;
 590 
 591   /* Read the dip switch values again for miscellaneous checking and
 592      informative messages */
 593   tmp = inb(INFLED);
 594 
 595   /* Bit 2 tells us if interrupts are disabled */
 596   if ( (tmp & 0x4) == 0 ) {
 597     printk("The IN-2000 is not configured for interrupt operation\n");
 598     printk("Change the DIP switch settings to enable interrupt operation\n");
 599   }
 600 
 601   /* Bit 6 tells us about floppy controller */
 602   printk("IN-2000 probe found floppy controller on IN-2000 ");
 603   if ( (tmp & 0x40) == 0)
 604     printk("enabled\n");
 605   else
 606     printk("disabled\n");
 607 
 608   /* Bit 5 tells us about synch/asynch mode */
 609   printk("IN-2000 probe found IN-2000 in ");
 610   if ( (tmp & 0x20) == 0)
 611     printk("synchronous mode\n");
 612   else
 613     printk("asynchronous mode\n");
 614 
 615     irq_level = int_tab [ ((~inb(INFLED)>>3)&0x3) ];
 616 
 617     printk("Configuring IN2000 at IO:%x, IRQ %d"
 618 #ifdef FAST_FIFO_IO
 619                 " (using fast FIFO I/O code)"
 620 #endif
 621                 "\n",base, irq_level);
 622 
 623     outb(2,ININTR);     /* Shut off the FIFO first, so it won't ask for data.*/
 624     if (request_irq(irq_level,in2000_intr_handle, 0, "in2000"))
 625     {
 626         printk("in2000_detect: Unable to allocate IRQ.\n");
 627         return 0;
 628     }
 629     outb(0,INFWRT);     /* read mode so WD can intrpt */
 630     outb(SCSIST,INSTAT);
 631     inb(INDATA);        /* free status reg, clear WD intrpt */
 632     outb(OWNID,INSTAT);
 633     outb(0x7,INDATA);   /* we use addr 7 */
 634     outb(COMMAND,INSTAT);
 635     outb(0,INDATA);     /* do chip reset */
 636     shpnt = scsi_register(tpnt, 0);
 637     /* Set these up so that we can unload the driver properly. */
 638     shpnt->io_port = base;
 639     shpnt->n_io_port = 12;
 640     shpnt->irq = irq_level;
 641     request_region(base, 12,"in2000");  /* Prevent other drivers from using this space */
 642     return 1;
 643 }
 644 
 645 int in2000_abort(Scsi_Cmnd * SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 646 {
 647     DEB(printk("in2000_abort\n"));
 648     /*
 649      * Ask no stupid questions, just order the abort.
 650      */
 651     outb(COMMAND,INSTAT);
 652     outb(1,INDATA);     /* Abort Command */
 653     return 0;
 654 }
 655 
 656 static inline void delay( unsigned how_long )
     /* [previous][next][first][last][top][bottom][index][help] */
 657 {
 658     unsigned long time = jiffies + how_long;
 659     while (jiffies < time) ;
 660 }
 661 
 662 int in2000_reset(Scsi_Cmnd * SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 663 {
 664     DEB(printk("in2000_reset called\n"));
 665     /*
 666      * Note: this is finished off by an incoming interrupt
 667      */
 668     outb(0,INFWRT);     /* read mode so WD can intrpt */
 669     outb(SCSIST,INSTAT);
 670     inb(INDATA);
 671     outb(OWNID,INSTAT);
 672     outb(0x7,INDATA);   /* ID=7,noadv, no parity, clk div=2 (8-10Mhz clk) */
 673     outb(COMMAND,INSTAT);
 674     outb(0,INDATA);     /* reset WD chip */
 675     delay(2);
 676 #ifdef SCSI_RESET_PENDING
 677     return SCSI_RESET_PENDING;
 678 #else
 679     if(SCpnt) SCpnt->flags |= NEEDS_JUMPSTART;
 680     return 0;
 681 #endif
 682 }
 683 
 684 int in2000_biosparam(Disk * disk, int dev, int* iinfo)
     /* [previous][next][first][last][top][bottom][index][help] */
 685         {
 686           int size = disk->capacity;
 687     DEB(printk("in2000_biosparam\n"));
 688     iinfo[0] = 64;
 689     iinfo[1] = 32;
 690     iinfo[2] = size >> 11;
 691 /* This should approximate the large drive handling that the DOS ASPI manager
 692    uses.  Drives very near the boundaries may not be handled correctly (i.e.
 693    near 2.0 Gb and 4.0 Gb) */
 694     if (iinfo[2] > 1024) {
 695         iinfo[0] = 64;
 696         iinfo[1] = 63;
 697         iinfo[2] = disk->capacity / (iinfo[0] * iinfo[1]);
 698         }
 699     if (iinfo[2] > 1024) {
 700         iinfo[0] = 128;
 701         iinfo[1] = 63;
 702         iinfo[2] = disk->capacity / (iinfo[0] * iinfo[1]);
 703         }
 704     if (iinfo[2] > 1024) {
 705         iinfo[0] = 255;
 706         iinfo[1] = 63;
 707         iinfo[2] = disk->capacity / (iinfo[0] * iinfo[1]);
 708         if (iinfo[2] > 1023)
 709             iinfo[2] = 1023;
 710         }
 711     return 0;
 712     }
 713 
 714 #ifdef MODULE
 715 /* Eventually this will go into an include file, but this will be later */
 716 Scsi_Host_Template driver_template = IN2000;
 717 
 718 #include "scsi_module.c"
 719 #endif
 720 

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