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

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