Annotation of Gnu-Mach/linux/src/drivers/scsi/qlogicfas.c, revision 1.1

1.1     ! root        1: /*----------------------------------------------------------------*/
        !             2: /*
        !             3:    Qlogic linux driver - work in progress. No Warranty express or implied.
        !             4:    Use at your own risk.  Support Tort Reform so you won't have to read all
        !             5:    these silly disclaimers.
        !             6: 
        !             7:    Copyright 1994, Tom Zerucha.   
        !             8:    [email protected]
        !             9: 
        !            10:    Additional Code, and much appreciated help by
        !            11:    Michael A. Griffith
        !            12:    [email protected]
        !            13: 
        !            14:    Thanks to Eric Youngdale and Dave Hinds for loadable module and PCMCIA
        !            15:    help respectively, and for suffering through my foolishness during the
        !            16:    debugging process.
        !            17: 
        !            18:    Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994
        !            19:    (you can reference it, but it is incomplete and inaccurate in places)
        !            20: 
        !            21:    Version 0.45 6/9/96 - kernel 1.2.0+
        !            22: 
        !            23:    Functions as standalone, loadable, and PCMCIA driver, the latter from
        !            24:    Dave Hind's PCMCIA package.
        !            25: 
        !            26:    Redistributable under terms of the GNU Public License
        !            27: 
        !            28: */
        !            29: /*----------------------------------------------------------------*/
        !            30: /* Configuration */
        !            31: 
        !            32: /* Set the following to 2 to use normal interrupt (active high/totempole-
        !            33:    tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open
        !            34:    drain */
        !            35: #define QL_INT_ACTIVE_HIGH 2
        !            36: 
        !            37: /* Set the following to 1 to enable the use of interrupts.  Note that 0 tends
        !            38:    to be more stable, but slower (or ties up the system more) */
        !            39: #define QL_USE_IRQ 1
        !            40: 
        !            41: /* Set the following to max out the speed of the PIO PseudoDMA transfers,
        !            42:    again, 0 tends to be slower, but more stable.  */
        !            43: #define QL_TURBO_PDMA 1
        !            44: 
        !            45: /* This should be 1 to enable parity detection */
        !            46: #define QL_ENABLE_PARITY 1
        !            47: 
        !            48: /* This will reset all devices when the driver is initialized (during bootup).
        !            49:    The other linux drivers don't do this, but the DOS drivers do, and after
        !            50:    using DOS or some kind of crash or lockup this will bring things back
        !            51:    without requiring a cold boot.  It does take some time to recover from a
        !            52:    reset, so it is slower, and I have seen timeouts so that devices weren't
        !            53:    recognized when this was set. */
        !            54: #define QL_RESET_AT_START 0
        !            55: 
        !            56: /* crystal frequency in megahertz (for offset 5 and 9)
        !            57:    Please set this for your card.  Most Qlogic cards are 40 Mhz.  The
        !            58:    Control Concepts ISA (not VLB) is 24 Mhz */
        !            59: #define XTALFREQ       40
        !            60: 
        !            61: /**********/
        !            62: /* DANGER! modify these at your own risk */
        !            63: /* SLOWCABLE can usually be reset to zero if you have a clean setup and
        !            64:    proper termination.  The rest are for synchronous transfers and other
        !            65:    advanced features if your device can transfer faster than 5Mb/sec.
        !            66:    If you are really curious, email me for a quick howto until I have
        !            67:    something official */
        !            68: /**********/
        !            69: 
        !            70: /*****/
        !            71: /* config register 1 (offset 8) options */
        !            72: /* This needs to be set to 1 if your cabling is long or noisy */
        !            73: #define SLOWCABLE 1
        !            74: 
        !            75: /*****/
        !            76: /* offset 0xc */
        !            77: /* This will set fast (10Mhz) synchronous timing when set to 1
        !            78:    For this to have an effect, FASTCLK must also be 1 */
        !            79: #define FASTSCSI 0
        !            80: 
        !            81: /* This when set to 1 will set a faster sync transfer rate */
        !            82: #define FASTCLK 0
        !            83: /*(XTALFREQ>25?1:0)*/
        !            84: 
        !            85: /*****/
        !            86: /* offset 6 */
        !            87: /* This is the sync transfer divisor, XTALFREQ/X will be the maximum
        !            88:    achievable data rate (assuming the rest of the system is capable
        !            89:    and set properly) */
        !            90: #define SYNCXFRPD 5
        !            91: /*(XTALFREQ/5)*/
        !            92: 
        !            93: /*****/
        !            94: /* offset 7 */
        !            95: /* This is the count of how many synchronous transfers can take place
        !            96:        i.e. how many reqs can occur before an ack is given.
        !            97:        The maximum value for this is 15, the upper bits can modify
        !            98:        REQ/ACK assertion and deassertion during synchronous transfers
        !            99:        If this is 0, the bus will only transfer asynchronously */
        !           100: #define SYNCOFFST 0
        !           101: /* for the curious, bits 7&6 control the deassertion delay in 1/2 cycles
        !           102:        of the 40Mhz clock. If FASTCLK is 1, specifying 01 (1/2) will
        !           103:        cause the deassertion to be early by 1/2 clock.  Bits 5&4 control
        !           104:        the assertion delay, also in 1/2 clocks (FASTCLK is ignored here). */
        !           105: 
        !           106: /*----------------------------------------------------------------*/
        !           107: #ifdef PCMCIA
        !           108: #undef QL_INT_ACTIVE_HIGH
        !           109: #define QL_INT_ACTIVE_HIGH 0
        !           110: #define MODULE
        !           111: #endif 
        !           112: 
        !           113: #include <linux/module.h>
        !           114: 
        !           115: #ifdef PCMCIA
        !           116: #undef MODULE
        !           117: #endif 
        !           118: 
        !           119: #include <linux/blk.h> /* to get disk capacity */
        !           120: #include <linux/kernel.h>
        !           121: #include <linux/string.h>
        !           122: #include <linux/ioport.h>
        !           123: #include <linux/sched.h>
        !           124: #include <linux/proc_fs.h>
        !           125: #include <linux/unistd.h>
        !           126: #include <asm/io.h>
        !           127: #include <asm/irq.h>
        !           128: #include "sd.h"
        !           129: #include "hosts.h"
        !           130: #include "qlogicfas.h"
        !           131: #include<linux/stat.h>
        !           132: 
        !           133: struct proc_dir_entry proc_scsi_qlogicfas = {
        !           134:     PROC_SCSI_QLOGICFAS, 6, "qlogicfas",
        !           135:     S_IFDIR | S_IRUGO | S_IXUGO, 2
        !           136: };
        !           137: 
        !           138: /*----------------------------------------------------------------*/
        !           139: /* driver state info, local to driver */
        !           140: static int         qbase = 0;  /* Port */
        !           141: static int         qinitid;    /* initiator ID */
        !           142: static int         qabort;     /* Flag to cause an abort */
        !           143: static int         qlirq = -1; /* IRQ being used */
        !           144: static char        qinfo[80];  /* description */
        !           145: static Scsi_Cmnd   *qlcmd;     /* current command being processed */
        !           146: 
        !           147: static int         qlcfg5 = ( XTALFREQ << 5 ); /* 15625/512 */
        !           148: static int         qlcfg6 = SYNCXFRPD;
        !           149: static int         qlcfg7 = SYNCOFFST;
        !           150: static int         qlcfg8 = ( SLOWCABLE << 7 ) | ( QL_ENABLE_PARITY << 4 );
        !           151: static int         qlcfg9 = ( ( XTALFREQ + 4 ) / 5 );
        !           152: static int         qlcfgc = ( FASTCLK << 3 ) | ( FASTSCSI << 4 );
        !           153: 
        !           154: /*----------------------------------------------------------------*/
        !           155: /* The qlogic card uses two register maps - These macros select which one */
        !           156: #define REG0 ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd ), outb( 4 , qbase + 0xd ))
        !           157: #define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd ))
        !           158: 
        !           159: /* following is watchdog timeout in microseconds */
        !           160: #define WATCHDOG 5000000
        !           161: 
        !           162: /*----------------------------------------------------------------*/
        !           163: /* the following will set the monitor border color (useful to find
        !           164:    where something crashed or gets stuck at and as a simple profiler) */
        !           165: 
        !           166: #if 0
        !           167: #define rtrc(i) {inb(0x3da);outb(0x31,0x3c0);outb((i),0x3c0);}
        !           168: #else
        !           169: #define rtrc(i) {}
        !           170: #endif
        !           171: 
        !           172: /*----------------------------------------------------------------*/
        !           173: /* local functions */
        !           174: /*----------------------------------------------------------------*/
        !           175: static void    ql_zap(void);
        !           176: /* error recovery - reset everything */
        !           177: void   ql_zap()
        !           178: {
        !           179: int    x;
        !           180: unsigned long  flags;
        !           181:        save_flags( flags );
        !           182:        cli();
        !           183:        x = inb(qbase + 0xd);
        !           184:        REG0;
        !           185:        outb(3, qbase + 3);                             /* reset SCSI */
        !           186:        outb(2, qbase + 3);                             /* reset chip */
        !           187:        if (x & 0x80)
        !           188:                REG1;
        !           189:        restore_flags( flags );
        !           190: }
        !           191: 
        !           192: /*----------------------------------------------------------------*/
        !           193: /* do pseudo-dma */
        !           194: static int     ql_pdma(int phase, char *request, int reqlen)
        !           195: {
        !           196: int    j;
        !           197:        j = 0;
        !           198:        if (phase & 1) {        /* in */
        !           199: #if QL_TURBO_PDMA
        !           200: rtrc(4)
        !           201:                /* empty fifo in large chunks */
        !           202:                if( reqlen >= 128 && (inb( qbase + 8 ) & 2) ) { /* full */
        !           203:                        insl( qbase + 4, request, 32 );
        !           204:                        reqlen -= 128;
        !           205:                        request += 128;
        !           206:                }
        !           207:                while( reqlen >= 84 && !( j & 0xc0 ) ) /* 2/3 */
        !           208:                        if( (j=inb( qbase + 8 )) & 4 ) {
        !           209:                                insl( qbase + 4, request, 21 );
        !           210:                                reqlen -= 84;
        !           211:                                request += 84;
        !           212:                        }
        !           213:                if( reqlen >= 44 && (inb( qbase + 8 ) & 8) ) {  /* 1/3 */
        !           214:                        insl( qbase + 4, request, 11 );
        !           215:                        reqlen -= 44;
        !           216:                        request += 44;
        !           217:                }
        !           218: #endif
        !           219:                /* until both empty and int (or until reclen is 0) */
        !           220: rtrc(7)
        !           221:                j = 0;
        !           222:                while( reqlen && !( (j & 0x10) && (j & 0xc0) ) ) {
        !           223:                        /* while bytes to receive and not empty */
        !           224:                        j &= 0xc0;
        !           225:                        while ( reqlen && !( (j=inb(qbase + 8)) & 0x10 ) ) {
        !           226:                                *request++ = inb(qbase + 4);
        !           227:                                reqlen--;
        !           228:                        }
        !           229:                        if( j & 0x10 )
        !           230:                                j = inb(qbase+8);
        !           231: 
        !           232:                }
        !           233:        }
        !           234:        else {  /* out */
        !           235: #if QL_TURBO_PDMA
        !           236: rtrc(4)
        !           237:                if( reqlen >= 128 && inb( qbase + 8 ) & 0x10 ) { /* empty */
        !           238:                        outsl(qbase + 4, request, 32 );
        !           239:                        reqlen -= 128;
        !           240:                        request += 128;
        !           241:                }
        !           242:                while( reqlen >= 84 && !( j & 0xc0 ) ) /* 1/3 */
        !           243:                        if( !((j=inb( qbase + 8 )) & 8) ) {
        !           244:                                outsl( qbase + 4, request, 21 );
        !           245:                                reqlen -= 84;
        !           246:                                request += 84;
        !           247:                        }
        !           248:                if( reqlen >= 40 && !(inb( qbase + 8 ) & 4 ) ) { /* 2/3 */
        !           249:                        outsl( qbase + 4, request, 10 );
        !           250:                        reqlen -= 40;
        !           251:                        request += 40;
        !           252:                }
        !           253: #endif
        !           254:                /* until full and int (or until reclen is 0) */
        !           255: rtrc(7)
        !           256:                j = 0;
        !           257:                while( reqlen && !( (j & 2) && (j & 0xc0) ) ) {
        !           258:                        /* while bytes to send and not full */
        !           259:                        while ( reqlen && !( (j=inb(qbase + 8)) & 2 ) ) {
        !           260:                                outb(*request++, qbase + 4);
        !           261:                                reqlen--;
        !           262:                        }
        !           263:                        if( j & 2 )
        !           264:                                j = inb(qbase+8);
        !           265:                }
        !           266:        }
        !           267: /* maybe return reqlen */
        !           268:        return inb( qbase + 8 ) & 0xc0;
        !           269: }
        !           270: 
        !           271: /*----------------------------------------------------------------*/
        !           272: /* wait for interrupt flag (polled - not real hardware interrupt) */
        !           273: static int     ql_wai(void)
        !           274: {
        !           275: int    i,k;
        !           276:        k = 0;
        !           277:        i = jiffies + WATCHDOG;
        !           278:        while ( i > jiffies && !qabort && !((k = inb(qbase + 4)) & 0xe0))
        !           279:                barrier();
        !           280:        if (i <= jiffies)
        !           281:                return (DID_TIME_OUT);
        !           282:        if (qabort)
        !           283:                return (qabort == 1 ? DID_ABORT : DID_RESET);
        !           284:        if (k & 0x60)
        !           285:                ql_zap();
        !           286:        if (k & 0x20)
        !           287:                return (DID_PARITY);
        !           288:        if (k & 0x40)
        !           289:                return (DID_ERROR);
        !           290:        return 0;
        !           291: }
        !           292: 
        !           293: /*----------------------------------------------------------------*/
        !           294: /* initiate scsi command - queueing handler */
        !           295: static void    ql_icmd(Scsi_Cmnd * cmd)
        !           296: {
        !           297: unsigned int       i;
        !           298: unsigned long  flags;
        !           299: 
        !           300:        qabort = 0;
        !           301: 
        !           302:        save_flags( flags );
        !           303:        cli();
        !           304:        REG0;
        !           305: /* clearing of interrupts and the fifo is needed */
        !           306:        inb(qbase + 5);                         /* clear interrupts */
        !           307:        if (inb(qbase + 5))                     /* if still interrupting */
        !           308:                outb(2, qbase + 3);             /* reset chip */
        !           309:        else if (inb(qbase + 7) & 0x1f)
        !           310:                outb(1, qbase + 3);             /* clear fifo */
        !           311:        while (inb(qbase + 5));                 /* clear ints */
        !           312:        REG1;
        !           313:        outb(1, qbase + 8);                     /* set for PIO pseudo DMA */
        !           314:        outb(0, qbase + 0xb);                   /* disable ints */
        !           315:        inb(qbase + 8);                         /* clear int bits */
        !           316:        REG0;
        !           317:        outb(0x40, qbase + 0xb);                /* enable features */
        !           318: 
        !           319: /* configurables */
        !           320:        outb( qlcfgc , qbase + 0xc);
        !           321: /* config: no reset interrupt, (initiator) bus id */
        !           322:        outb( 0x40 | qlcfg8 | qinitid, qbase + 8);
        !           323:        outb( qlcfg7 , qbase + 7 );
        !           324:        outb( qlcfg6 , qbase + 6 );
        !           325: /**/
        !           326:        outb(qlcfg5, qbase + 5);                /* select timer */
        !           327:        outb(qlcfg9 & 7, qbase + 9);                    /* prescaler */
        !           328: /*     outb(0x99, qbase + 5);  */
        !           329:        outb(cmd->target, qbase + 4);
        !           330: 
        !           331:        for (i = 0; i < cmd->cmd_len; i++)
        !           332:                outb(cmd->cmnd[i], qbase + 2);
        !           333:        qlcmd = cmd;
        !           334:        outb(0x41, qbase + 3);  /* select and send command */
        !           335:        restore_flags( flags );
        !           336: }
        !           337: /*----------------------------------------------------------------*/
        !           338: /* process scsi command - usually after interrupt */
        !           339: static unsigned int    ql_pcmd(Scsi_Cmnd * cmd)
        !           340: {
        !           341: unsigned int   i, j, k;
        !           342: unsigned int   result;                 /* ultimate return result */
        !           343: unsigned int   status;                 /* scsi returned status */
        !           344: unsigned int   message;                /* scsi returned message */
        !           345: unsigned int   phase;                  /* recorded scsi phase */
        !           346: unsigned int   reqlen;                 /* total length of transfer */
        !           347: struct scatterlist     *sglist;        /* scatter-gather list pointer */
        !           348: unsigned int   sgcount;                /* sg counter */
        !           349: 
        !           350: rtrc(1)
        !           351:        j = inb(qbase + 6);
        !           352:        i = inb(qbase + 5);
        !           353:        if (i == 0x20) {
        !           354:                return (DID_NO_CONNECT << 16);
        !           355:        }
        !           356:        i |= inb(qbase + 5);    /* the 0x10 bit can be set after the 0x08 */
        !           357:        if (i != 0x18) {
        !           358:                printk("Ql:Bad Interrupt status:%02x\n", i);
        !           359:                ql_zap();
        !           360:                return (DID_BAD_INTR << 16);
        !           361:        }
        !           362:        j &= 7; /* j = inb( qbase + 7 ) >> 5; */
        !           363: /* correct status is supposed to be step 4 */
        !           364: /* it sometimes returns step 3 but with 0 bytes left to send */
        !           365: /* We can try stuffing the FIFO with the max each time, but we will get a
        !           366:    sequence of 3 if any bytes are left (but we do flush the FIFO anyway */
        !           367:        if(j != 3 && j != 4) {
        !           368:                printk("Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n", j, i, inb( qbase+7 ) & 0x1f );
        !           369:                ql_zap();
        !           370:                return (DID_ERROR << 16);
        !           371:        }
        !           372:        result = DID_OK;
        !           373:        if (inb(qbase + 7) & 0x1f)      /* if some bytes in fifo */
        !           374:                outb(1, qbase + 3);             /* clear fifo */
        !           375: /* note that request_bufflen is the total xfer size when sg is used */
        !           376:        reqlen = cmd->request_bufflen;
        !           377: /* note that it won't work if transfers > 16M are requested */
        !           378:        if (reqlen && !((phase = inb(qbase + 4)) & 6)) {        /* data phase */
        !           379: rtrc(2)
        !           380:                outb(reqlen, qbase);                    /* low-mid xfer cnt */
        !           381:                outb(reqlen >> 8, qbase+1);                     /* low-mid xfer cnt */
        !           382:                outb(reqlen >> 16, qbase + 0xe);        /* high xfer cnt */
        !           383:                outb(0x90, qbase + 3);                  /* command do xfer */
        !           384: /* PIO pseudo DMA to buffer or sglist */
        !           385:                REG1;
        !           386:                if (!cmd->use_sg)
        !           387:                        ql_pdma(phase, cmd->request_buffer, cmd->request_bufflen);
        !           388:                else {
        !           389:                        sgcount = cmd->use_sg;
        !           390:                        sglist = cmd->request_buffer;
        !           391:                        while (sgcount--) {
        !           392:                                if (qabort) {
        !           393:                                        REG0;
        !           394:                                        return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
        !           395:                                }
        !           396:                                if (ql_pdma(phase, sglist->address, sglist->length))
        !           397:                                        break;
        !           398:                                sglist++;
        !           399:                        }
        !           400:                }
        !           401:                REG0;
        !           402: rtrc(2)
        !           403: /* wait for irq (split into second state of irq handler if this can take time) */
        !           404:                if ((k = ql_wai()))
        !           405:                        return (k << 16);
        !           406:                k = inb(qbase + 5);     /* should be 0x10, bus service */
        !           407:        }
        !           408: /*** Enter Status (and Message In) Phase ***/
        !           409:        k = jiffies + WATCHDOG;
        !           410:        while ( k > jiffies && !qabort && !(inb(qbase + 4) & 6));       /* wait for status phase */
        !           411:        if ( k <= jiffies ) {
        !           412:                ql_zap();
        !           413:                return (DID_TIME_OUT << 16);
        !           414:        }
        !           415:        while (inb(qbase + 5));                                 /* clear pending ints */
        !           416:        if (qabort)
        !           417:                return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
        !           418:        outb(0x11, qbase + 3);                                  /* get status and message */
        !           419:        if ((k = ql_wai()))
        !           420:                return (k << 16);
        !           421:        i = inb(qbase + 5);                                     /* get chip irq stat */
        !           422:        j = inb(qbase + 7) & 0x1f;                              /* and bytes rec'd */
        !           423:        status = inb(qbase + 2);
        !           424:        message = inb(qbase + 2);
        !           425: /* should get function complete int if Status and message, else bus serv if only status */
        !           426:        if (!((i == 8 && j == 2) || (i == 0x10 && j == 1))) {
        !           427:                printk("Ql:Error during status phase, int=%02X, %d bytes recd\n", i, j);
        !           428:                result = DID_ERROR;
        !           429:        }
        !           430:        outb(0x12, qbase + 3);  /* done, disconnect */
        !           431: rtrc(1)
        !           432:        if ((k = ql_wai()))
        !           433:                return (k << 16);
        !           434: /* should get bus service interrupt and disconnect interrupt */
        !           435:        i = inb(qbase + 5);     /* should be bus service */
        !           436:        while (!qabort && ((i & 0x20) != 0x20)) {
        !           437:                barrier();
        !           438:                i |= inb(qbase + 5);
        !           439:        }
        !           440: rtrc(0)
        !           441:        if (qabort)
        !           442:                return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
        !           443:        return (result << 16) | (message << 8) | (status & STATUS_MASK);
        !           444: }
        !           445: 
        !           446: #if QL_USE_IRQ
        !           447: /*----------------------------------------------------------------*/
        !           448: /* interrupt handler */
        !           449: static void           ql_ihandl(int irq, void *dev_id, struct pt_regs * regs)
        !           450: {
        !           451: Scsi_Cmnd         *icmd;
        !           452:        REG0;
        !           453:        if (!(inb(qbase + 4) & 0x80))   /* false alarm? */
        !           454:                return;
        !           455:        if (qlcmd == NULL) {            /* no command to process? */
        !           456:                int     i;
        !           457:                i = 16;
        !           458:                while (i-- && inb(qbase + 5)); /* maybe also ql_zap() */
        !           459:                return;
        !           460:        }
        !           461:        icmd = qlcmd;
        !           462:        icmd->result = ql_pcmd(icmd);
        !           463:        qlcmd = NULL;
        !           464: /* if result is CHECK CONDITION done calls qcommand to request sense */
        !           465:        (icmd->scsi_done) (icmd);
        !           466: }
        !           467: #endif
        !           468: 
        !           469: /*----------------------------------------------------------------*/
        !           470: /* global functions */
        !           471: /*----------------------------------------------------------------*/
        !           472: /* non queued command */
        !           473: #if QL_USE_IRQ
        !           474: static void    qlidone(Scsi_Cmnd * cmd) {};            /* null function */
        !           475: #endif
        !           476: 
        !           477: /* command process */
        !           478: int    qlogicfas_command(Scsi_Cmnd * cmd)
        !           479: {
        !           480: int    k;
        !           481: #if QL_USE_IRQ
        !           482:        if (qlirq >= 0) {
        !           483:                qlogicfas_queuecommand(cmd, qlidone);
        !           484:                while (qlcmd != NULL);
        !           485:                return cmd->result;
        !           486:        }
        !           487: #endif
        !           488: /* non-irq version */
        !           489:        if (cmd->target == qinitid)
        !           490:                return (DID_BAD_TARGET << 16);
        !           491:        ql_icmd(cmd);
        !           492:        if ((k = ql_wai()))
        !           493:                return (k << 16);
        !           494:        return ql_pcmd(cmd);
        !           495: 
        !           496: }
        !           497: 
        !           498: #if QL_USE_IRQ
        !           499: /*----------------------------------------------------------------*/
        !           500: /* queued command */
        !           501: int    qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
        !           502: {
        !           503:        if(cmd->target == qinitid) {
        !           504:                cmd->result = DID_BAD_TARGET << 16;
        !           505:                done(cmd);
        !           506:                return 0;
        !           507:        }
        !           508: 
        !           509:        cmd->scsi_done = done;
        !           510: /* wait for the last command's interrupt to finish */
        !           511:        while (qlcmd != NULL)
        !           512:                barrier();
        !           513:        ql_icmd(cmd);
        !           514:        return 0;
        !           515: }
        !           516: #else
        !           517: int    qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
        !           518: {
        !           519:        return 1;
        !           520: }
        !           521: #endif
        !           522: 
        !           523: #ifdef PCMCIA
        !           524: /*----------------------------------------------------------------*/
        !           525: /* allow PCMCIA code to preset the port */
        !           526: /* port should be 0 and irq to -1 respectively for autoprobing */
        !           527: void   qlogicfas_preset(int port, int irq)
        !           528: {
        !           529:        qbase=port;
        !           530:        qlirq=irq;
        !           531: }
        !           532: #endif
        !           533: 
        !           534: /*----------------------------------------------------------------*/
        !           535: /* look for qlogic card and init if found */
        !           536: int    qlogicfas_detect(Scsi_Host_Template * host)
        !           537: {
        !           538: int    i, j;                   /* these are only used by IRQ detect */
        !           539: int    qltyp;                  /* type of chip */
        !           540: struct Scsi_Host       *hreg;  /* registered host structure */
        !           541: unsigned long  flags;
        !           542: 
        !           543: host->proc_dir =  &proc_scsi_qlogicfas;
        !           544: 
        !           545: /* Qlogic Cards only exist at 0x230 or 0x330 (the chip itself decodes the
        !           546:    address - I check 230 first since MIDI cards are typically at 330
        !           547: 
        !           548:    Theoretically, two Qlogic cards can coexist in the same system.  This
        !           549:    should work by simply using this as a loadable module for the second
        !           550:    card, but I haven't tested this.
        !           551: */
        !           552: 
        !           553:        if( !qbase ) {
        !           554:                for (qbase = 0x230; qbase < 0x430; qbase += 0x100) {
        !           555:                        if( check_region( qbase , 0x10 ) )
        !           556:                                continue;
        !           557:                        REG1;
        !           558:                        if ( ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 )
        !           559:                          && ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 ) )
        !           560:                                break;
        !           561:                }
        !           562:                if (qbase == 0x430)
        !           563:                        return 0;
        !           564:        }
        !           565:        else
        !           566:                printk( "Ql: Using preset base address of %03x\n", qbase );
        !           567: 
        !           568:        qltyp = inb(qbase + 0xe) & 0xf8;
        !           569:        qinitid = host->this_id;
        !           570:        if (qinitid < 0)
        !           571:                qinitid = 7;                    /* if no ID, use 7 */
        !           572:        outb(1, qbase + 8);                     /* set for PIO pseudo DMA */
        !           573:        REG0;
        !           574:        outb(0x40 | qlcfg8 | qinitid, qbase + 8);       /* (ini) bus id, disable scsi rst */
        !           575:        outb(qlcfg5, qbase + 5);                /* select timer */
        !           576:        outb(qlcfg9, qbase + 9);                        /* prescaler */
        !           577: #if QL_RESET_AT_START
        !           578:        outb( 3 , qbase + 3 );
        !           579:        REG1;
        !           580:        while( inb( qbase + 0xf ) & 4 );
        !           581:        REG0;
        !           582: #endif
        !           583: #if QL_USE_IRQ
        !           584: /* IRQ probe - toggle pin and check request pending */
        !           585: 
        !           586:        if( qlirq == -1 ) {
        !           587:                save_flags( flags );
        !           588:                cli();
        !           589:                i = 0xffff;
        !           590:                j = 3;
        !           591:                outb(0x90, qbase + 3);  /* illegal command - cause interrupt */
        !           592:                REG1;
        !           593:                outb(10, 0x20); /* access pending interrupt map */
        !           594:                outb(10, 0xa0);
        !           595:                while (j--) {
        !           596:                        outb(0xb0 | QL_INT_ACTIVE_HIGH , qbase + 0xd);  /* int pin off */
        !           597:                        i &= ~(inb(0x20) | (inb(0xa0) << 8));   /* find IRQ off */
        !           598:                        outb(0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd);  /* int pin on */
        !           599:                        i &= inb(0x20) | (inb(0xa0) << 8);      /* find IRQ on */
        !           600:                }
        !           601:                REG0;
        !           602:                while (inb(qbase + 5));                         /* purge int */
        !           603:                j = -1;
        !           604:                while (i)                                       /* find on bit */
        !           605:                        i >>= 1, j++;   /* should check for exactly 1 on */
        !           606:                qlirq = j;
        !           607:                restore_flags( flags );
        !           608:        }
        !           609:        else
        !           610:                printk( "Ql: Using preset IRQ %d\n", qlirq );
        !           611: 
        !           612:        if (qlirq >= 0 && !request_irq(qlirq, ql_ihandl, 0, "qlogicfas", NULL))
        !           613:                host->can_queue = 1;
        !           614: #endif
        !           615:        request_region( qbase , 0x10 ,"qlogicfas");
        !           616:        hreg = scsi_register( host , 0 );       /* no host data */
        !           617:        hreg->io_port = qbase;
        !           618:        hreg->n_io_port = 16;
        !           619:        hreg->dma_channel = -1;
        !           620:        if( qlirq != -1 )
        !           621:                hreg->irq = qlirq;
        !           622: 
        !           623:        sprintf(qinfo, "Qlogicfas Driver version 0.45, chip %02X at %03X, IRQ %d, TPdma:%d",
        !           624:            qltyp, qbase, qlirq, QL_TURBO_PDMA );
        !           625:        host->name = qinfo;
        !           626: 
        !           627:        return 1;
        !           628: }
        !           629: 
        !           630: /*----------------------------------------------------------------*/
        !           631: /* return bios parameters */
        !           632: int    qlogicfas_biosparam(Disk * disk, kdev_t dev, int ip[])
        !           633: {
        !           634: /* This should mimic the DOS Qlogic driver's behavior exactly */
        !           635:        ip[0] = 0x40;
        !           636:        ip[1] = 0x20;
        !           637:        ip[2] = disk->capacity / (ip[0] * ip[1]);
        !           638:        if (ip[2] > 1024) {
        !           639:                ip[0] = 0xff;
        !           640:                ip[1] = 0x3f;
        !           641:                ip[2] = disk->capacity / (ip[0] * ip[1]);
        !           642:                if (ip[2] > 1023)
        !           643:                        ip[2] = 1023;
        !           644:        }
        !           645:        return 0;
        !           646: }
        !           647: 
        !           648: /*----------------------------------------------------------------*/
        !           649: /* abort command in progress */
        !           650: int    qlogicfas_abort(Scsi_Cmnd * cmd)
        !           651: {
        !           652:        qabort = 1;
        !           653:        ql_zap();
        !           654:        return 0;
        !           655: }
        !           656: 
        !           657: /*----------------------------------------------------------------*/
        !           658: /* reset SCSI bus */
        !           659: int    qlogicfas_reset(Scsi_Cmnd * cmd, unsigned int flags)
        !           660: {
        !           661:        qabort = 2;
        !           662:        ql_zap();
        !           663:        return 1;
        !           664: }
        !           665: 
        !           666: /*----------------------------------------------------------------*/
        !           667: /* return info string */
        !           668: const char     *qlogicfas_info(struct Scsi_Host * host)
        !           669: {
        !           670:        return qinfo;
        !           671: }
        !           672: 
        !           673: #ifdef MODULE
        !           674: /* Eventually this will go into an include file, but this will be later */
        !           675: Scsi_Host_Template driver_template = QLOGICFAS;
        !           676: 
        !           677: #include "scsi_module.c"
        !           678: #endif
        !           679: 

unix.superglobalmegacorp.com

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