Annotation of Gnu-Mach/i386/i386at/gpl/linux/scsi/in2000.c, revision 1.1.1.1

1.1       root        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, [email protected]
                     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 [email protected]. (WDE)
                     49:  *
                     50:  * 1/7/95 Fix from Peter Lu ([email protected]) for datalen vs. dataptr
                     51:  * logic, much more stable under load.
                     52:  *
                     53:  * 1/19/95 ([email protected]) 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 )
                     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 )
                    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)
                    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)
                    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 */
                    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 */
                    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)
                    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 *))
                    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)
                    568: {
                    569:     internal_done_errcode = SCpnt->result;
                    570:     ++internal_done_flag;
                    571: }
                    572: 
                    573: int in2000_command(Scsi_Cmnd * SCpnt)
                    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)
                    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)
                    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 )
                    668: {
                    669:     unsigned long time = jiffies + how_long;
                    670:     while (jiffies < time) ;
                    671: }
                    672: 
                    673: int in2000_reset(Scsi_Cmnd * SCpnt)
                    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)
                    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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.