Annotation of lucent/sys/src/boot/pc/scsi14f.c, 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 "lib.h"
                     11: #include "mem.h"
                     12: #include "dat.h"
                     13: #include "fns.h"
                     14: #include "io.h"
                     15: 
                     16: typedef struct Ctlr Ctlr;
                     17: typedef struct Mailbox Mailbox;
                     18: typedef struct Scatter Scatter;
                     19: 
                     20: enum {
                     21:        Nctl            = 1,            /* only support one */
                     22:        Nmbox           = 8,            /* number of Mailboxes; up to 16? */
                     23:        Nscatter        = 33,           /* s/g list limit fixed by Ultrastor controller */
                     24:        Timeout         = 10,           /* seconds to wait for things to complete */
                     25: 
                     26:        Port            = 0x330,        /* factory defaults: I/O port */
                     27:        CtlrID          = 7,            /*      adapter SCSI id */
                     28:        Irq             = 14,           /*      interrupt request level */
                     29: };
                     30: 
                     31: struct Scatter {
                     32:        ulong   start;  /* physical address; Intel byte order */
                     33:        ulong   len;    /* length in bytes; Intel byte order */
                     34: };
                     35: 
                     36: /*
                     37:  * Ultrastor mailbox pointers point to one of these structures
                     38:  */
                     39: struct Mailbox {
                     40:        uchar   op;             /* Adapter operation */
                     41:        uchar   addr;           /* lun, chan, scsi ID */
                     42:        uchar   datap[4];       /* transfer data phys. pointer */
                     43:        uchar   datalen[4];     /* transfer data length */
                     44:        uchar   cmdlink[4];     /* command link phys. pointer */
                     45:        uchar   linkid;         /* SCSI command link ID */
                     46:        uchar   nscatter;       /* scatter/gather length (8 bytes per entry) */
                     47:        uchar   senselen;       /* length of sense data */
                     48:        uchar   cmdlen;         /* length of CDB */
                     49:        uchar   cmd[12];        /* SCSI command */
                     50:        uchar   adapterstatus;
                     51:        uchar   targetstatus;
                     52:        uchar   sensep[4];      /* sense data phys. pointer */
                     53: 
                     54:        /* the remainder is used by software, not the device */
                     55:        uchar   sensedata[64];  /* enough for AdapterInquiry data too */
                     56:        int     busy;           /* interrupt pending */
                     57:        ulong   physaddr;       /* physical address of this Mailbox */
                     58:        int     p9status;       /* p9 status value */
                     59:        Mailbox *next;          /* next Mailbox in free list */
                     60: };
                     61: 
                     62: /* pack pointer as Intel order bytes (can simply assign) */
                     63: #define        PL(buf,p)       (*(ulong*)(buf)=(ulong)(p))
                     64: 
                     65: enum {
                     66:                                        /* bits in Mailbox.op[0] */
                     67:                                        /* 3 bit opcode */
                     68:        OpAdapter       = 0x01,         /* adapter command, not SCSI command */
                     69:        OpTarget        = 0x02,         /* SCSI command for device */
                     70:        OpReset         = 0x04,         /* device reset */
                     71:                                        /* 2 bit transfer direction */
                     72:        CmdDirection    = 0<<3,         /* transfer direction determined by SCSI command */
                     73:        DataIn          = 1<<3,         /* SCSI Data In */
                     74:        DataOut         = 2<<3,         /* SCSI Data Out */
                     75:        NoTransfer      = 3<<3,
                     76:        Nodiscon=       1<<5,           /* disable disconnect */
                     77:        Usecache=       1<<6,           /* use adapter cache (if available) */
                     78:        Scattered=      1<<7,           /* transfer pointer refers to S/G list */
                     79: 
                     80:                                        /* OpAdapter commands in Mailbox.cmd[0] */
                     81:        AdapterInquiry  = 0x01,
                     82:        AdapterSelftest = 0x02,
                     83:        AdapterRead     = 0x03,         /* read adapter's buffer */
                     84:        AdapterWrite    = 0x04,         /* write to adapter's buffer */
                     85: 
                     86:                                        /* IO port offsets and bits */
                     87:        AdapterMask     = 0x00,         /* local doorbell mask register */
                     88:          OGMIntEnable  = 0x01,
                     89:          SoftResetEnable = 0x40,
                     90:          AdapterReady  = 0xe1,         /* adapter ready for work when all these set */
                     91:        AdapterIntr     = 0x01,         /* adapter interrupt/status; set by host, reset by adapter */
                     92:          SignalAdapter = 0x01,         /* tell adapter to read OGMpointer */
                     93:          BusReset      = 0x20,         /* SCSI Bus Reset */
                     94:          SoftReset     = 0x40,         /* Adapter Soft Reset */
                     95:        HostMask        = 0x02,         /* host doorbell mask register */
                     96:          ICMIntEnable  = 0x01,         /* incoming mail enable */
                     97:          SIntEnable    = 0x80,         /* enable interrupt from HostIntr reg */
                     98:        HostIntr        = 0x03,         /* host doorbell interrupt/status; set by adapter, reset by host */
                     99:          IntPending    = 0x80,         /* interrupt pending for host */
                    100:          SignalHost    = 0x01,         /* Incoming Mail Interrupt */
                    101:        ProductID       = 0x04,         /* two byte product ID */
                    102:        Config1         = 0x06,
                    103:        Config2         = 0x07,
                    104:        OGMpointer      = 0x08,         /* pointer to Outgoing Mail */
                    105:        ICMpointer      = 0x0c,         /* pointer to Incoming Mail */
                    106: };
                    107: 
                    108: #define        OUT(c,v) outb(ctlr->io+(c), (v))
                    109: #define        IN(c)   inb(ctlr->io+(c))
                    110: 
                    111: struct Ctlr {
                    112:        int     io;             /* io port */
                    113:        int     irq;            /* interrupt vector */
                    114:        int     dma;            /* DMA channel */
                    115:        int     ownid;          /* adapter's SCSI ID */
                    116:        Mailbox mbox[Nmbox];
                    117:        Mailbox *free;          /* next free Mailbox */
                    118: };
                    119: 
                    120: static Ctlr    ultra[Nctl];
                    121: 
                    122: static void
                    123: resetadapter(int busreset)
                    124: {
                    125:        Ctlr *ctlr = &ultra[0];
                    126:        int i;
                    127: 
                    128:        if(IN(AdapterMask) & SoftResetEnable){
                    129:                OUT(AdapterIntr, SoftReset|busreset);
                    130:                for(i=50000; IN(AdapterIntr) & (SoftReset|busreset);)
                    131:                        if(--i<0) {
                    132:                                print("Ultrastor reset timed out\n");
                    133:                                break;
                    134:                        }
                    135:        }
                    136: }
                    137: 
                    138: static void
                    139: freebox(Ctlr *ctlr, Mailbox *mbox)
                    140: {
                    141:        mbox->next = ctlr->free;
                    142:        ctlr->free = mbox;
                    143: }
                    144: 
                    145: static void
                    146: ultra14fwait(Ctlr *ctlr, Mailbox *mbox)
                    147: {
                    148:        ulong start;
                    149:        int x;
                    150:        static void interrupt(Ureg*, void*);
                    151: 
                    152:        x = spllo();
                    153:        start = m->ticks;
                    154:        while(TK2SEC(m->ticks - start) < Timeout && mbox->busy)
                    155:                ;
                    156:        if(TK2SEC(m->ticks - start) >= Timeout){
                    157:                print("ultra14fwait timed out\n");
                    158:                interrupt(0, ctlr);
                    159:        }
                    160:        splx(x);
                    161: }
                    162: 
                    163: static int
                    164: ultra14fexec(Scsi *p, int rflag)
                    165: {
                    166:        Ctlr *ctlr = &ultra[0];
                    167:        Mailbox *mbox;
                    168:        long n;
                    169:        uchar *cp;
                    170:        ulong s;
                    171: 
                    172:        if (p == 0 || ctlr->io == 0)
                    173:                return 0x6001;  /* device not available */
                    174: 
                    175:        /*
                    176:         * get a free Mailbox and build an Ultrastor command
                    177:         */
                    178:        if((mbox = ctlr->free) == 0)
                    179:                return 0x6001;
                    180:        ctlr->free = mbox->next;
                    181:        p->rflag = rflag;
                    182:        mbox->p9status = 0;
                    183:        mbox->op = OpTarget | CmdDirection | Usecache;  /* BUG? is it safe always to Usecache? */
                    184:        mbox->addr = p->target | (p->lun<<5);
                    185:        if(p->cmd.lim - p->cmd.ptr > sizeof(mbox->cmd))
                    186:                panic("ultra14fexec");
                    187:        mbox->cmdlen = p->cmd.lim - p->cmd.ptr;
                    188:        for(cp = mbox->cmd; p->cmd.ptr < p->cmd.lim;)
                    189:                *cp++ = *p->cmd.ptr++;
                    190:        n = p->data.lim - p->data.ptr;
                    191:        mbox->nscatter = 0;
                    192:        PL(mbox->datap, PADDR(p->data.ptr));
                    193:        PL(mbox->datalen, n);
                    194:        mbox->adapterstatus = 0;
                    195:        mbox->targetstatus = 0;
                    196: 
                    197:        /*
                    198:         * send the command to the host adapter
                    199:         */
                    200:        s = splhi();
                    201:        if(IN(AdapterIntr) & SignalAdapter)
                    202:                panic("ultrastor busy");
                    203:        mbox->busy = 1;
                    204:        outl(ctlr->io+OGMpointer, mbox->physaddr);
                    205:        OUT(AdapterIntr, SignalAdapter);
                    206: 
                    207:        /*
                    208:         * wait for reply
                    209:         */
                    210:        splx(s);
                    211:        ultra14fwait(ctlr, mbox);
                    212: 
                    213:        p->status = mbox->p9status;
                    214:        if(p->status == 0x6000)
                    215:                p->data.ptr = p->data.lim;      /* can only assume no residue */
                    216:        freebox(ctlr, mbox);
                    217:        return p->status;
                    218: }
                    219: 
                    220: static void
                    221: scsimoan(char *msg, Mailbox *mbox)
                    222: {
                    223:        /*int i;*/
                    224: 
                    225:        print("SCSI error: %s:", msg);
                    226:        print("id=%d cmd=%2.2x status=%2.2x adapter=%2.2x",
                    227:                mbox->addr&7, mbox->cmd[0], mbox->targetstatus, mbox->adapterstatus);
                    228:        /*print(" sense:");
                    229:        for(i=0; i<10; i++)
                    230:                print(" %2.2x", mbox->sensedata[i]);*/
                    231:        print("\n");
                    232: }
                    233: 
                    234: static void
                    235: interrupt(Ureg*, void *arg)
                    236: {
                    237:        Ctlr *ctlr;
                    238:        Mailbox *mbox;
                    239:        ulong pa;
                    240: 
                    241:        ctlr = arg;
                    242: 
                    243:        if((IN(HostIntr) & SignalHost) == 0)
                    244:                return; /* no incoming mail */
                    245:        pa = inl(ctlr->io+ICMpointer);
                    246:        OUT(HostIntr, SignalHost);      /* release ICM slot */
                    247:        for(mbox = &ctlr->mbox[0]; mbox->physaddr != pa;)
                    248:                if(++mbox >= &ctlr->mbox[Nmbox]) {
                    249:                        /* these sometimes happen in response to a scsi bus reset; ignore them */
                    250:                        print("ultrastor: invalid ICM pointer #%lux\n", pa);
                    251:                        return;
                    252:                }
                    253: 
                    254:        mbox->p9status = 0x1000 | mbox->adapterstatus;
                    255:        switch(mbox->adapterstatus){
                    256:        default:
                    257:                scsimoan("adapter", mbox);
                    258:                if(mbox->adapterstatus >= 0x92) /* ie, scsi command protocol error */
                    259:                        resetadapter(BusReset);
                    260:                /* might adapter reset be required in other cases? */
                    261:                break;
                    262: 
                    263:        case 0x91:      /* selection timed out */
                    264:                mbox->p9status = 0x20;
                    265:                break;
                    266: 
                    267:        case 0xA3:
                    268:                scsimoan("SCSI bus reset error", mbox);
                    269:                break;
                    270: 
                    271:        case 0x00:
                    272:                mbox->p9status = 0x6000 | mbox->targetstatus;
                    273:                break;
                    274:        }
                    275:        mbox->busy = 0;
                    276: }
                    277: 
                    278: static int irq[4] = {
                    279:        15, 14, 11, 10,
                    280: };
                    281: 
                    282: int (*
                    283: ultra14freset(void))(Scsi*, int)
                    284: {
                    285:        Ctlr *ctlr = &ultra[0];
                    286:        Mailbox *mbox;
                    287:        int i, model;
                    288: 
                    289:        /*
                    290:         * Check it is an Ultrastor [13]4f.
                    291:         * Only one controller for now.
                    292:         * For the moment assume the factory default settings.
                    293:         */
                    294:        memset(ctlr, 0, sizeof(Ctlr));
                    295:        ctlr->io = Port;
                    296: 
                    297:        if(IN(ProductID) != 0x56)
                    298:                return 0;
                    299:        model = IN(ProductID+1);
                    300:        switch(model){
                    301: 
                    302:        case 0x40:
                    303:                model = 14;
                    304:                break;
                    305: 
                    306:        case 0x41:
                    307:                model = 34;
                    308:                break;
                    309: 
                    310:        default:
                    311:                return 0;
                    312:        }
                    313: 
                    314:        i = IN(Config1);
                    315:        ctlr->irq = irq[((i>>4)&03)];
                    316:        if(model == 14)
                    317:                ctlr->dma = 5 + ((i>>6)&03);
                    318:        ctlr->ownid = IN(Config2)&07;
                    319:        /*print("Ultrastor %dF id %d io 0x%x irq %d dma %d\n",
                    320:                model, ctlr->ownid, ctlr->io, ctlr->irq, ctlr->dma);*/
                    321: 
                    322:        /*
                    323:         * set the DMA controller to cascade mode for bus master
                    324:         */
                    325:        switch(ctlr->dma){
                    326:        case 5:
                    327:                outb(0xd6, 0xc1); outb(0xd4, 1); break;
                    328:        case 6:
                    329:                outb(0xd6, 0xc2); outb(0xd4, 2); break;
                    330:        case 7:
                    331:                outb(0xd6, 0xc3); outb(0xd4, 3); break;
                    332:        }
                    333: 
                    334:        resetadapter(0);
                    335:        ctlr->free = 0;
                    336:        for(i=0; i<Nmbox; i++){
                    337:                mbox = &ctlr->mbox[i];
                    338:                memset(mbox, 0, sizeof(*mbox));
                    339:                mbox->physaddr = PADDR(mbox);
                    340:                PL(mbox->sensep, 0);    /* DON'T collect sense data automatically: messes up scuzz? */
                    341:                mbox->senselen = 0;
                    342:                mbox->next = ctlr->free;
                    343:                ctlr->free = mbox;
                    344:        }
                    345: 
                    346:        setvec(Int0vec+ctlr->irq, interrupt, ctlr);
                    347: 
                    348:        /*
                    349:         * issue AdapterInquiry command to check it's alive
                    350:         * -- could check enquiry data
                    351:         */
                    352:        OUT(HostMask, 0);       /* mask interrupts */
                    353:        mbox = &ctlr->mbox[0];
                    354:        mbox->op = OpAdapter | CmdDirection;
                    355:        mbox->addr = ctlr->ownid;
                    356:        mbox->cmdlen = 1;
                    357:        mbox->cmd[0] = AdapterInquiry;
                    358:        PL(mbox->datap, PADDR(mbox->sensedata));
                    359:        PL(mbox->datalen, 38);
                    360:        while(IN(AdapterIntr) & SignalAdapter)
                    361:                ;
                    362:        outl(ctlr->io+OGMpointer, mbox->physaddr);
                    363:        OUT(AdapterIntr, SignalAdapter);
                    364:        for(i=100000; (IN(HostIntr)&SignalHost)==0;)
                    365:                if(--i < 0){
                    366:                        print("No response to UltraStor Inquiry\n");
                    367:                        ctlr->io = 0;
                    368:                        return 0;
                    369:                }
                    370:        OUT(HostIntr, SignalHost);
                    371: 
                    372:        OUT(HostMask, ICMIntEnable|SIntEnable);
                    373: 
                    374:        return ultra14fexec;
                    375: }

unix.superglobalmegacorp.com

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