Annotation of lucent/sys/src/9/pc/f002531, revision 1.1

1.1     ! root        1: /*
        !             2:  * Ultrastor [13]4f SCSI Host Adapter.
        !             3:  * Originally written by Charles Forsyth, [email protected].
        !             4:  * Needs work:
        !             5:  *     handle multiple controllers;
        !             6:  *     set options from user-level;
        !             7:  *     split out to handle adaptec too;
        !             8:  */
        !             9: #include "u.h"
        !            10: #include "../port/lib.h"
        !            11: #include "mem.h"
        !            12: #include "dat.h"
        !            13: #include "fns.h"
        !            14: #include "io.h"
        !            15: #include "../port/error.h"
        !            16: 
        !            17: #include "ureg.h"
        !            18: 
        !            19: typedef struct Ctlr Ctlr;
        !            20: typedef struct Mailbox Mailbox;
        !            21: typedef struct Scatter Scatter;
        !            22: 
        !            23: enum {
        !            24:        Nctl            = 1,            /* only support one */
        !            25:        Nmbox           = 8,            /* number of Mailboxes; up to 16? */
        !            26:        Nscatter        = 33,           /* s/g list limit fixed by Ultrastor controller */
        !            27: 
        !            28:        Port            = 0x330,        /* factory defaults: I/O port */
        !            29:        CtlrID          = 7,            /*      adapter SCSI id */
        !            30:        Irq             = 14,           /*      interrupt request level */
        !            31: };
        !            32: 
        !            33: struct Scatter {
        !            34:        ulong   start;  /* physical address; Intel byte order */
        !            35:        ulong   len;    /* length in bytes; Intel byte order */
        !            36: };
        !            37: 
        !            38: /*
        !            39:  * Ultrastor mailbox pointers point to one of these structures
        !            40:  */
        !            41: struct Mailbox {
        !            42:        uchar   op;             /* Adapter operation */
        !            43:        uchar   addr;           /* lun, chan, scsi ID */
        !            44:        uchar   datap[4];       /* transfer data phys. pointer */
        !            45:        uchar   datalen[4];     /* transfer data length */
        !            46:        uchar   cmdlink[4];     /* command link phys. pointer */
        !            47:        uchar   linkid;         /* SCSI command link ID */
        !            48:        uchar   nscatter;       /* scatter/gather length (8 bytes per entry) */
        !            49:        uchar   senselen;       /* length of sense data */
        !            50:        uchar   cmdlen;         /* length of CDB */
        !            51:        uchar   cmd[12];        /* SCSI command */
        !            52:        uchar   adapterstatus;
        !            53:        uchar   targetstatus;
        !            54:        uchar   sensep[4];      /* sense data phys. pointer */
        !            55: 
        !            56:        /* the remainder is used by software, not the device */
        !            57:        uchar   sensedata[64];  /* enough for AdapterInquiry data too */
        !            58:        Scatter sglist[Nscatter];
        !            59:        Rendez  iodone;
        !            60:        int     busy;           /* interrupt pending */
        !            61:        ulong   physaddr;       /* physical address of this Mailbox */
        !            62:        int     p9status;       /* p9 status value */
        !            63:        Mailbox *next;          /* next Mailbox in free list */
        !            64: };
        !            65: 
        !            66: /* pack pointer as Intel order bytes (can simply assign) */
        !            67: #define        PL(buf,p)       (*(ulong*)(buf)=(ulong)(p))
        !            68: 
        !            69: enum {
        !            70:                                        /* bits in Mailbox.op[0] */
        !            71:                                        /* 3 bit opcode */
        !            72:        OpAdapter       = 0x01,         /* adapter command, not SCSI command */
        !            73:        OpTarget        = 0x02,         /* SCSI command for device */
        !            74:        OpReset         = 0x04,         /* device reset */
        !            75:                                        /* 2 bit transfer direction */
        !            76:        CmdDirection    = 0<<3,         /* transfer direction determined by SCSI command */
        !            77:        DataIn          = 1<<3,         /* SCSI Data In */
        !            78:        DataOut         = 2<<3,         /* SCSI Data Out */
        !            79:        NoTransfer      = 3<<3,
        !            80:        Nodiscon=       1<<5,           /* disable disconnect */
        !            81:        Usecache=       1<<6,           /* use adapter cache (if available) */
        !            82:        Scattered=      1<<7,           /* transfer pointer refers to S/G list */
        !            83: 
        !            84:                                        /* OpAdapter commands in Mailbox.cmd[0] */
        !            85:        AdapterInquiry  = 0x01,
        !            86:        AdapterSelftest = 0x02,
        !            87:        AdapterRead     = 0x03,         /* read adapter's buffer */
        !            88:        AdapterWrite    = 0x04,         /* write to adapter's buffer */
        !            89: 
        !            90:                                        /* IO port offsets and bits */
        !            91:        AdapterMask     = 0x00,         /* local doorbell mask register */
        !            92:          OGMIntEnable  = 0x01,
        !            93:          SoftResetEnable = 0x40,
        !            94:          AdapterReady  = 0xe1,         /* adapter ready for work when all these set */
        !            95:        AdapterIntr     = 0x01,         /* adapter interrupt/status; set by host, reset by adapter */
        !            96:          SignalAdapter = 0x01,         /* tell adapter to read OGMpointer */
        !            97:          BusReset      = 0x20,         /* SCSI Bus Reset */
        !            98:          SoftReset     = 0x40,         /* Adapter Soft Reset */
        !            99:        HostMask        = 0x02,         /* host doorbell mask register */
        !           100:          ICMIntEnable  = 0x01,         /* incoming mail enable */
        !           101:          SIntEnable    = 0x80,         /* enable interrupt from HostIntr reg */
        !           102:        HostIntr        = 0x03,         /* host doorbell interrupt/status; set by adapter, reset by host */
        !           103:          IntPending    = 0x80,         /* interrupt pending for host */
        !           104:          SignalHost    = 0x01,         /* Incoming Mail Interrupt */
        !           105:        ProductID       = 0x04,         /* two byte product ID */
        !           106:        Config1         = 0x06,
        !           107:        Config2         = 0x07,
        !           108:        OGMpointer      = 0x08,         /* pointer to Outgoing Mail */
        !           109:        ICMpointer      = 0x0c,         /* pointer to Incoming Mail */
        !           110: };
        !           111: 
        !           112: #define        OUT(c,v) outb(ctlr->io+(c), (v))
        !           113: #define        IN(c)   inb(ctlr->io+(c))
        !           114: 
        !           115: struct Ctlr {
        !           116:        Lock;
        !           117:        QLock;
        !           118:        int     io;             /* io port */
        !           119:        int     irq;            /* interrupt vector */
        !           120:        int     dma;            /* DMA channel */
        !           121:        int     ownid;          /* adapter's SCSI ID */
        !           122:        Mailbox mbox[Nmbox];
        !           123:        Mailbox *free;          /* next free Mailbox */
        !           124:        Rendez  mboxes;         /* wait for free mbox */
        !           125:        QLock   mboxq;          /* mutex for mboxes */
        !           126:        Rendez  ogm;            /* wait for free OGM slot with Ctlr qlocked */
        !           127: };
        !           128: 
        !           129: static Ctlr    ultra[Nctl];
        !           130: 
        !           131: int    scsidebugs[8] = {0};
        !           132: int    scsiownid = 7;
        !           133: 
        !           134: static void
        !           135: prmbox(Mailbox *m)
        !           136: {
        !           137:        int i;
        !           138: 
        !           139:        print("scsi %lx: op=%2.2x dir=%x cmd=%d [", m->physaddr, m->op&07, (m->op>>3)&3, m->cmdlen);
        !           140:        for(i=0; i<m->cmdlen; i++)
        !           141:                print(" %2.2x", m->cmd[i]);
        !           142:        print("] id=%d lun=%d chan=%d", m->addr&7, (m->addr>>5)&7, (m->addr>>3)&3);
        !           143:        print(" dlen=%lx dptr=%lx\n", *(long*)m->datalen, *(long*)m->datap);
        !           144:        print(" astat=%2.2x dstat=%2.2x sc=%d [", m->adapterstatus, m->targetstatus, m->nscatter);
        !           145:        for(i=0; i<m->nscatter; i++)
        !           146:                print(" %lx,%ld", m->sglist[i].start, m->sglist[i].len);
        !           147:        print("]\n");
        !           148:        /*for(i=0; i<10; i++)
        !           149:                print(" %2.2x", m->sensedata[i]);*/
        !           150:        print("\n");
        !           151: }
        !           152: 
        !           153: static void
        !           154: resetadapter(int busreset)
        !           155: {
        !           156:        Ctlr *ctlr = &ultra[0];
        !           157:        int i;
        !           158: 
        !           159:        if(IN(AdapterMask) & SoftResetEnable){
        !           160:                OUT(AdapterIntr, SoftReset|busreset);
        !           161:                for(i=50000; IN(AdapterIntr) & (SoftReset|busreset);)
        !           162:                        if(--i<0) {
        !           163:                                print("Ultrastor reset timed out\n");
        !           164:                                break;
        !           165:                        }
        !           166:        }
        !           167: }
        !           168: 
        !           169: static void
        !           170: freebox(Ctlr *ctlr, Mailbox *m)
        !           171: {
        !           172:        lock(ctlr);
        !           173:        if((m->next = ctlr->free) == 0)
        !           174:                wakeup(&ctlr->mboxes);
        !           175:        ctlr->free = m;
        !           176:        unlock(ctlr);
        !           177: }
        !           178: 
        !           179: static int
        !           180: boxavail(void *a)
        !           181: {
        !           182:        return ((Ctlr*)a)->free != 0;
        !           183: }
        !           184: 
        !           185: static int
        !           186: scatter(Scatter *list, void *va, ulong nb)
        !           187: {
        !           188:        char *p = (char *)va;
        !           189:        Scatter *sp = list;
        !           190:        int limit = Nscatter;
        !           191: 
        !           192:        for(; nb != 0; sp++){
        !           193:                if(--limit < 0)
        !           194:                        panic("Ultrastor I/O too scattered");
        !           195:                sp->start = PADDR(p);
        !           196:                sp->len = BY2PG - (sp->start&(BY2PG-1));        /* the rest of that page */
        !           197:                if(sp->len > nb)
        !           198:                        sp->len = nb;
        !           199:                nb -= sp->len;
        !           200:                p += sp->len;
        !           201:        }
        !           202:        return sp - list;
        !           203: }
        !           204: 
        !           205: static int
        !           206: isready(void *a)
        !           207: {
        !           208:        Ctlr *ctlr = (Ctlr*)a;
        !           209: 
        !           210:        return (IN(AdapterIntr) & SignalAdapter) == 0;
        !           211: }
        !           212: 
        !           213: static int
        !           214: isdone(void *a)
        !           215: {
        !           216:        return ((Mailbox*)a)->busy == 0;
        !           217: }
        !           218: 
        !           219: static int
        !           220: ultra14fexec(Scsi *p, int rflag)
        !           221: {
        !           222:        Ctlr *ctlr = &ultra[0];
        !           223:        Mailbox *m;
        !           224:        long n;
        !           225:        uchar *cp;
        !           226: 
        !           227:        if (p == 0 || ctlr->io == 0)
        !           228:                return 0x0200;  /* device not available */
        !           229: 
        !           230:        /*
        !           231:         * get a free Mailbox and build an Ultrastor command
        !           232:         */
        !           233:        while(lock(ctlr), (m = ctlr->free) == 0){
        !           234:                unlock(ctlr);
        !           235:                qlock(&ctlr->mboxq);
        !           236:                if(waserror()){
        !           237:                        qunlock(&ctlr->mboxq);
        !           238:                        nexterror();
        !           239:                }
        !           240:                sleep(&ctlr->mboxes, boxavail, ctlr);
        !           241:                poperror();
        !           242:                qunlock(&ctlr->mboxq);
        !           243:        }
        !           244:        ctlr->free = m->next;
        !           245:        unlock(ctlr);
        !           246:        p->rflag = rflag;
        !           247:        m->p9status = 0;
        !           248:        m->op = OpTarget | CmdDirection | Usecache;     /* BUG? is it safe always to Usecache? */
        !           249:        m->addr = p->target | (p->lun<<5);
        !           250:        if(p->cmd.lim - p->cmd.ptr > sizeof(m->cmd))
        !           251:                panic("scsiexec");
        !           252:        m->cmdlen = p->cmd.lim - p->cmd.ptr;
        !           253:        for(cp = m->cmd; p->cmd.ptr < p->cmd.lim;)
        !           254:                *cp++ = *p->cmd.ptr++;
        !           255:        n = p->data.lim - p->data.ptr;
        !           256:        if(n){
        !           257:                PL(m->datap, PADDR(m->sglist));
        !           258:                m->op |= Scattered;
        !           259:                m->nscatter = scatter(m->sglist, p->data.ptr, n);
        !           260:        } else {
        !           261:                m->nscatter = 0; /* controller will not allow s/g when n==0 */
        !           262:                PL(m->datap, 0);
        !           263:        }
        !           264:        PL(m->datalen, n);
        !           265:        m->adapterstatus = 0;
        !           266:        m->targetstatus = 0;
        !           267: 
        !           268:        /*
        !           269:         * send the command to the host adapter
        !           270:         */
        !           271:        while(lock(ctlr), IN(AdapterIntr) & SignalAdapter) {    /* adapter busy: infrequent? */
        !           272:                static int fred;
        !           273:                if(fred == 0){
        !           274:                        print("ultrastor busy\n");
        !           275:                        fred = 1;
        !           276:                }
        !           277:                unlock(ctlr);
        !           278:                qlock(ctlr);
        !           279:                if(waserror()) {
        !           280:                        freebox(ctlr, m);
        !           281:                        qunlock(ctlr);
        !           282:                        nexterror();
        !           283:                }
        !           284:                sleep(&ctlr->ogm, isready, ctlr);
        !           285:                poperror();
        !           286:                qunlock(ctlr);
        !           287:        }
        !           288:        m->busy = 1;
        !           289:        outl(ctlr->io+OGMpointer, m->physaddr);
        !           290:        OUT(AdapterIntr, SignalAdapter);
        !           291:        unlock(ctlr);
        !           292: 
        !           293:        /*
        !           294:         * wait for reply
        !           295:         */
        !           296:        while(waserror())
        !           297:                ;       /* could send MSCP abort request to adapter */
        !           298:        while(m->busy)
        !           299:                sleep(&m->iodone, isdone, m);
        !           300:        poperror();
        !           301:        p->status = m->p9status;
        !           302:        if(scsidebugs[2])
        !           303:                prmbox(m);
        !           304:        if(p->status == 0x6000)
        !           305:                p->data.ptr = p->data.lim;      /* can only assume no residue */
        !           306:        freebox(ctlr, m);
        !           307:        return p->status;
        !           308: }
        !           309: 
        !           310: static void
        !           311: scsimoan(char *msg, Mailbox *m)
        !           312: {
        !           313:        /*int i;*/
        !           314: 
        !           315:        print("SCSI error: %s:", msg);
        !           316:        print("id=%d cmd=%2.2x status=%2.2x adapter=%2.2x", m->addr&7, m->cmd[0], m->targetstatus, m->adapterstatus);
        !           317:        /*print(" sense:");
        !           318:        for(i=0; i<10; i++)
        !           319:                print(" %2.2x", m->sensedata[i]);*/
        !           320:        print("\n");
        !           321: }
        !           322: 
        !           323: static void
        !           324: interrupt(Ureg *ur, void *a)
        !           325: {
        !           326:        Ctlr *ctlr = &ultra[0];
        !           327:        Mailbox *m;
        !           328:        ulong pa;
        !           329: 
        !           330:        USED(ur, a);
        !           331:        if(ctlr->ogm.p && (IN(AdapterIntr) & SignalAdapter) == 0)
        !           332:                wakeup(&ctlr->ogm);
        !           333:        if((IN(HostIntr) & SignalHost) == 0)
        !           334:                return; /* no incoming mail */
        !           335:        pa = inl(ctlr->io+ICMpointer);
        !           336:        OUT(HostIntr, SignalHost);      /* release ICM slot */
        !           337:        for(m = &ctlr->mbox[0]; m->physaddr != pa;)
        !           338:                if(++m >= &ctlr->mbox[Nmbox]) {
        !           339:                        /* these sometimes happen in response to a scsi bus reset; ignore them */
        !           340:                        print("ultrastor: invalid ICM pointer #%lux\n", pa);
        !           341:                        return;
        !           342:                }
        !           343:        if(scsidebugs[1])
        !           344:                prmbox(m);
        !           345: 
        !           346:        m->p9status = 0x1000 | m->adapterstatus;
        !           347:        switch(m->adapterstatus){
        !           348:        default:
        !           349:                scsimoan("adapter", m);
        !           350:                if(m->adapterstatus >= 0x92) /* ie, scsi command protocol error */
        !           351:                        resetadapter(BusReset);
        !           352:                /* might adapter reset be required in other cases? */
        !           353:                break;
        !           354: 
        !           355:        case 0x91:      /* selection timed out */
        !           356:                m->p9status = 0x0200;
        !           357:                if(scsidebugs[0])
        !           358:                        scsimoan("timeout", m);
        !           359:                break;
        !           360: 
        !           361:        case 0xA3:
        !           362:                scsimoan("SCSI bus reset error", m);
        !           363:                break;
        !           364: 
        !           365:        case 0x00:
        !           366:                m->p9status = 0x6000 | m->targetstatus;
        !           367:                if(m->targetstatus && scsidebugs[0])
        !           368:                        scsimoan("device", m);
        !           369:                break;
        !           370:        }
        !           371:        m->busy = 0;
        !           372:        wakeup(&m->iodone);
        !           373: }
        !           374: 
        !           375: static ISAConf ultra14f = {
        !           376:        "ultra14f",
        !           377:        Port,
        !           378:        Irq,
        !           379:        0,
        !           380:        0,
        !           381: };
        !           382: 
        !           383: static int irq[4] = {
        !           384:        15, 14, 11, 10,
        !           385: };
        !           386: 
        !           387: int (*
        !           388: ultra14freset(void))(Scsi*, int)
        !           389: {
        !           390:        ISAConf *isa = &ultra14f;
        !           391:        Ctlr *ctlr = &ultra[0];
        !           392:        Mailbox *m;
        !           393:        int i, model;
        !           394: 
        !           395:        /*
        !           396:         * See if we have any configuration info
        !           397:         * and check it is an Ultrastor [13]4f.
        !           398:         * Only one controller for now.
        !           399:         */
        !           400:        if(isaconfig("scsi", 0, &ultra14f) == 0)
        !           401:                return 0;
        !           402:        memset(ctlr, 0, sizeof(Ctlr));
        !           403:        ctlr->io = isa->port;
        !           404: 
        !           405:        if(IN(ProductID) != 0x56)
        !           406:                return 0;
        !           407:        model = IN(ProductID+1);
        !           408:        switch(model){
        !           409: 
        !           410:        case 0x40:
        !           411:                model = 14;
        !           412:                break;
        !           413: 
        !           414:        case 0x41:
        !           415:                model = 34;
        !           416:                break;
        !           417: 
        !           418:        default:
        !           419:                return 0;
        !           420:        }
        !           421: 
        !           422:        i = IN(Config1);
        !           423:        ctlr->irq = irq[((i>>4)&03)];
        !           424:        if(model == 14)
        !           425:                ctlr->dma = 5 + ((i>>6)&03);
        !           426:        ctlr->ownid = IN(Config2)&07;
        !           427:        /*print("Ultrastor %dF id %d io 0x%x irq %d dma %d\n",
        !           428:                model, ctlr->ownid, ctlr->io, ctlr->irq, ctlr->dma);*/
        !           429: 
        !           430:        /*
        !           431:         * set the DMA controller to cascade mode for bus master
        !           432:         */
        !           433:        switch(ctlr->dma){
        !           434:        case 5:
        !           435:                outb(0xd6, 0xc1); outb(0xd4, 1); break;
        !           436:        case 6:
        !           437:                outb(0xd6, 0xc2); outb(0xd4, 2); break;
        !           438:        case 7:
        !           439:                outb(0xd6, 0xc3); outb(0xd4, 3); break;
        !           440:        }
        !           441: 
        !           442:        resetadapter(0);
        !           443:        ctlr->free = 0;
        !           444:        for(i=0; i<Nmbox; i++){
        !           445:                m = &ctlr->mbox[i];
        !           446:                memset(m, 0, sizeof(*m));
        !           447:                m->physaddr = PADDR(m);
        !           448:                PL(m->sensep, 0);       /* DON'T collect sense data automatically: messes up scuzz? */
        !           449:                m->senselen = 0;
        !           450:                m->next = ctlr->free;
        !           451:                ctlr->free = m;
        !           452:        }
        !           453: 
        !           454:        setvec(Int0vec+ctlr->irq, interrupt, 0);
        !           455: 
        !           456:        /*
        !           457:         * issue AdapterInquiry command to check it's alive
        !           458:         * -- could check enquiry data
        !           459:         */
        !           460:        OUT(HostMask, 0);       /* mask interrupts */
        !           461:        m = &ctlr->mbox[0];
        !           462:        m->op = OpAdapter | CmdDirection;
        !           463:        m->addr = ctlr->ownid;
        !           464:        m->cmdlen = 1;
        !           465:        m->cmd[0] = AdapterInquiry;
        !           466:        PL(m->datap, PADDR(m->sensedata));
        !           467:        PL(m->datalen, 38);
        !           468:        while(IN(AdapterIntr) & SignalAdapter)
        !           469:                ;
        !           470:        outl(ctlr->io+OGMpointer, m->physaddr);
        !           471:        OUT(AdapterIntr, SignalAdapter);
        !           472:        for(i=100000; (IN(HostIntr)&SignalHost)==0;)
        !           473:                if(--i < 0){
        !           474:                        print("No response to UltraStor Inquiry\n");
        !           475:                        ctlr->io = 0;
        !           476:                        return 0;
        !           477:                }
        !           478:        OUT(HostIntr, SignalHost);
        !           479: 
        !           480:        OUT(HostMask, ICMIntEnable|SIntEnable);
        !           481:        scsiownid = ctlr->ownid;
        !           482: 
        !           483:        print("scsi%d: %s: port %lux irq %d, dma = %d\n",
        !           484:                0, isa->type, ctlr->io, ctlr->irq, ctlr->dma);
        !           485: 
        !           486:        return ultra14fexec;
        !           487: }

unix.superglobalmegacorp.com

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