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 it's 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 558 {
 559     internal_done_errcode = SCpnt->result;
 560     ++internal_done_flag;
 561 }
 562 
 563 int in2000_command(Scsi_Cmnd * SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 )
     /* [previous][next][first][last][top][bottom][index][help] */
 656 {
 657     unsigned long time = jiffies + how_long;
 658     while (jiffies < time) ;
 659 }
 660 
 661 int in2000_reset(Scsi_Cmnd * SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 

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