Annotation of researchv10no/sys/io/up.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * UNIBUS SMD disk driver
                      3:  *
                      4:  * undone:
                      5:  *     Add bad sector forwarding code
                      6:  *     Check that offset recovery code works
                      7:  *     unibus mapping is suboptimal; if the queue gets long,
                      8:  *     buffered data paths will be underused
                      9:  */
                     10: 
                     11: #include "sys/param.h"
                     12: #include "sys/buf.h"
                     13: #include "sys/conf.h"
                     14: #include "sys/user.h"
                     15: #include "sys/up.h"
                     16: #include "sys/ubaddr.h"
                     17: #include "sys/subaddr.h"
                     18: #include "sys/diskio.h"
                     19: #include "sys/file.h"
                     20: 
                     21: #define        NOUPSEEK        1       /* because emulex doesn't do it right */
                     22: 
                     23: /*
                     24:  * hardware registers
                     25:  */
                     26: 
                     27: struct updevice
                     28: {
                     29:        unsigned short  upcs1;          /* control and status register 1 */
                     30:        short   upwc;                   /* word count register */
                     31:        unsigned short  upba;           /* UNIBUS address register */
                     32:        unsigned short  upda;           /* desired address register */
                     33:        unsigned short  upcs2;          /* control and status register 2 */
                     34:        unsigned short  upds;           /* drive status */
                     35:        unsigned short  uper1;          /* error register 1 */
                     36:        unsigned short  upas;           /* attention summary */
                     37:        unsigned short  upla;           /* look ahead */
                     38:        unsigned short  updb;           /* data buffer */
                     39:        unsigned short  upmr;           /* maintenance */ 
                     40:        unsigned short  updt;           /* drive type */
                     41:        unsigned short  upsn;           /* serial number */
                     42:        unsigned short  upof;           /* offset register */
                     43:        unsigned short  updc;           /* desired cylinder address register */
                     44:        unsigned short  uphr;           /* holding register */
                     45:        unsigned short  upmr2;          /* maintenance register 2 */
                     46:        unsigned short  uper2;          /* error register 2 */
                     47:        unsigned short  upec1;          /* burst error bit position */
                     48:        unsigned short  upec2;          /* burst error bit pattern */
                     49: };
                     50: 
                     51: /*
                     52:  * upcs1
                     53:  */
                     54: 
                     55: #define        UP_SC   0100000         /* special condition */
                     56: #define        UP_TRE  0040000         /* transfer error */
                     57: #define        UP_IE   0000100         /* interrupt enable */
                     58: #define        UP_GO   0000001
                     59: 
                     60: #define        UP_SEEK         004             /* seek */
                     61: #define        UP_RECAL        006             /* recalibrate */
                     62: #define        UP_DCLR         010             /* drive clear */
                     63: #define        UP_OFFSET       014             /* offset */
                     64: #define        UP_RTC          016             /* return to center-line */
                     65: #define        UP_PRESET       020             /* read-in preset */
                     66: #define        UP_SEARCH       030             /* search */
                     67: #define        UP_WCOM         060             /* write */
                     68: #define        UP_RCOM         070             /* read data */
                     69: 
                     70: /*
                     71:  * upcs2
                     72:  */
                     73: #define        UPCS2_NED       0010000         /* nonexistent drive */
                     74: #define        UPCS2_CLR       0000040         /* controller clear */
                     75: #define        UPCS2_SEL       0000007         /* unit select */
                     76: 
                     77: /*
                     78:  * upds
                     79:  */
                     80: #define        UPDS_ERR        0040000         /* composite drive error */
                     81: #define        UPDS_PIP        0020000         /* positioning in progress */
                     82: #define        UPDS_MOL        0010000         /* medium on line */
                     83: #define        UPDS_DPR        0000400         /* drive present */
                     84: #define        UPDS_DRY        0000200         /* drive ready */
                     85: #define        UPDS_VV         0000100         /* volume valid */
                     86: #define        UPDS_DREADY     (UPDS_DPR|UPDS_DRY|UPDS_MOL|UPDS_VV)
                     87: 
                     88: /*
                     89:  * uper1
                     90:  */
                     91: #define        UPER1_DCK       0100000         /* data check */
                     92: #define        UPER1_WLE       0004000         /* write lock error */
                     93: #define        UPER1_ECH       0000100         /* ecc hard error */
                     94: 
                     95: /*
                     96:  * uphr: emulex hack
                     97:  */
                     98: #define        UPHR_MAXCYL     0100027         /* max cyl address */
                     99: #define        UPHR_MAXTRAK    0100030         /* max track address */
                    100: #define        UPHR_MAXSECT    0100031         /* max sector address */
                    101: 
                    102: /*
                    103:  * upof
                    104:  */
                    105: #define        UPOF_FMT22      0010000         /* 16 bit format */
                    106: /* THE SC21 ACTUALLY JUST IMPLEMENTS ADVANCE/RETARD... */
                    107: #define        UPOF_P400       0020            /*  +400 uinches */
                    108: #define        UPOF_M400       0220            /*  -400 uinches */
                    109: #define        UPOF_P800       0040            /*  +800 uinches */
                    110: #define        UPOF_M800       0240            /*  -800 uinches */
                    111: #define        UPOF_P1200      0060            /* +1200 uinches */
                    112: #define        UPOF_M1200      0260            /* -1200 uinches */
                    113: 
                    114: #define        SECTOR  512     /* size of a hardware sector */
                    115: 
                    116: /*
                    117:  * monstrous size tables
                    118:  * one per type of drive
                    119:  */
                    120: struct size
                    121: {
                    122:        daddr_t nblocks;
                    123:        daddr_t blkoff;
                    124: } up_sizes[NUPPART] = {
                    125:        15884,  0*608,          /* A=cyl 0 thru 26 */
                    126:        33440,  27*608,         /* B=cyl 27 thru 81 */
                    127:        495520, 0*608,          /* C=cyl 0 thru 814 */
                    128:        15884,  562*608,                /* D=cyl 562 thru 588 */
                    129:        55936,  589*608,                /* E=cyl 589 thru 680 */
                    130: #ifndef NOBADSECT
                    131:        81376,  681*608,                /* F=cyl 681 thru 814 */
                    132:        153728, 562*608,                /* G=cyl 562 thru 814 */
                    133: #else
                    134:        81472,  681*608,
                    135:        153824, 562*608,
                    136: #endif
                    137:        291346, 82*608,         /* H=cyl 82 thru 561 */
                    138: }, fj_sizes[8] = {
                    139:        10240,  0*320,          /* A=cyl 0 thru 31 */
                    140:        20480,  32*320,         /* B=cyl 32 thru 95 */
                    141:        232640, 96*320,         /* C=cyl 96 thru 822 */
                    142:        0,      0*320,
                    143:        0,      0*320,
                    144:        0,      0*320,
                    145:        0,      0*320,
                    146: #ifndef NOBADSECT
                    147:        0,      0*320,          /* H=cyl 155 thru 822 */
                    148: #else
                    149:        0,      0*320,
                    150: #endif
                    151: }, fj3_sizes[8] = {
                    152:        10240,  0*512,          /* A=cyl 0 thru 19 */
                    153:        20480,  20*512,         /* B=cyl 20 thru 59 */
                    154:        246784, 60*512,         /* C=cyl 60 thru 541 */
                    155:        246784, 542*512,                /* D=cyl 542 thru 1024 */
                    156:        0,      0*512,
                    157:        0,      0*512,
                    158:        0,      0*512,
                    159: #ifndef NOBADSECT
                    160:        0,      0*512,          /* H=cyl 155 thru 822 */
                    161: #else
                    162:        0,      0*512,
                    163: #endif
                    164: }, cd_sizes[8] = {
                    165:        10240,  0*160,          /* A=cyl 0 thru 63 */
                    166:        20480,  64*160,         /* B=cyl 64 thru 191 */
                    167:        100960, 192*160,                /* C=cyl 192 thru 822 */
                    168:        0,      0*160,
                    169:        0,      0*160,
                    170:        0,      0*160,
                    171:        0,      0*160,
                    172: #ifndef NOBADSECT
                    173:        100960, 0*160,          /* H=cyl 0 thru 630 */
                    174: #else
                    175:        100960, 0*160,
                    176: #endif
                    177: }, fj1_sizes[8] = {
                    178:        1024,   0*256,          /* cyl 0 through 3 */
                    179:        0,      0*256,
                    180:        0,      0*256,
                    181:        0,      0*256,
                    182:        0,      0*256,
                    183:        0,      0*256,
                    184:        0,      0*256,
                    185:        0,      0*256,
                    186: };
                    187: 
                    188: /*
                    189:  * tables of per-drive info, mostly sizes of things
                    190:  * indexed by magic numbers; see uputype
                    191:  */
                    192: struct upst upst[] = {
                    193:        32, 19, 3, 4,   32*19,  823,    up_sizes,       /* 9300/cdc */
                    194: /* 9300 actually has 815 cylinders... */
                    195:        32, 10, 3, 4,   32*10,  823,    fj_sizes,       /* fujitsu 160m */
                    196:        32, 5,  3, 4,   32*5,   631,    cd_sizes,       /* CDC 76 MB */
                    197:        32, 8,  3, 4,   32*8,   4,      fj1_sizes,      /* Fixed part of FJ */
                    198:        32, 16, 3, 4,   32*16,  1024,   fj3_sizes,      /* fujitsu 330m */
                    199: };
                    200: 
                    201: unsigned char  up_offset[16] = {
                    202:     UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400,
                    203:     UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, 
                    204:     UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200,
                    205:     0, 0, 0, 0
                    206: };
                    207: 
                    208: /*
                    209:  * things from config
                    210:  */
                    211: extern int upcnt, sccnt;
                    212: extern struct ubaddr scaddr[];
                    213: extern struct subaddr upaddr[];
                    214: extern struct scctl scctl[];
                    215: extern struct updisk updisk[];
                    216: extern struct buf upbuf[];
                    217: 
                    218: /*
                    219:  * controller flags, scctl.flags
                    220:  */
                    221: 
                    222: #define        CACTIVE 01      /* xfer in progress */
                    223: #define        CWAITING 02     /* xfering and timer has ticked */
                    224: 
                    225: /*
                    226:  * unit flags, updisk.flags
                    227:  */
                    228: 
                    229: #define        UACTIVE 01      /* working on this xfer */
                    230: #define        URXFR   02      /* done with any seeking; ready to roll */
                    231: #define        UWOL    04      /* waiting for offline drive */
                    232: #define        UWAITOL 010     /* waiting and timer has ticked */
                    233: 
                    234: /*
                    235:  * device number
                    236:  * 0100 in the minor device is (temporarily?)
                    237:  * usurped to indicate bitmapped file systems
                    238:  * quietly ignore it for now
                    239:  * when things improve, change the UNIT mask to 037
                    240:  */
                    241: 
                    242: #define        UNIT(d) ((minor(d)>>3) & 027)
                    243: #define        PART(d) (minor(d) & 07)
                    244: 
                    245: /*
                    246:  * abuse of spare bits of struct buf
                    247:  */
                    248: #define        b_cylin b_resid         /* for disksort */
                    249: #define        b_ubm   av_back         /* this buffer's map */
                    250: 
                    251: int    upwstart, upwatch();            /* Have started guardian */
                    252: int    upwaitdry;
                    253: 
                    254: int upopen(), upstrategy(), upread(), upwrite(), upioctl();
                    255: 
                    256: struct cdevsw upcdev = cdinit(upopen, nulldev, upread, upwrite, upioctl);
                    257: 
                    258: struct bdevsw upbdev = bdinit(upopen, nulldev, upstrategy, 0);
                    259: 
                    260: upopen(dev, flag)
                    261: int dev, flag;
                    262: {
                    263:        register struct updisk *up;
                    264:        register struct upst *st;
                    265:        register int p;
                    266: 
                    267:        if (upuinit(UNIT(dev)) == 0) {
                    268:                u.u_error = ENXIO;
                    269:                return;
                    270:        }
                    271:        up = &updisk[UNIT(dev)];
                    272:        st = &upst[up->type];
                    273:        p = PART(dev);
                    274:        if ((up->pinit & (1<<p)) == 0) {
                    275:                up->nblocks[p] = st->sizes[p].nblocks;
                    276:                up->blkoff[p] = st->sizes[p].blkoff;
                    277:                if ((up->blkoff[p] % st->nspc) != 0) {
                    278:                        printf("up minor %d bad blkoff\n", minor(dev));
                    279:                        u.u_error = EINVAL;
                    280:                        return;
                    281:                }
                    282:                up->pinit |= (1<<p);
                    283:        }
                    284: }
                    285: 
                    286: upuinit(unit)
                    287: register int unit;
                    288: {
                    289:        register struct updevice *reg;
                    290:        register struct updisk *up;
                    291:        register struct subaddr *ua;
                    292: 
                    293:        if (unit < 0 || unit > upcnt)
                    294:                return (0);
                    295:        ua = &upaddr[unit];
                    296:        if (ua->ctl < 0)
                    297:                return (0);
                    298:        up = &updisk[unit];
                    299:        if (up->ctl)
                    300:                return (1);
                    301:        if (upcinit(ua->ctl) == 0)
                    302:                return (0);
                    303:        reg = scctl[ua->ctl].addr;
                    304:        if ((up->type = uputype(reg, ua->unit)) < 0) {
                    305:                printf("up%d absent or bad type\n", unit);
                    306:                return (0);
                    307:        }
                    308:        up->unit = ua->unit;
                    309:        up->ctl = &scctl[ua->ctl];
                    310:        up->ctl->drives[ua->unit] = up;
                    311:        return (1);
                    312: }
                    313:        
                    314: 
                    315: /*
                    316:  * determine drive type
                    317:  * very emulex dependent; should look at drive type register too.
                    318:  * perhaps there should be a way to change it?
                    319:  * this is called by updump too;
                    320:  * be prepared to run without memory management
                    321:  * unit is the hardware unit
                    322:  * return is an index into upst
                    323:  */
                    324: int
                    325: uputype(reg, unit)
                    326: register struct updevice *reg;
                    327: int unit;
                    328: {
                    329: 
                    330:        reg->upcs1 = 0;         /* conservative */
                    331:        reg->upcs2 = unit;
                    332:        if (reg->upcs2&UPCS2_NED) {
                    333:                reg->upcs1 = UP_DCLR|UP_GO;
                    334:                return (-1);
                    335:        }
                    336:        reg->uphr = UPHR_MAXTRAK;
                    337:        switch (reg->uphr) {
                    338:        default:
                    339:                reg->upcs1 = UP_DCLR|UP_GO;
                    340:                return (-1);
                    341:        case 9:
                    342:                return (unit >= 4 ? 3 : 1);             /* fujitsu hack */
                    343:        case 4:
                    344:                return (2);             /* CDC 76MB hack */
                    345:        case 7:
                    346:                return (3);             /* Fixed Fujitsu hack */
                    347:        case 15:
                    348:                return (4);             /* fuji 330m hack */
                    349:        case 19:
                    350:                return (0);             /* CDC 300 MB hack */
                    351:        }
                    352: }
                    353: 
                    354: upcinit(ctl)
                    355: int ctl;
                    356: {
                    357:        register struct scctl *sc;
                    358:        register struct updevice *reg;
                    359: 
                    360:        if (ctl < 0 || ctl >= sccnt)
                    361:                return (0);
                    362:        sc = &scctl[ctl];
                    363:        if (sc->addr)
                    364:                return (1);
                    365:        if ((reg = (struct updevice *)ubaddr(&scaddr[ctl])) == 0
                    366:        ||  ubbadaddr(scaddr[ctl].ubno, &reg->upcs1, sizeof(short))) {
                    367:                printf("sc%d absent\n", ctl);
                    368:                return (0);
                    369:        }
                    370:        reg->upcs2 = UPCS2_CLR;
                    371:        sc->addr = reg;
                    372:        sc->ubno = scaddr[ctl].ubno;
                    373:        if (upwstart == 0) {
                    374:                timeout(upwatch, (caddr_t)0, HZ);
                    375:                upwstart++;
                    376:        }
                    377:        return (1);
                    378: }
                    379:  
                    380: upstrategy(bp)
                    381:        register struct buf *bp;
                    382: {
                    383:        register struct updisk *up;
                    384:        register struct upst *st;
                    385:        register int unit;
                    386:        register int part;
                    387:        long sz;
                    388:        int s;
                    389: 
                    390:        sz = (bp->b_bcount+SECTOR-1)/SECTOR;
                    391:        unit = UNIT(bp->b_dev);
                    392:        up = &updisk[unit];
                    393:        if (up->ctl == 0) {
                    394:                bp->b_flags |= B_ERROR;
                    395:                iodone(bp);
                    396:                return;
                    397:        }
                    398:        st = &upst[up->type];
                    399:        part = PART(bp->b_dev);
                    400:        if (bp->b_blkno < 0 || bp->b_blkno+sz > up->nblocks[part]) {
                    401:                if (bp->b_blkno == up->nblocks[part])
                    402:                        bp->b_resid = bp->b_bcount;
                    403:                else {  /* partial read too hard for now */
                    404:                        bp->b_error = ENXIO;
                    405:                        bp->b_flags |= B_ERROR;
                    406:                }
                    407:                iodone(bp);
                    408:                return;
                    409:        }
                    410:        bp->b_cylin = (bp->b_blkno + up->blkoff[part])/st->nspc;
                    411:        bp->b_ubm = (struct buf *)ubmbuf(up->ctl->ubno, bp, USLP);
                    412:        s = spl6();
                    413:        disksort(&up->actf, &up->actl, bp);
                    414:        if ((up->flags & UACTIVE) == 0) {
                    415:                upustart(up);
                    416:                if (up->ctl->actf && (up->ctl->flags & CACTIVE) == 0)
                    417:                        upstart(up->ctl);
                    418:        }
                    419:        splx(s);
                    420: }
                    421: 
                    422: /*
                    423:  * unit start:
                    424:  * if there's a block for this drive, start seeking there
                    425:  *
                    426:  * up->upcs = UP_IE cancels a pending command in the SC21
                    427:  * why not up->cs |= UP_IE?
                    428:  */
                    429: upustart(up)
                    430: register struct updisk *up;
                    431: {
                    432:        register struct buf *bp;
                    433:        register struct updevice *reg;
                    434:        register struct scctl *sc;
                    435:        register struct upst *st;
                    436:        int sn, csn;
                    437:        int didie = 0;
                    438: 
                    439:        sc = up->ctl;
                    440:        if ((bp = up->actf) == NULL)
                    441:                return (0);
                    442: #ifndef NOUPSEEK
                    443:        if (sc->flags & CACTIVE) {      /* can't start seek till xfer done */
                    444:                sc->softas |= 1<<up->unit;
                    445:                return (0);
                    446:        }
                    447: #endif
                    448:        reg = sc->addr;
                    449:        reg->upcs2 = up->unit;
                    450:        if ((reg->upds & UPDS_VV) == 0) {
                    451:                reg->upcs1 = UP_IE|UP_DCLR|UP_GO;
                    452:                reg->upcs1 = UP_IE|UP_PRESET|UP_GO;
                    453:                reg->upof = UPOF_FMT22;
                    454:                didie = 1;
                    455:        }
                    456:        if ((reg->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL)) {
                    457:                up->flags |= UWOL;
                    458:                return (didie);
                    459:        }
                    460:        if ((up->flags & UACTIVE) == 0) {       /* start seek if didn't already */
                    461:                up->flags |= UACTIVE;
                    462: #ifndef NOUPSEEK
                    463:                st = &upst[up->type];
                    464:                sn = bp->b_blkno%st->nspc;
                    465:                sn = (sn + st->nsect - st->sdist) % st->nsect;  /* sector to seek to */
                    466:                csn = sn - (reg->upla>>6);
                    467:                if (csn < 0)
                    468:                        csn += st->nsect;
                    469:                if (bp->b_cylin != reg->updc    /* seek if off cylinder */
                    470:                ||  csn > st->rdist) {          /* or not close enough */
                    471:                        reg->updc = bp->b_cylin;
                    472:                        reg->upda = sn;
                    473:                        reg->upcs1 = UP_IE|UP_SEARCH|UP_GO;
                    474:                        return (1);
                    475:                }
                    476: #endif
                    477:        }
                    478:        if ((up->flags & URXFR) == 0) { /* seek done, put on ctl queue */
                    479:                up->next = NULL;
                    480:                if (sc->actf == NULL)
                    481:                        sc->actf = up;
                    482:                else
                    483:                        sc->actl->next = up;
                    484:                sc->actl = up;
                    485:                up->flags |= URXFR;
                    486:        }
                    487:        return (didie);
                    488: }
                    489: 
                    490: /*
                    491:  * Start up a transfer on a drive.
                    492:  */
                    493: upstart(sc)
                    494: register struct scctl *sc;
                    495: {
                    496:        register struct buf *bp;
                    497:        register struct updisk *up;
                    498:        register struct updevice *reg;
                    499:        register struct upst *st;
                    500:        register c;
                    501:        uaddr_t uad;
                    502:        int sn, tn;
                    503: 
                    504: loop:
                    505:        if ((up = sc->actf) == NULL)
                    506:                return (0);
                    507:        if ((bp = up->actf) == NULL) {
                    508:                sc->actf = up->next;
                    509:                goto loop;
                    510:        }
                    511:        sc->flags |= CACTIVE;
                    512:        st = &upst[up->type];
                    513:        sn = bp->b_blkno%st->nspc;
                    514:        tn = sn/st->nsect;
                    515:        sn %= st->nsect;
                    516:        reg = sc->addr;
                    517:        reg->upcs2 = up->unit;
                    518:        c = 0;
                    519:        while ((reg->upds&UPDS_DRY) == 0) {
                    520:                if (++c > 512)
                    521:                        break;
                    522:                upwaitdry++;
                    523:        }
                    524:        if ((reg->upds & UPDS_DREADY) != UPDS_DREADY) {
                    525:                printf("up%d: not ready", UNIT(bp->b_dev));
                    526:                if ((reg->upds & UPDS_DREADY) != UPDS_DREADY) {
                    527:                        printf("\n");
                    528:                        sc->flags &=~ (CACTIVE|CWAITING);
                    529:                        sc->errcnt = 0;
                    530:                        up->actf = bp->av_forw;
                    531:                        up->flags &=~ (UACTIVE|URXFR);
                    532:                        bp->b_flags |= B_ERROR;
                    533:                        iodone(bp);
                    534:                        goto loop;
                    535:                }
                    536:                printf(" (flakey)\n");  /* inscrutable */
                    537:        }
                    538:        reg->updc = bp->b_cylin;
                    539:        reg->upda = (tn << 8) + sn;
                    540:        reg->upwc = -bp->b_bcount / sizeof(short);
                    541:        if (bp->b_flags & B_READ)
                    542:                c = UP_IE|UP_RCOM|UP_GO;
                    543:        else
                    544:                c = UP_IE|UP_WCOM|UP_GO;
                    545:        bp->b_ubm = (struct buf *)ubinspath(ubmapath(sc->ubno), (ubm_t)bp->b_ubm);
                    546:        uad = ubadbuf(sc->ubno, bp, (ubm_t)bp->b_ubm);
                    547:        reg->upba = uad;
                    548:        reg->upcs1 = c|((uad>>8)&0x300);
                    549:        return (1);
                    550: }
                    551: 
                    552: /*
                    553:  * Handle a disk interrupt.
                    554:  */
                    555: sc0int(ctl)
                    556: int ctl;
                    557: {
                    558:        register struct updevice *reg;
                    559:        register struct scctl *sc;
                    560:        register struct updisk *up;
                    561:        register struct buf *bp;
                    562:        register int unit, i, as;
                    563:        int needie;
                    564: 
                    565:        if (ctl < 0 || ctl >= sccnt) {
                    566:                printf("sc%d bad intr\n");
                    567:                return;
                    568:        }
                    569:        sc = &scctl[ctl];
                    570:        if ((reg = sc->addr) == 0) {
                    571:                printf("sc%d: stray intr\n");
                    572:                return;
                    573:        }
                    574:        needie = 1;
                    575:        as = (reg->upas & 0377) | sc->softas;
                    576:        sc->softas = 0;
                    577:        if ((sc->flags & CACTIVE) == 0) {       /* must be a seek */
                    578:                if (reg->upcs1 & UP_TRE)
                    579:                        reg->upcs1 = UP_TRE;
                    580:                goto doattn;
                    581:        }
                    582:        up = sc->actf;
                    583:        bp = up->actf;
                    584:        reg->upcs2 = up->unit;
                    585:        if ((reg->upds&UPDS_ERR) || (reg->upcs1&UP_TRE)) {
                    586:                i = 0;
                    587:                while ((reg->upds & UPDS_DRY) == 0) {
                    588:                        if (++i > 512)
                    589:                                break;
                    590:                        upwaitdry++;
                    591:                }
                    592:                if (reg->uper1&UPER1_WLE) {
                    593:                        printf("up%d: write locked\n", UNIT(bp->b_dev));
                    594:                        bp->b_flags |= B_ERROR;
                    595:                } else if (++sc->errcnt > 27) {
                    596:                        harderr(bp, "up");
                    597:                        printf("cs2=%o er1=%o er2=%o\n",
                    598:                            reg->upcs2&0177777, reg->uper1&0177777, reg->uper2&0177777);
                    599:                        bp->b_flags |= B_ERROR;
                    600:                } else {
                    601:                        /*
                    602:                         * soft ecc, try to correct
                    603:                         */
                    604:                        sc->flags &=~ (CACTIVE|CWAITING);        /* force retry */
                    605:                        if ((reg->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK)
                    606:                                if (upecc(up))
                    607:                                        return; /* probably wrong */
                    608:                }
                    609:                /*
                    610:                 * `hard' error. clear and try again
                    611:                 */
                    612:                reg->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO;
                    613:                needie = 0;
                    614:                if ((sc->errcnt&07) == 4 && (sc->flags & CACTIVE) == 0) {
                    615:                        reg->upcs1 = UP_RECAL|UP_IE|UP_GO;
                    616:                        sc->recal = 0;
                    617:                        goto nextrecal;
                    618:                }
                    619:        }
                    620:        /*
                    621:         * Advance recalibration finite state machine
                    622:         * if recalibrate in progress, through
                    623:         *      RECAL
                    624:         *      SEEK
                    625:         *      OFFSET (optional)
                    626:         *      RETRY
                    627:         */
                    628:        switch (sc->recal) {
                    629:        case 1:
                    630:                reg->updc = bp->b_cylin;
                    631:                reg->upcs1 = UP_SEEK|UP_IE|UP_GO;
                    632:                goto nextrecal;
                    633:        case 2:
                    634:                if (sc->errcnt < 16 || (bp->b_flags&B_READ) == 0)
                    635:                        goto donerecal;
                    636:                reg->upof = up_offset[sc->errcnt & 017] | UPOF_FMT22;
                    637:                reg->upcs1 = UP_IE|UP_OFFSET|UP_GO;
                    638:        nextrecal:
                    639:                sc->recal++;
                    640:                sc->flags |= CACTIVE;
                    641:                return;
                    642: 
                    643:        donerecal:
                    644:        case 3:
                    645:                sc->recal = 0;
                    646:                sc->flags &=~ CACTIVE;
                    647:                break;
                    648:        }
                    649:        if (sc->flags & CACTIVE) {      /* `active' means we're done */
                    650:                if (sc->errcnt >= 16) {
                    651:                        reg->upof = UPOF_FMT22;
                    652:                        reg->upcs1 = UP_RTC|UP_GO|UP_IE;
                    653:                        while (reg->upds & UPDS_PIP)
                    654:                                DELAY(25);
                    655:                        needie = 0;
                    656:                }
                    657:                sc->flags &=~ (CACTIVE|CWAITING);
                    658:                sc->errcnt = 0;
                    659:                sc->actf = up->next;
                    660:                up->flags &=~ (UACTIVE|URXFR);
                    661:                up->actf = bp->av_forw;
                    662:                bp->b_resid = (-reg->upwc * sizeof(short));
                    663:                ubmfree(sc->ubno, (ubm_t)bp->b_ubm);
                    664:                iodone(bp);
                    665:                if (up->actf)
                    666:                        if (upustart(up))
                    667:                                needie = 0;
                    668:        }
                    669:        as |= reg->upas;
                    670:        as &= ~(1<<up->unit);
                    671: doattn:
                    672:        /*
                    673:         * Process other units which need attention.
                    674:         */
                    675:        for (unit = 0, i = 1; unit < NSCUP && as; i <<= 1, unit++) {
                    676:                if ((as & i) == 0)
                    677:                        continue;
                    678:                as &= ~i;
                    679:                reg->upas = i;
                    680:                if ((up = sc->drives[unit]) != NULL && upustart(up))
                    681:                        needie = 0;
                    682:        }
                    683:        if (sc->actf && (sc->flags & CACTIVE) == 0)
                    684:                if (upstart(sc))
                    685:                        needie = 0;
                    686:        if (needie)
                    687:                reg->upcs1 = UP_IE;     /* why bother? */
                    688: }
                    689: 
                    690: upread(dev)
                    691:        dev_t dev;
                    692: {
                    693:        physio(upstrategy, &upbuf[UNIT(dev)], dev, B_READ, minphys);
                    694: }
                    695: 
                    696: upwrite(dev)
                    697:        dev_t dev;
                    698: {
                    699:        physio(upstrategy, &upbuf[UNIT(dev)], dev, B_WRITE, minphys);
                    700: }
                    701: 
                    702: upioctl(dev, cmd, addr, flag)
                    703: dev_t dev;
                    704: int cmd;
                    705: caddr_t addr;
                    706: int flag;
                    707: {
                    708:        register struct updisk *up;
                    709:        long parts[2];
                    710: 
                    711:        up = &updisk[UNIT(dev)];
                    712:        switch (cmd) {
                    713:        case DIOSSIZ:
                    714:                if ((flag & FWRITE) == 0) {
                    715:                        u.u_error = EBADF;
                    716:                        return;
                    717:                }
                    718:                if (copyin(addr, (caddr_t)parts, sizeof(parts)) < 0) {
                    719:                        u.u_error = EFAULT;
                    720:                        return;
                    721:                }
                    722:                /*
                    723:                 * why test this?  see comments above upstrategy
                    724:                 */
                    725:                if ((parts[0] % upst[up->type].nspc) != 0) {
                    726:                        u.u_error = EINVAL;
                    727:                        return;
                    728:                }
                    729:                up->blkoff[PART(dev)] = parts[0];
                    730:                up->nblocks[PART(dev)] = parts[1];
                    731:                return;
                    732: 
                    733:        case DIOGSIZ:
                    734:                parts[0] = up->blkoff[PART(dev)];
                    735:                parts[1] = up->nblocks[PART(dev)];
                    736:                if (copyout((caddr_t)parts, addr, sizeof(parts)) < 0)
                    737:                        u.u_error = EFAULT;
                    738:                return;
                    739: 
                    740:        default:
                    741:                u.u_error = ENOTTY;
                    742:                return;
                    743:        }
                    744: }
                    745: 
                    746: /*
                    747:  * correct an ECC error and restart the transfer
                    748:  * the error is (upec1-1) bits into the current sector;
                    749:  * at that point, the bits set in upec2 are wrong.
                    750:  *
                    751:  * should be able just to set the GO bit and proceed,
                    752:  * but emulex insists we do DCLR first, or so the book says,
                    753:  * because DCK sets ERR in upds
                    754:  */
                    755: upecc(up)
                    756: register struct updisk *up;
                    757: {
                    758:        register struct updevice *reg;
                    759:        register struct scctl *sc;
                    760:        register struct buf *bp;
                    761:        register int i;
                    762:        int nxf;
                    763:        unsigned int mask;
                    764:        uaddr_t uad, lastua;
                    765:        int xc, xa;
                    766: 
                    767:        if ((bp = up->actf) == NULL || (sc = up->ctl) == NULL)
                    768:                panic("upecc");
                    769:        reg = sc->addr;
                    770:        ubmflush(sc->ubno, ubmpath((ubm_t)bp->b_ubm));
                    771:        lastua = reg->upba + ((reg->upcs1&0x300)<<8);
                    772:        nxf = bp->b_bcount + (reg->upwc * sizeof(short));
                    773:        i = reg->upec1 - 1;             /* -1 makes 0 origin */
                    774:        uad = lastua - (nxf > SECTOR ? SECTOR : nxf) + ((i&~07)>>3);
                    775:        mask = reg->upec2;
                    776:        mask <<= i&07;
                    777:        for (; uad < lastua && mask; mask >>= 8, uad++)
                    778:                ubputc(sc->ubno, uad, ubgetc(sc->ubno, uad)^mask);
                    779:        printf("up%d%o: soft ecc sec %ld\n", UNIT(bp->b_dev), PART(bp->b_dev),
                    780:                bp->b_blkno + nxf/SECTOR - 1);
                    781:        sc->flags |= CACTIVE;   /* either complete or continuing */
                    782:        if (reg->upwc == 0)
                    783:                return (0);
                    784: #ifdef notdef
                    785:        reg->uper1 = 0;
                    786:        reg->upcs1 |= UP_GO;
                    787: #else          /* clear wretched emulex error */
                    788:        xc = reg->updc;
                    789:        xa = reg->upda;
                    790:        /* ba, wc undisturbed by DCLR */
                    791:        reg->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO;
                    792:        reg->updc = xc;
                    793:        reg->upda = xa;
                    794:        reg->upba = lastua;
                    795:        i = (lastua >> 8) & 0x300;
                    796:        i |= UP_IE|UP_GO|UP_RCOM;
                    797:        reg->upcs1 = i;
                    798: #endif
                    799:        return (1);
                    800: }
                    801: 
                    802: /*
                    803:  * check for offline drives and hung controllers
                    804:  */
                    805: 
                    806: upwatch()
                    807: {
                    808:        register struct scctl *sc;
                    809:        register struct updisk *up;
                    810:        register struct updevice *reg;
                    811:        register struct buf *bp;
                    812:        register int ounit;
                    813:        register int s;
                    814: 
                    815:        s = spl6();
                    816:        timeout(upwatch, (caddr_t)0, 15*HZ);
                    817:        for (up = &updisk[upcnt-1]; up >= updisk; up--) {
                    818:                if ((up->flags & UWOL) == 0)
                    819:                        continue;
                    820:                reg = up->ctl->addr;
                    821:                ounit = reg->upcs2 & UPCS2_SEL;
                    822:                reg->upcs2 = up->unit;
                    823:                if ((reg->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL)) {
                    824:                        if ((up->flags & UWAITOL) == 0) {
                    825:                                up->flags |= UWAITOL;
                    826:                                reg->upcs2 = ounit;
                    827:                                continue;
                    828:                        }
                    829:                        printf("up%d offline\n", up - updisk);
                    830:                        while ((bp = up->actf) != NULL) {
                    831:                                bp->b_flags |= B_ERROR;
                    832:                                up->actf = bp->av_forw;
                    833:                                ubmfree(up->ctl->ubno, (ubm_t)bp->b_ubm);
                    834:                                iodone(bp);
                    835:                        }
                    836:                }
                    837:                up->flags &=~ (UWAITOL|UWOL);
                    838:                upustart(up);
                    839:                reg->upcs2 = ounit;
                    840:        }
                    841:        for (sc = &scctl[sccnt-1]; sc >= scctl; sc--) {
                    842:                if (sc->flags & CACTIVE) {
                    843:                        if ((sc->flags & CWAITING) == 0)
                    844:                                sc->flags |= CWAITING;
                    845:                        else {
                    846:                                sc->addr->upcs2 = UPCS2_CLR;
                    847:                                printf("sc%d hung, kicked\n", sc - scctl);
                    848:                                sc->flags &=~ (CWAITING|CACTIVE);
                    849:                        }
                    850:                }
                    851:                if (sc->actf && (sc->flags & CACTIVE) == 0)
                    852:                        upstart(sc);
                    853:        }
                    854:        splx(s);
                    855: }

unix.superglobalmegacorp.com

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