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

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