Annotation of 41BSD/sys/dev/up.c, revision 1.1.1.1

1.1       root        1: /*     up.c    4.3     11/13/80        */
                      2: 
                      3: #include "../conf/up.h"
                      4: #if NUP > 0
                      5: /*
                      6:  * UNIBUS disk driver with overlapped seeks and ECC recovery.
                      7:  */
                      8: #define        DELAY(N)                { register int d; d = N; while (--d > 0); }
                      9: 
                     10: #include "../h/param.h"
                     11: #include "../h/systm.h"
                     12: #include "../h/dk.h"
                     13: #include "../h/buf.h"
                     14: #include "../h/conf.h"
                     15: #include "../h/dir.h"
                     16: #include "../h/user.h"
                     17: #include "../h/map.h"
                     18: #include "../h/pte.h"
                     19: #include "../h/mba.h"
                     20: #include "../h/mtpr.h"
                     21: #include "../h/uba.h"
                     22: #include "../h/vm.h"
                     23: 
                     24: #define        ushort  unsigned short
                     25: 
                     26: struct device
                     27: {
                     28:        ushort  upcs1;          /* control and status register 1 */
                     29:        short   upwc;           /* word count register */
                     30:        ushort  upba;           /* UNIBUS address register */
                     31:        ushort  upda;           /* desired address register */
                     32:        ushort  upcs2;          /* control and status register 2 */
                     33:        ushort  upds;           /* drive Status */
                     34:        ushort  uper1;          /* error register 1 */
                     35:        ushort  upas;           /* attention summary */
                     36:        ushort  upla;           /* look ahead */
                     37:        ushort  updb;           /* data buffer */
                     38:        ushort  upmr;           /* maintenance */ 
                     39:        ushort  updt;           /* drive type */
                     40:        ushort  upsn;           /* serial number */
                     41:        ushort  upof;           /* offset register */
                     42:        ushort  updc;           /* desired cylinder address register */
                     43:        ushort  upcc;           /* current cylinder */
                     44:        ushort  uper2;          /* error register 2 */
                     45:        ushort  uper3;          /* error register 3 */
                     46:        ushort  upec1;          /* burst error bit position */
                     47:        ushort  upec2;          /* burst error bit pattern */
                     48: };
                     49: 
                     50: /*
                     51:  * Software extension to the upas register, so we can
                     52:  * postpone starting SEARCH commands until the controller
                     53:  * is not transferring.
                     54:  */
                     55: int    upsoftas;
                     56: 
                     57: /*
                     58:  * If upseek then we don't issue SEARCH commands but rather just
                     59:  * settle for a SEEK to the correct cylinder.
                     60:  */
                     61: int    upseek;
                     62: 
                     63: #define        NSECT   32
                     64: #define        NTRAC   19
                     65: 
                     66: /*
                     67:  * Constants controlling on-cylinder SEARCH usage.
                     68:  *
                     69:  *     upSDIST/2 msec          time needed to start transfer
                     70:  *     upRDIST/2 msec          tolerable rotational latency when on-cylinder
                     71:  *
                     72:  * If we are no closer than upSDIST sectors and no further than upSDIST+upRDIST
                     73:  * and in the driver then we take it as it is.  Otherwise we do a SEARCH
                     74:  * requesting an interrupt upSDIST sectors in advance.
                     75:  */
                     76: #define        _upSDIST        2               /* 1.0 msec */
                     77: #define        _upRDIST        4               /* 2.0 msec */
                     78: 
                     79: int    upSDIST = _upSDIST;
                     80: int    upRDIST = _upRDIST;
                     81: 
                     82: /*
                     83:  * To fill a 300M drive:
                     84:  *     A is designed to be used as a root.
                     85:  *     B is suitable for a swap area.
                     86:  *     H is the primary storage area.
                     87:  * On systems with RP06'es, we normally use only 291346 blocks of the H
                     88:  * area, and use DEF or G to cover the rest of the drive.  The C system
                     89:  * covers the whole drive and can be used for pack-pack copying.
                     90:  *
                     91:  * Note: sizes here are for AMPEX drives with 815 cylinders.
                     92:  * CDC drives can make the F,G, and H areas larger as they have 823 cylinders.
                     93:  */
                     94: struct size
                     95: {
                     96:        daddr_t nblocks;
                     97:        int     cyloff;
                     98: } up_sizes[8] = {
                     99:        15884,  0,              /* A=cyl 0 thru 26 */
                    100:        33440,  27,             /* B=cyl 27 thru 81 */
                    101:        495520, 0,              /* C=cyl 0 thru 814 */
                    102:        15884,  562,            /* D=cyl 562 thru 588 */
                    103:        55936,  589,            /* E=cyl 589 thru 680 */
                    104:        81472,  681,            /* F=cyl 681 thru 814 */
                    105:        153824, 562,            /* G=cyl 562 thru 814 */
                    106:        291346, 82,             /* H=cyl 82 thru 561 */
                    107: };
                    108: 
                    109: /*
                    110:  * The following defines are used in offset positioning
                    111:  * when trying to recover disk errors, with the constants being
                    112:  * +/- microinches.  Note that header compare inhibit (HCI) is not
                    113:  * tried (this makes sense only during read, in any case.)
                    114:  *
                    115:  * NB: Not all drives/controllers emulate all of these.
                    116:  */
                    117: #define        P400    020
                    118: #define        M400    0220
                    119: #define        P800    040
                    120: #define        M800    0240
                    121: #define        P1200   060
                    122: #define        M1200   0260
                    123: #define        HCI     020000
                    124: 
                    125: int    up_offset[16] =
                    126: {
                    127:        P400, M400, P400, M400,
                    128:        P800, M800, P800, M800,
                    129:        P1200, M1200, P1200, M1200,
                    130:        0, 0, 0, 0,
                    131: };
                    132: 
                    133: /*
                    134:  * Each drive has a table uputab[i].  On this table are sorted the
                    135:  * pending requests implementing an elevator algorithm (see dsort.c.)
                    136:  * In the upustart() routine, each drive is independently advanced
                    137:  * until it is on the desired cylinder for the next transfer and near
                    138:  * the desired sector.  The drive is then chained onto the uptab
                    139:  * table, and the transfer is initiated by the upstart() routine.
                    140:  * When the transfer is completed the driver reinvokes the upustart()
                    141:  * routine to set up the next transfer.
                    142:  */
                    143: struct buf     uptab;
                    144: struct buf     uputab[NUP];
                    145: 
                    146: struct buf     rupbuf;                 /* Buffer for raw i/o */
                    147: 
                    148: /* Drive commands, placed in upcs1 */
                    149: #define        GO      01              /* Go bit, set in all commands */
                    150: #define        PRESET  020             /* Preset drive at init or after errors */
                    151: #define        OFFSET  014             /* Offset heads to try to recover error */
                    152: #define        RTC     016             /* Return to center-line after OFFSET */
                    153: #define        SEARCH  030             /* Search for cylinder+sector */
                    154: #define        SEEK    04              /* Seek to cylinder */
                    155: #define        RECAL   06              /* Recalibrate, needed after seek error */
                    156: #define        DCLR    010             /* Drive clear, after error */
                    157: #define        WCOM    060             /* Write */
                    158: #define        RCOM    070             /* Read */
                    159: 
                    160: /* Other bits of upcs1 */
                    161: #define        IE      0100            /* Controller wide interrupt enable */
                    162: #define        TRE     040000          /* Transfer error */
                    163: #define        RDY     0200            /* Transfer terminated */
                    164: 
                    165: /* Drive status bits of upds */
                    166: #define        PIP     020000          /* Positioning in progress */
                    167: #define        ERR     040000          /* Error has occurred, DCLR necessary */
                    168: #define        VV      0100            /* Volume is valid, set by PRESET */
                    169: #define        DPR     0400            /* Drive has been preset */
                    170: #define        MOL     010000          /* Drive is online, heads loaded, etc */
                    171: #define        DRY     0200            /* Drive ready */
                    172: 
                    173: /* Bits of upcs2 */
                    174: #define        CLR     040             /* Controller clear */
                    175: /* Bits of uper1 */
                    176: #define        DCK     0100000         /* Ecc error occurred */
                    177: #define        ECH     0100            /* Ecc error was unrecoverable */
                    178: #define        WLE     04000           /* Attempt to write read-only drive */
                    179: 
                    180: /* Bits of upof; the offset bits above are also in this register */
                    181: #define        FMT22   010000          /* 16 bits/word, must be always set */
                    182: 
                    183: #define        b_cylin b_resid
                    184: 
                    185: int    up_ubinfo;              /* Information about UBA usage saved here */
                    186: 
                    187: int    up_wticks;              /* Ticks waiting for interrupt */
                    188: int    upwstart;               /* Have started guardian */
                    189: int    upwatch();
                    190: 
                    191: #ifdef INTRLVE
                    192: daddr_t dkblock();
                    193: #endif
                    194:  
                    195: /*
                    196:  * Queue an i/o request for a drive, checking first that it is in range.
                    197:  *
                    198:  * A unit start is issued if the drive is inactive, causing
                    199:  * a SEARCH for the correct cylinder/sector.  If the drive is
                    200:  * already nearly on the money and the controller is not transferring
                    201:  * we kick it to start the transfer.
                    202:  */
                    203: upstrategy(bp)
                    204: register struct buf *bp;
                    205: {
                    206:        register struct buf *dp;
                    207:        register unit, xunit;
                    208:        long sz, bn;
                    209: 
                    210:        if (upwstart == 0) {
                    211:                timeout(upwatch, (caddr_t)0, HZ);
                    212:                upwstart++;
                    213:        }
                    214:        xunit = minor(bp->b_dev) & 077;
                    215:        sz = bp->b_bcount;
                    216:        sz = (sz+511) >> 9;             /* transfer size in 512 byte sectors */
                    217:        unit = dkunit(bp);
                    218:        if (unit >= NUP ||
                    219:            bp->b_blkno < 0 ||
                    220:            (bn = dkblock(bp))+sz > up_sizes[xunit&07].nblocks) {
                    221:                bp->b_flags |= B_ERROR;
                    222:                iodone(bp);
                    223:                return;
                    224:        }
                    225:        if (DK_N+unit <= DK_NMAX)
                    226:                dk_mspw[DK_N+unit] = .0000020345;
                    227:        bp->b_cylin = bn/(NSECT*NTRAC) + up_sizes[xunit&07].cyloff;
                    228:        dp = &uputab[unit];
                    229:        (void) spl5();
                    230:        disksort(dp, bp);
                    231:        if (dp->b_active == 0) {
                    232:                (void) upustart(unit);
                    233:                if (uptab.b_actf && uptab.b_active == 0)
                    234:                        (void) upstart();
                    235:        }
                    236:        (void) spl0();
                    237: }
                    238: 
                    239: /*
                    240:  * Start activity on specified drive; called when drive is inactive
                    241:  * and new transfer request arrives and also when upas indicates that
                    242:  * a SEARCH command is complete.
                    243:  */
                    244: upustart(unit)
                    245: register unit;
                    246: {
                    247:        register struct buf *bp, *dp;
                    248:        register struct device *upaddr = UPADDR;
                    249:        daddr_t bn;
                    250:        int sn, cn, csn;
                    251:        int didie = 0;
                    252: 
                    253:        /*
                    254:         * Other drivers tend to say something like
                    255:         *      upaddr->upcs1 = IE;
                    256:         *      upaddr->upas = 1<<unit;
                    257:         * here, but some controllers will cancel a command
                    258:         * happens to be sitting in the cs1 if you clear the go
                    259:         * bit by storing there (so the first is not safe).
                    260:         *
                    261:         * Thus we keep careful track of when we re-enable IE
                    262:         * after an interrupt and do it only if we didn't issue
                    263:         * a command which re-enabled it as a matter of course.
                    264:         * We clear bits in upas in the interrupt routine, when
                    265:         * no transfers are active.
                    266:         */
                    267:        if (unit >= NUP)
                    268:                goto out;
                    269:        if (unit+DK_N <= DK_NMAX)
                    270:                dk_busy &= ~(1<<(unit+DK_N));
                    271:        dp = &uputab[unit];
                    272:        if ((bp = dp->b_actf) == NULL)
                    273:                goto out;
                    274:        /*
                    275:         * Most controllers don't start SEARCH commands when transfers are
                    276:         * in progress.  In fact, some tend to get confused when given
                    277:         * SEARCH'es during transfers, generating interrupts with neither
                    278:         * RDY nor a bit in the upas register.  Thus we defer
                    279:         * until an interrupt when a transfer is pending.
                    280:         */
                    281:        if (uptab.b_active) {
                    282:                upsoftas |= 1<<unit;
                    283:                return (0);
                    284:        }
                    285:        if (dp->b_active)
                    286:                goto done;
                    287:        dp->b_active = 1;
                    288:        if ((upaddr->upcs2 & 07) != unit)
                    289:                upaddr->upcs2 = unit;
                    290:        /*
                    291:         * If we have changed packs or just initialized,
                    292:         * then the volume will not be valid; if so, clear
                    293:         * the drive, preset it and put in 16bit/word mode.
                    294:         */
                    295:        if ((upaddr->upds & VV) == 0) {
                    296:                upaddr->upcs1 = IE|DCLR|GO;
                    297:                upaddr->upcs1 = IE|PRESET|GO;
                    298:                upaddr->upof = FMT22;
                    299:                didie = 1;
                    300:        }
                    301:        if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL))
                    302:                goto done;
                    303:        /*
                    304:         * Do enough of the disk address decoding to determine
                    305:         * which cylinder and sector the request is on.
                    306:         * If we are on the correct cylinder and the desired sector
                    307:         * lies between upSDIST and upSDIST+upRDIST sectors ahead of us, then
                    308:         * we don't bother to SEARCH but just begin the transfer asap.
                    309:         * Otherwise ask for a interrupt upSDIST sectors ahead.
                    310:         */
                    311:        bn = dkblock(bp);
                    312:        cn = bp->b_cylin;
                    313:        sn = bn%(NSECT*NTRAC);
                    314:        sn = (sn+NSECT-upSDIST)%NSECT;
                    315: 
                    316:        if (cn - upaddr->updc)
                    317:                goto search;            /* Not on-cylinder */
                    318:        else if (upseek)
                    319:                goto done;              /* Ok just to be on-cylinder */
                    320:        csn = (upaddr->upla>>6) - sn - 1;
                    321:        if (csn < 0)
                    322:                csn += NSECT;
                    323:        if (csn > NSECT-upRDIST)
                    324:                goto done;
                    325: 
                    326: search:
                    327:        upaddr->updc = cn;
                    328:        if (upseek)
                    329:                upaddr->upcs1 = IE|SEEK|GO;
                    330:        else {
                    331:                upaddr->upda = sn;
                    332:                upaddr->upcs1 = IE|SEARCH|GO;
                    333:        }
                    334:        didie = 1;
                    335:        /*
                    336:         * Mark this unit busy.
                    337:         */
                    338:        unit += DK_N;
                    339:        if (unit <= DK_NMAX) {
                    340:                dk_busy |= 1<<unit;
                    341:                dk_seek[unit]++;
                    342:        }
                    343:        goto out;
                    344: 
                    345: done:
                    346:        /*
                    347:         * This unit is ready to go so
                    348:         * link it onto the chain of ready disks.
                    349:         */
                    350:        dp->b_forw = NULL;
                    351:        if (uptab.b_actf == NULL)
                    352:                uptab.b_actf = dp;
                    353:        else
                    354:                uptab.b_actl->b_forw = dp;
                    355:        uptab.b_actl = dp;
                    356: 
                    357: out:
                    358:        return (didie);
                    359: }
                    360: 
                    361: /*
                    362:  * Start a transfer; call from top level at spl5() or on interrupt.
                    363:  */
                    364: upstart()
                    365: {
                    366:        register struct buf *bp, *dp;
                    367:        register unit;
                    368:        register struct device *upaddr;
                    369:        daddr_t bn;
                    370:        int dn, sn, tn, cn, cmd;
                    371: 
                    372: loop:
                    373:        /*
                    374:         * Pick a drive off the queue of ready drives, and
                    375:         * perform the first transfer on its queue.
                    376:         *
                    377:         * Looping here is completely for the sake of drives which
                    378:         * are not present and on-line, for which we completely clear the
                    379:         * request queue.
                    380:         */
                    381:        if ((dp = uptab.b_actf) == NULL)
                    382:                return (0);
                    383:        if ((bp = dp->b_actf) == NULL) {
                    384:                uptab.b_actf = dp->b_forw;
                    385:                goto loop;
                    386:        }
                    387:        /*
                    388:         * Mark the controller busy, and multi-part disk address.
                    389:         * Select the unit on which the i/o is to take place.
                    390:         */
                    391:        uptab.b_active++;
                    392:        unit = minor(bp->b_dev) & 077;
                    393:        dn = dkunit(bp);
                    394:        bn = dkblock(bp);
                    395:        cn = up_sizes[unit&07].cyloff;
                    396:        cn += bn/(NSECT*NTRAC);
                    397:        sn = bn%(NSECT*NTRAC);
                    398:        tn = sn/NSECT;
                    399:        sn %= NSECT;
                    400:        upaddr = UPADDR;
                    401:        if ((upaddr->upcs2 & 07) != dn)
                    402:                upaddr->upcs2 = dn;
                    403:        up_ubinfo = ubasetup(bp, 1);
                    404:        /*
                    405:         * If drive is not present and on-line, then
                    406:         * get rid of this with an error and loop to get
                    407:         * rid of the rest of its queued requests.
                    408:         * (Then on to any other ready drives.)
                    409:         */
                    410:        if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) {
                    411:                printf("!DPR || !MOL, unit %d, ds %o", dn, upaddr->upds);
                    412:                if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) {
                    413:                        printf("-- hard\n");
                    414:                        uptab.b_active = 0;
                    415:                        uptab.b_errcnt = 0;
                    416:                        dp->b_actf = bp->av_forw;
                    417:                        dp->b_active = 0;
                    418:                        bp->b_flags |= B_ERROR;
                    419:                        iodone(bp);
                    420:                        /* A funny place to do this ... */
                    421:                        ubafree(up_ubinfo), up_ubinfo = 0;
                    422:                        goto loop;
                    423:                }
                    424:                printf("-- came back\n");
                    425:        }
                    426:        /*
                    427:         * If this is a retry, then with the 16'th retry we
                    428:         * begin to try offsetting the heads to recover the data.
                    429:         */
                    430:        if (uptab.b_errcnt >= 16 && (bp->b_flags&B_WRITE) == 0) {
                    431:                upaddr->upof = up_offset[uptab.b_errcnt & 017] | FMT22;
                    432:                upaddr->upcs1 = IE|OFFSET|GO;
                    433:                while (upaddr->upds & PIP)
                    434:                        DELAY(25);
                    435:        }
                    436:        /*
                    437:         * Now set up the transfer, retrieving the high
                    438:         * 2 bits of the UNIBUS address from the information
                    439:         * returned by ubasetup() for the cs1 register bits 8 and 9.
                    440:         */
                    441:        upaddr->updc = cn;
                    442:        upaddr->upda = (tn << 8) + sn;
                    443:        upaddr->upba = up_ubinfo;
                    444:        upaddr->upwc = -bp->b_bcount / sizeof (short);
                    445:        cmd = (up_ubinfo >> 8) & 0x300;
                    446:        if (bp->b_flags & B_READ)
                    447:                cmd |= IE|RCOM|GO;
                    448:        else
                    449:                cmd |= IE|WCOM|GO;
                    450:        upaddr->upcs1 = cmd;
                    451:        /*
                    452:         * This is a controller busy situation.
                    453:         * Record in dk slot NUP+DK_N (after last drive)
                    454:         * unless there aren't that many slots reserved for
                    455:         * us in which case we record this as a drive busy
                    456:         * (if there is room for that).
                    457:         */
                    458:        unit = dn+DK_N;
                    459:        if (unit <= DK_NMAX) {
                    460:                dk_busy |= 1<<unit;
                    461:                dk_xfer[unit]++;
                    462:                dk_wds[unit] += bp->b_bcount>>6;
                    463:        }
                    464:        return (1);
                    465: }
                    466: 
                    467: /*
                    468:  * Handle a device interrupt.
                    469:  *
                    470:  * If the transferring drive needs attention, service it
                    471:  * retrying on error or beginning next transfer.
                    472:  * Service all other ready drives, calling ustart to transfer
                    473:  * their blocks to the ready queue in uptab, and then restart
                    474:  * the controller if there is anything to do.
                    475:  */
                    476: upintr()
                    477: {
                    478:        register struct buf *bp, *dp;
                    479:        register unit;
                    480:        register struct device *upaddr = UPADDR;
                    481:        int as = upaddr->upas & 0377;
                    482:        int oupsoftas;
                    483:        int needie = 1;
                    484: 
                    485:        (void) spl6();
                    486:        up_wticks = 0;
                    487:        if (uptab.b_active) {
                    488:                /*
                    489:                 * The drive is transferring, thus the hardware
                    490:                 * (say the designers) will only interrupt when the transfer
                    491:                 * completes; check for it anyways.
                    492:                 */
                    493:                if ((upaddr->upcs1 & RDY) == 0) {
                    494:                        printf("!RDY: cs1 %o, ds %o, wc %d\n", upaddr->upcs1,
                    495:                            upaddr->upds, upaddr->upwc);
                    496:                        printf("as=%d act %d %d %d\n", as, uptab.b_active,
                    497:                            uputab[0].b_active, uputab[1].b_active);
                    498:                }
                    499:                /*
                    500:                 * Mark drive not busy, and check for an
                    501:                 * error condition which may have resulted from the transfer.
                    502:                 */
                    503:                dp = uptab.b_actf;
                    504:                bp = dp->b_actf;
                    505:                unit = dkunit(bp);
                    506:                if (DK_N+unit <= DK_NMAX)
                    507:                        dk_busy &= ~(1<<(DK_N+unit));
                    508:                if ((upaddr->upcs2 & 07) != unit)
                    509:                        upaddr->upcs2 = unit;
                    510:                if ((upaddr->upds&ERR) || (upaddr->upcs1&TRE)) {
                    511:                        /*
                    512:                         * An error occurred, indeed.  Select this unit
                    513:                         * to get at the drive status (a SEARCH may have
                    514:                         * intervened to change the selected unit), and
                    515:                         * wait for the command which caused the interrupt
                    516:                         * to complete (DRY).
                    517:                         */
                    518:                        while ((upaddr->upds & DRY) == 0)
                    519:                                DELAY(25);
                    520:                        /*
                    521:                         * After 28 retries (16 w/o servo offsets, and then
                    522:                         * 12 with servo offsets), or if we encountered
                    523:                         * an error because the drive is write-protected,
                    524:                         * give up.  Print an error message on the last 2
                    525:                         * retries before a hard failure.
                    526:                         */
                    527:                        if (++uptab.b_errcnt > 28 || upaddr->uper1&WLE)
                    528:                                bp->b_flags |= B_ERROR;
                    529:                        else
                    530:                                uptab.b_active = 0;     /* To force retry */
                    531:                        if (uptab.b_errcnt > 27)
                    532:                                deverror(bp, (int)upaddr->upcs2,
                    533:                                    (int)upaddr->uper1);
                    534:                        /*
                    535:                         * If this was a correctible ECC error, let upecc
                    536:                         * do the dirty work to correct it.  If upecc
                    537:                         * starts another READ for the rest of the data
                    538:                         * then it returns 1 (having set uptab.b_active).
                    539:                         * Otherwise we are done and fall through to
                    540:                         * finish up.
                    541:                         */
                    542:                        if ((upaddr->uper1&(DCK|ECH))==DCK && upecc(upaddr, bp))
                    543:                                return;
                    544:                        /*
                    545:                         * Clear the drive and, every 4 retries, recalibrate
                    546:                         * to hopefully help clear up seek positioning problems.
                    547:                         */
                    548:                        upaddr->upcs1 = TRE|IE|DCLR|GO;
                    549:                        needie = 0;
                    550:                        if ((uptab.b_errcnt&07) == 4) {
                    551:                                upaddr->upcs1 = RECAL|GO|IE;
                    552:                                while(upaddr->upds & PIP)
                    553:                                        DELAY(25);
                    554:                        }
                    555:                }
                    556:                /*
                    557:                 * If we are still noted as active, then no
                    558:                 * (further) retries are necessary.  
                    559:                 *
                    560:                 * Make sure the correct unit is selected,
                    561:                 * return it to centerline if necessary, and mark
                    562:                 * this i/o complete, starting the next transfer
                    563:                 * on this drive with the upustart routine (if any).
                    564:                 */
                    565:                if (uptab.b_active) {
                    566:                        if (uptab.b_errcnt >= 16) {
                    567:                                upaddr->upcs1 = RTC|GO|IE;
                    568:                                while (upaddr->upds & PIP)
                    569:                                        DELAY(25);
                    570:                                needie = 0;
                    571:                        }
                    572:                        uptab.b_active = 0;
                    573:                        uptab.b_errcnt = 0;
                    574:                        uptab.b_actf = dp->b_forw;
                    575:                        dp->b_active = 0;
                    576:                        dp->b_errcnt = 0;
                    577:                        dp->b_actf = bp->av_forw;
                    578:                        bp->b_resid = (-upaddr->upwc * sizeof(short));
                    579:                        if (bp->b_resid)
                    580:                                printf("resid %d ds %o er? %o %o %o\n",
                    581:                                    bp->b_resid, upaddr->upds,
                    582:                                    upaddr->uper1, upaddr->uper2, upaddr->uper3);
                    583:                        iodone(bp);
                    584:                        if(dp->b_actf)
                    585:                                if (upustart(unit))
                    586:                                        needie = 0;
                    587:                }
                    588:                as &= ~(1<<unit);
                    589:                upsoftas &= ~(1<<unit);
                    590:                ubafree(up_ubinfo), up_ubinfo = 0;
                    591:        } else {
                    592:                if (upaddr->upcs1 & TRE)
                    593:                        upaddr->upcs1 = TRE;
                    594:        }
                    595:        /*
                    596:         * If we have a unit with an outstanding SEARCH,
                    597:         * and the hardware indicates the unit requires attention,
                    598:         * the bring the drive to the ready queue.
                    599:         * Finally, if the controller is not transferring
                    600:         * start it if any drives are now ready to transfer.
                    601:         */
                    602:        as |= upsoftas;
                    603:        oupsoftas = upsoftas;
                    604:        upsoftas = 0;
                    605:        for (unit = 0; unit < NUP; unit++)
                    606:                if ((as|oupsoftas) & (1<<unit)) {
                    607:                        if (as & (1<<unit))
                    608:                                upaddr->upas = 1<<unit;
                    609:                        if (upustart(unit))
                    610:                                needie = 0;
                    611:                }
                    612:        if (uptab.b_actf && uptab.b_active == 0)
                    613:                if (upstart())
                    614:                        needie = 0;
                    615:        if (needie)
                    616:                upaddr->upcs1 = IE;
                    617: }
                    618: 
                    619: upread(dev)
                    620: {
                    621: 
                    622:        physio(upstrategy, &rupbuf, dev, B_READ, minphys);
                    623: }
                    624: 
                    625: upwrite(dev)
                    626: {
                    627: 
                    628:        physio(upstrategy, &rupbuf, dev, B_WRITE, minphys);
                    629: }
                    630: 
                    631: /*
                    632:  * Correct an ECC error, and restart the i/o to complete
                    633:  * the transfer if necessary.  This is quite complicated because
                    634:  * the transfer may be going to an odd memory address base and/or
                    635:  * across a page boundary.
                    636:  */
                    637: upecc(up, bp)
                    638: register struct device *up;
                    639: register struct buf *bp;
                    640: {
                    641:        struct uba_regs *ubp = (struct uba_regs *)UBA0;
                    642:        register int i;
                    643:        caddr_t addr;
                    644:        int reg, bit, byte, npf, mask, o, cmd, ubaddr;
                    645:        int bn, cn, tn, sn;
                    646: 
                    647:        /*
                    648:         * Npf is the number of sectors transferred before the sector
                    649:         * containing the ECC error, and reg is the UBA register
                    650:         * mapping (the first part of) the transfer.
                    651:         * O is offset within a memory page of the first byte transferred.
                    652:         */
                    653:        npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1;
                    654:        reg = btop(up_ubinfo&0x3ffff) + npf;
                    655:        o = (int)bp->b_un.b_addr & PGOFSET;
                    656:        printf("%D ", bp->b_blkno+npf);
                    657:        prdev("ECC", bp->b_dev);
                    658:        mask = up->upec2;
                    659:        if (mask == 0) {
                    660:                up->upof = FMT22;               /* == RTC ???? */
                    661:                return (0);
                    662:        }
                    663:        /*
                    664:         * Flush the buffered data path, and compute the
                    665:         * byte and bit position of the error.  The variable i
                    666:         * is the byte offset in the transfer, the variable byte
                    667:         * is the offset from a page boundary in main memory.
                    668:         */
                    669:        ubp->uba_dpr[(up_ubinfo>>28)&0x0f] |= BNE;
                    670:        i = up->upec1 - 1;              /* -1 makes 0 origin */
                    671:        bit = i&07;
                    672:        i = (i&~07)>>3;
                    673:        byte = i + o;
                    674:        /*
                    675:         * Correct while possible bits remain of mask.  Since mask
                    676:         * contains 11 bits, we continue while the bit offset is > -11.
                    677:         * Also watch out for end of this block and the end of the whole
                    678:         * transfer.
                    679:         */
                    680:        while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) {
                    681:                addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+
                    682:                    (byte & PGOFSET);
                    683:                putmemc(addr, getmemc(addr)^(mask<<bit));
                    684:                byte++;
                    685:                i++;
                    686:                bit -= 8;
                    687:        }
                    688:        uptab.b_active++;       /* Either complete or continuing... */
                    689:        if (up->upwc == 0)
                    690:                return (0);
                    691:        /*
                    692:         * Have to continue the transfer... clear the drive,
                    693:         * and compute the position where the transfer is to continue.
                    694:         * We have completed npf+1 sectors of the transfer already;
                    695:         * restart at offset o of next sector (i.e. in UBA register reg+1).
                    696:         */
                    697:        up->upcs1 = TRE|IE|DCLR|GO;
                    698:        bn = dkblock(bp);
                    699:        cn = bp->b_cylin;
                    700:        sn = bn%(NSECT*NTRAC) + npf + 1;
                    701:        tn = sn/NSECT;
                    702:        sn %= NSECT;
                    703:        cn += tn/NTRAC;
                    704:        tn %= NTRAC;
                    705:        up->updc = cn;
                    706:        up->upda = (tn << 8) | sn;
                    707:        ubaddr = (int)ptob(reg+1) + o;
                    708:        up->upba = ubaddr;
                    709:        cmd = (ubaddr >> 8) & 0x300;
                    710:        cmd |= IE|GO|RCOM;
                    711:        up->upcs1 = cmd;
                    712:        return (1);
                    713: }
                    714: 
                    715: /*
                    716:  * Reset driver after UBA init.
                    717:  * Cancel software state of all pending transfers
                    718:  * and restart all units and the controller.
                    719:  */
                    720: upreset()
                    721: {
                    722:        int unit;
                    723: 
                    724:        printf(" up");
                    725:        uptab.b_active = 0;
                    726:        uptab.b_actf = uptab.b_actl = 0;
                    727:        if (up_ubinfo) {
                    728:                printf("<%d>", (up_ubinfo>>28)&0xf);
                    729:                ubafree(up_ubinfo), up_ubinfo = 0;
                    730:        }
                    731:        UPADDR->upcs2 = CLR;            /* clear controller */
                    732:        for (unit = 0; unit < NUP; unit++) {
                    733:                uputab[unit].b_active = 0;
                    734:                (void) upustart(unit);
                    735:        }
                    736:        (void) upstart();
                    737: }
                    738: 
                    739: /*
                    740:  * Wake up every second and if an interrupt is pending
                    741:  * but nothing has happened increment a counter.
                    742:  * If nothing happens for 20 seconds, reset the controller
                    743:  * and begin anew.
                    744:  */
                    745: upwatch()
                    746: {
                    747:        int i;
                    748: 
                    749:        timeout(upwatch, (caddr_t)0, HZ);
                    750:        if (uptab.b_active == 0) {
                    751:                for (i = 0; i < NUP; i++)
                    752:                        if (uputab[i].b_active)
                    753:                                goto active;
                    754:                up_wticks = 0;          /* idling */
                    755:                return;
                    756:        }
                    757: active:
                    758:        up_wticks++;
                    759:        if (up_wticks >= 20) {
                    760:                up_wticks = 0;
                    761:                printf("LOST INTERRUPT RESET");
                    762:                upreset();
                    763:                printf("\n");
                    764:        }
                    765: }
                    766: #endif

unix.superglobalmegacorp.com

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