Annotation of lucent/sys/src/9/pc/f002531, revision 1.1.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.