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

unix.superglobalmegacorp.com

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