📄 up.c
字号:
if (upaddr->uper1&UPER1_HCRC) { if (upecc(ui, BSE)) return; } hard: harderr(bp, "up"); printf("cn=%d tn=%d sn=%d cs2=%b er1=%b er2=%b\n", upaddr->updc, ((upaddr->upda)>>8)&077, (upaddr->upda)&037, upaddr->upcs2, UPCS2_BITS, upaddr->uper1, UPER1_BITS, upaddr->uper2, UPER2_BITS); bp->b_flags |= B_ERROR; } else if (upaddr->uper2 & UPER2_BSE) { if (upecc(ui, BSE)) return; else goto hard; } else { /* * Retriable error. * If a soft ecc, correct it (continuing * by returning if necessary. * Otherwise fall through and retry the transfer */ if ((upaddr->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK) { if (upecc(ui, ECC)) return; } else um->um_tab.b_active = 0; /* force retry */ } /* * Clear drive error and, every eight attempts, * (starting with the fourth) * recalibrate to clear the slate. */ upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; needie = 0; if ((um->um_tab.b_errcnt&07) == 4 && um->um_tab.b_active == 0) { upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO; sc->sc_recal = 0; goto nextrecal; } } /* * Advance recalibration finite state machine * if recalibrate in progress, through * RECAL * SEEK * OFFSET (optional) * RETRY */ switch (sc->sc_recal) { case 1: upaddr->updc = bp->b_cylin; upaddr->upcs1 = UP_SEEK|UP_IE|UP_GO; goto nextrecal; case 2: if (um->um_tab.b_errcnt < 16 || (bp->b_flags&B_READ) == 0) goto donerecal; upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UPOF_FMT22; upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO; goto nextrecal; nextrecal: sc->sc_recal++; um->um_tab.b_active = 1; return; donerecal: case 3: sc->sc_recal = 0; um->um_tab.b_active = 0; break; } /* * If still ``active'', then don't need any more retries. */ if (um->um_tab.b_active) { /* * If we were offset positioning, * return to centerline. */ if (um->um_tab.b_errcnt >= 16) { upaddr->upof = UPOF_FMT22; upaddr->upcs1 = UP_RTC|UP_GO|UP_IE; while (upaddr->upds & UPDS_PIP) DELAY(25); needie = 0; } um->um_tab.b_active = 0; um->um_tab.b_errcnt = 0; um->um_tab.b_actf = dp->b_forw; dp->b_active = 0; dp->b_errcnt = 0; dp->b_actf = bp->av_forw; bp->b_resid = (-upaddr->upwc * sizeof(short)); iodone(bp); /* * If this unit has more work to do, * then start it up right away. */ if (dp->b_actf) if (upustart(ui)) needie = 0; } as &= ~(1<<ui->ui_slave); /* * Release unibus resources and flush data paths. */ ubadone(um);doattn: /* * Process other units which need attention. * For each unit which needs attention, call * the unit start routine to place the slave * on the controller device queue. */ while (unit = ffs(as)) { unit--; /* was 1 origin */ as &= ~(1<<unit); upaddr->upas = 1<<unit; if (unit < UPIPUNITS && upustart(upip[sc21][unit])) needie = 0; } /* * If the controller is not transferring, but * there are devices ready to transfer, start * the controller. */ if (um->um_tab.b_actf && um->um_tab.b_active == 0) if (upstart(um)) needie = 0; if (needie) upaddr->upcs1 = UP_IE;}upread(dev, uio) dev_t dev; struct uio *uio;{ register int unit = minor(dev) >> 3; if (unit >= nNUP) return (ENXIO); return (physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys, uio));}upwrite(dev, uio) dev_t dev; struct uio *uio;{ register int unit = minor(dev) >> 3; if (unit >= nNUP) return (ENXIO); return (physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys, uio));}/*ARGSUSED*/upioctl(dev, cmd, data, flag) dev_t dev; int cmd; caddr_t data; int flag;{ struct pt *pt = (struct pt *)data; int unit = minor(dev) >> 3; register struct uba_device *ui; register int nspc; register int i; int error; switch (cmd) { case DIOCGETPT: /* 001 get partition table info */ /* * Do a structure copy into the user's data area */ *pt = up_part[unit]; return(0); case DIOCDGTPT: /* 002 Return that default partition table */ ui = updinfo[unit]; /* * Get number sector per cylinder */ nspc = upst[ui->ui_type].nspc; /* * Get and store the default block count and offset */ for( i = 0; i <= 7; i++ ) { pt->pt_part[i].pi_nblocks = upst[ui->ui_type].sizes[i].nblocks; pt->pt_part[i].pi_blkoff = upst[ui->ui_type].sizes[i].cyloff * nspc; } return(0); case DIOCSETPT: /* 001 set the driver partition tables */ /* * Only super users can set the pack's partition * table */ if ( !suser() ) return(EACCES); /* * Before we set the new partition tables make sure * that it will no corrupt any of the kernel data * structures */ if ( ( error = ptcmp( dev, &up_part[unit], pt ) ) != 0 ) return(error); /* * Using the user's data to set the partition table * for the pack */ up_part[unit] = *pt; /* * See if we need to update the superblock of the * "a" partition of this disk */ ssblk(dev,pt); /* * Just make sure that we set the valid bit */ up_part[unit].pt_valid = PT_VALID; return(0); default: return (ENXIO); }}/* * Correct an ECC error, and restart the i/o to complete * the transfer if necessary. This is quite complicated because * the transfer may be going to an odd memory address base and/or * across a page boundary. */upecc(ui, flag) register struct uba_device *ui; int flag;{ register struct updevice *up = (struct updevice *)ui->ui_addr; register struct buf *bp = uputab[ui->ui_unit].b_actf; register struct uba_ctlr *um = ui->ui_mi; register struct upst *st; struct uba_regs *ubp = ui->ui_hd->uh_uba; register int i; caddr_t addr; int reg, bit, byte, npf, mask, o, cmd, ubaddr; int bn, cn, tn, sn; /* * Npf is the number of sectors transferred before the sector * containing the ECC error, and reg is the UBA register * mapping (the first part of) the transfer. * O is offset within a memory page of the first byte transferred. */ if (flag == CONT) npf = bp->b_error; else npf = btop((up->upwc * sizeof(short)) + bp->b_bcount); reg = btop(um->um_ubinfo&0x3ffff) + npf; o = (int)bp->b_un.b_addr & PGOFSET; mask = up->upec2;#ifdef UPECCDEBUG printf("npf %d reg %x o %d mask %o pos %d\n", npf, reg, o, mask, up->upec1);#endif bn = dkblock(bp); st = &upst[ui->ui_type]; cn = bp->b_cylin; sn = bn%st->nspc + npf; tn = sn/st->nsect; sn %= st->nsect; cn += tn/st->ntrak; tn %= st->ntrak; ubapurge(um); um->um_tab.b_active=2; /* * action taken depends on the flag */ switch(flag){ case ECC: npf--; reg--; mask = up->upec2; printf("up%d%c: soft ecc sn%d\n", dkunit(bp), 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf); /* * Flush the buffered data path, and compute the * byte and bit position of the error. The variable i * is the byte offset in the transfer, the variable byte * is the offset from a page boundary in main memory. */ i = up->upec1 - 1; /* -1 makes 0 origin */ bit = i&07; i = (i&~07)>>3; byte = i + o; /* * Correct while possible bits remain of mask. Since mask * contains 11 bits, we continue while the bit offset is > -11. * Also watch out for end of this block and the end of the whole * transfer. */ while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { struct pte pte; pte = ubp->uba_map[reg + btop(byte)]; addr = ptob(pte.pg_pfnum) + (byte & PGOFSET);#ifdef UPECCDEBUG printf("addr %x map reg %x\n", addr, *(int *)(&ubp->uba_map[reg+btop(byte)])); printf("old: %x, ", getmemc(addr));#endif putmemc(addr, getmemc(addr)^(mask<<bit));#ifdef UPECCDEBUG printf("new: %x\n", getmemc(addr));#endif byte++; i++; bit -= 8; } if (up->upwc == 0) return (0); npf++; reg++; break; case BSE: /* * if not in bad sector table, return 0 */ if ((bn = isbad(&upbad[ui->ui_unit], cn, tn, sn)) < 0) return(0); /* * flag this one as bad */ bp->b_flags |= B_BAD; bp->b_error = npf + 1;#ifdef UPECCDEBUG printf("BSE: restart at %d\n",npf+1);#endif bn = st->ncyl * st->nspc -st->nsect - 1 - bn; cn = bn / st->nspc; sn = bn % st->nspc; tn = sn / st->nsect; sn %= st->nsect; up->upwc = -(512 / sizeof (short));#ifdef UPECCDEBUG printf("revector to cn %d tn %d sn %d\n", cn, tn, sn);#endif break; case CONT:#ifdef UPECCDEBUG printf("upecc, CONT: bn %d cn %d tn %d sn %d\n", bn, cn, tn, sn);#endif bp->b_flags &= ~B_BAD; up->upwc = -((bp->b_bcount - (int)ptob(npf)) / sizeof(short)); if (up->upwc == 0) return(0); break; } if (up->upwc == 0) { um->um_tab.b_active = 0; return (0); } /* * Have to continue the transfer... clear the drive, * and compute the position where the transfer is to continue. * We have completed npf+1 sectors of the transfer already; * restart at offset o of next sector (i.e. in UBA register reg+1). */#ifdef notdef up->uper1 = 0; up->upcs1 |= UP_GO;#else up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; up->updc = cn; up->upda = (tn << 8) | sn; ubaddr = (int)ptob(reg) + o; up->upba = ubaddr; cmd = (ubaddr >> 8) & 0x300; cmd |= ((bp->b_flags&B_READ)?UP_RCOM:UP_WCOM)|UP_IE|UP_GO; um->um_tab.b_errcnt = 0; up->upcs1 = cmd;#endif return (1);}/* * Reset driver after UBA init. * Cancel software state of all pending transfers * and restart all units and the controller. */upreset(uban) int uban;{ register struct uba_ctlr *um; register struct uba_device *ui; register sc21, unit; for (sc21 = 0; sc21 < nNSC; sc21++) { if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || um->um_alive == 0) continue; printf(" sc%d", sc21); um->um_tab.b_active = 0; um->um_tab.b_actf = um->um_tab.b_actl = 0; up_softc[sc21].sc_recal = 0; up_softc[sc21].sc_wticks = 0; if (um->um_ubinfo) { printf("<%d>", (um->um_ubinfo>>28)&0xf); um->um_ubinfo = 0; } ((struct updevice *)(um->um_addr))->upcs2 = UPCS2_CLR; for (unit = 0; unit < nNUP; unit++) { if ((ui = updinfo[unit]) == 0) continue; if (ui->ui_alive == 0 || ui->ui_mi != um) continue; uputab[unit].b_active = 0; (void) upustart(ui); } (void) upstart(um); }}/* * Wake up every second and if an interrupt is pending * but nothing has happened increment a counter. * If nothing happens for 20 seconds, reset the UNIBUS * and begin anew. */upwatch(){ register struct uba_ctlr *um; register sc21, unit; register struct up_softc *sc; timeout(upwatch, (caddr_t)0, hz); for (sc21 = 0; sc21 < nNSC; sc21++) { um = upminfo[sc21]; if (um == 0 || um->um_alive == 0) continue; sc = &up_softc[sc21]; if (um->um_tab.b_active == 0) { for (unit = 0; unit < nNUP; unit++) if (uputab[unit].b_active && updinfo[unit]->ui_mi == um) goto active; sc->sc_wticks = 0; continue; }active: sc->sc_wticks++; if (sc->sc_wticks >= 20) { sc->sc_wticks = 0; printf("sc%d: lost interrupt\n", sc21); ubareset(um->um_ubanum); } }}#define DBSIZE 20updump(dev, dumpinfo) dev_t dev; /* dump device */ struct dumpinfo dumpinfo; /* dump info */{#ifdef notdef struct updevice *upaddr; char *start; char *start_tmp; int blk, unit, ubatype; register struct uba_regs *uba; register struct uba_device *ui; register short *rp; struct upst *st; register int retry; unit = minor(dev) >> 3; if (unit >= nNUP) return (ENXIO);#define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) ui = phys(struct uba_device *, updinfo[unit]); if (ui->ui_alive == 0) return (ENXIO); uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; ubatype = phys(struct uba_hd *, ui->ui_hd)->uba_type; ubainit(uba,ubatype); upaddr = (struct updevice *)ui->ui_physaddr; DELAY(5000000); upaddr->upcs2 = unit; DELAY(100); upaddr->upcs1 = UP_DCLR|UP_GO; upaddr->upcs1 = UP_PRESET|UP_GO; upaddr->upof = UPOF_FMT22; retry = 0; do { DELAY(25); if (++retry > 527) break; } while ((upaddr->upds & UP_RDY) == 0); if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) return (EFAULT); start = start_tmp = 0; st = &upst[ui->ui_type]; /* * If a full dump is being performed, then this loop * will dump all of core. If a partial dump is being * performed, then as much of core as possible will be * dumped, leaving room for the u_area and error logger * buffer. Please note that dumpsys predetermined what * type of dump will be performed. */ while ((dumpinfo.size_to_dump > 0) || (dumpinfo.partial_dump)) { register struct pte *io; register int i; int cn, sn, tn; daddr_t bn; blk = dumpinfo.size_to_dump > DBSIZE ? DBSIZE : dumpinfo.size_to_dump; io = uba->uba_map; for (i = 0; i < blk; i++) *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; *(int *)io = 0; bn = dumplo + btop(start_tmp); cn = bn/st->nspc + dumpinfo.blkoffs / st->nspc; sn = bn%st->nspc; tn = sn/st->nsect; sn = sn%st->nsect; upaddr->updc = cn; rp = (short *) &upaddr->upda; *rp = (tn << 8) + sn; *--rp = 0; *--rp = -blk*NBPG / sizeof (short); *--rp = UP_GO|UP_WCOM; retry = 0; do { DELAY(25); if (++retry > 527) break; } while ((upaddr->upcs1 & UP_RDY) == 0); if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { printf("up%d: not ready", unit); if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { printf("\n"); return (EIO); } printf(" (flakey)\n"); } if (upaddr->upds&UPDS_ERR) return (EIO); start += blk*NBPG; start_tmp += blk*NBPG; dumpinfo.size_to_dump -= blk; if ((dumpinfo.size_to_dump <= 0) && (dumpinfo.partial_dump)) { /* * If a partial dump is being performed.... */ /* Set size_to_dump to the number of pages of elbuf */ dumpinfo.size_to_dump = dumpinfo.pdump[NUM_TO_DUMP-dumpinfo.partial_dump].num_blks; /* Set start to starting address */ start = 0; start += dumpinfo.pdump[NUM_TO_DUMP-dumpinfo.partial_dump].start_addr; dumpinfo.partial_dump--; } } return (0);#endif notdef}upsize(dev) dev_t dev;{ int unit = minor(dev) >> 3; struct uba_device *ui; struct upst *st; if (unit >= nNUP || (ui = updinfo[unit]) == 0 || ui->ui_alive == 0) return (-1); /* * Sanity check 001 */ if ( up_part[unit].pt_valid != PT_VALID ) panic("upsize: invalid partition table "); return (up_part[unit].pt_part[minor(dev) & 07].pi_nblocks); /* 001 */}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -