Annotation of Gnu-Mach/i386/i386at/gpl/linux/scsi/in2000.c, revision 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.