/* hp.c 4.47 82/02/18 */ #ifdef HPDEBUG int hpdebug; #endif #ifdef HPBDEBUG int hpbdebug; #endif #include "hp.h" /* * HP disk driver for RP0x+RMxx+ML11 * * TODO: * check RM80 skip sector handling when ECC's occur later * check offset recovery handling * see if DCLR and/or RELEASE set attention status * print bits of mr && mr2 symbolically */ #include "../h/param.h" #include "../h/systm.h" #include "../h/dk.h" #include "../h/buf.h" #include "../h/conf.h" #include "../h/dir.h" #include "../h/user.h" #include "../h/map.h" #include "../h/pte.h" #include "../h/mbareg.h" #include "../h/mbavar.h" #include "../h/mtpr.h" #include "../h/vm.h" #include "../h/cmap.h" #include "../h/dkbad.h" #include "../h/hpio.h" #include "../h/hpreg.h" /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ struct size { daddr_t nblocks; int cyloff; } hp6_sizes[8] = { 15884, 0, /* A=cyl 0 thru 37 */ 33440, 38, /* B=cyl 38 thru 117 */ 340670, 0, /* C=cyl 0 thru 814 */ 0, 0, 0, 0, 0, 0, #ifndef NOBADSECT 291280, 118, /* G=cyl 118 thru 814 */ #else 291346, 118, #endif 0, 0, }, rm3_sizes[8] = { 15884, 0, /* A=cyl 0 thru 99 */ 33440, 100, /* B=cyl 100 thru 309 */ 131680, 0, /* C=cyl 0 thru 822 */ 0, 0, 0, 0, 0, 0, #ifndef NOBADSECT 81984, 310, /* G=cyl 310 thru 822 */ #else 82080, 310, #endif 0, 0, }, rm5_sizes[8] = { 15884, 0, /* A=cyl 0 thru 26 */ 33440, 27, /* B=cyl 27 thru 81 */ 500384, 0, /* C=cyl 0 thru 822 */ 15884, 562, /* D=cyl 562 thru 588 */ 55936, 589, /* E=cyl 589 thru 680 */ #ifndef NOBADSECT 86240, 681, /* F=cyl 681 thru 822 */ 158592, 562, /* G=cyl 562 thru 822 */ #else 86636, 681, 158688, 562, #endif 291346, 82, /* H=cyl 82 thru 561 */ }, rm80_sizes[8] = { 15884, 0, /* A=cyl 0 thru 36 */ 33440, 37, /* B=cyl 37 thru 114 */ 242606, 0, /* C=cyl 0 thru 558 */ 0, 0, 0, 0, 192223, 115, /* F=cyl 115 thru 558 */ 82080, 115, /* G=cyl 115 thru 304 */ 110143, 305, /* H=cyl 305 thru 558 */ }, mfj_sizes[8] = { 10240, 0, /* A=cyl 0 thru 31 */ 20480, 32, /* B=cyl 32 thru 95 */ 232640, 96, /* C=cyl 96 thru 822 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, eagle_sizes[8] ={ 27520, 0, /* A=cyl 0 thru 31 */ 27520, 32, /* B=cyl 32 thru 63 */ 667360, 64, /* C=cyl 64 thru 839 */ 232640, 64, /* D=cyl 64 thru 340 (partial) */ 232640, 341, /* E=cyl 341 thru 617 (partial) */ 0, 0, 0, 0, 0, 0, /* 48 sector Emulex Eagle */ }, eag48_sizes[8] = { /* cyl 841 used for bad sectors + info */ #ifdef ICARUS 11*960, 0, /* A = cyl 0 thru 10 for / */ 22*960, 11, /* B = cyl 11 thru 32 for swap */ 842*960, 0, /* C = all cyl 0 thru 841 for testing */ 16*960, 33, /* D = cyl 33 thru 48 for /usr/guest */ 66*960, 49, /* E = cyl 49 thru 114 for /usr/src */ 242*960,115, /* F = cyl 115 thru 356 nearly 1/3 */ 242*960,357, /* G = cyl 357 thru 598 nearly 1/3 */ 242*960,599, /* H = cyl 599 thru 840 nearly 1/3 */ #else ICARUS 45*960, 0, /* A = cyl 0 thru 44 for /tmp */ 64*960, 45, /* B = cyl 45 thru 108 for swap */ 842*960, 0, /* C = all cyl 0 thru 841 for testing */ 244*960,109, /* D = cyl 109 thru 352 nearly 1/3 */ 244*960,353, /* E = cyl 353 thru 596 nearly 1/3 */ 244*960,597, /* F = cyl 597 thru 840 nearly 1/3 */ 0, 0, /* G = cyl 0 thru 402 nearly 1/2 */ 0, 0, /* H = cyl 438 thru 840 nearly 1/2 */ #endif ICARUS }, hp7_sizes[8] = { 15884, 0, /* A=cyl 0 thru 9 */ 64000, 10, /* B=cyl 10 thru 49 */ 1008000,0, /* C=cyl 0 thru 629 */ 504000, 0, /* D=cyl 0 thru 314 */ 504000, 315, /* E=cyl 315 thru 629 */ 928000, 50, /* F=cyl 50 thru 629 */ 0, 0, 0, 0, }; /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ #ifndef EAG48 #define _hpSDIST 2 #define _hpRDIST 3 #else EAG48 /* these constants were originally 2 and 3 respectively. they have been changed to improve the performance of the eagle drives with the emulex controller. to date, 8,9 is better than 2,3. 12,13 did not do any better than 8,9. changing these constants changes the lead for all drives using the hp driver including the rm80. that's a mistake, but empirically, changing these to 8,9 did not measurably change rm80 performance. */ #define _hpSDIST 8 #define _hpRDIST 9 #endif EAG48 int hpSDIST = _hpSDIST; int hpRDIST = _hpRDIST; short hptypes[] = { MBDT_RM03, MBDT_RM05, MBDT_RP06, MBDT_RM80, MBDT_RP05, MBDT_RP07, MBDT_FUJI, MBDT_FUJI, MBDT_FUJI, MBDT_ML11A, MBDT_ML11B, 0 }; struct mba_device *hpinfo[NHP]; int hpattach(),hpustart(),hpstart(),hpdtint(); struct mba_driver hpdriver = { hpattach, 0, hpustart, hpstart, hpdtint, 0, hptypes, "hp", 0, hpinfo }; struct hpst { short nsect; short ntrak; short nspc; short ncyl; struct size *sizes; } hpst[] = { 32, 5, 32*5, 823, rm3_sizes, /* RM03 */ 32, 19, 32*19, 823, rm5_sizes, /* RM05 */ 22, 19, 22*19, 815, hp6_sizes, /* RP06 */ 31, 14, 31*14, 559, rm80_sizes, /* RM80 */ 22, 19, 22*19, 411, hp6_sizes, /* RP05 */ 50, 32, 50*32, 630, hp7_sizes, /* RP07 */ /* the following three entries must be contiguous */ 32, 10, 32*10, 823, mfj_sizes, /* little fujitsu */ 43, 20, 43*20, 842, eagle_sizes, /* eagle */ 48, 20, 48*20, 842, eag48_sizes, /* eagle 48 sectors */ 1, 1, 1, 1, 0, /* ML11A */ 1, 1, 1, 1, 0, /* ML11B */ }; u_char hp_offset[16] = { HPOF_P400, HPOF_M400, HPOF_P400, HPOF_M400, HPOF_P800, HPOF_M800, HPOF_P800, HPOF_M800, HPOF_P1200, HPOF_M1200, HPOF_P1200, HPOF_M1200, 0, 0, 0, 0, }; struct buf rhpbuf[NHP]; #ifndef NOBADSECT struct buf bhpbuf[NHP]; struct dkbad hpbad[NHP]; #endif char hpinit[NHP]; char hprecal[NHP]; char hphdr[NHP]; daddr_t mlsize[NHP]; #define b_cylin b_resid /* #define ML11 0 to remove ML11 support */ #define ML11 0 /*#define ML11 (hptypes[mi->mi_type] == MBDT_ML11A)*/ #define RP06 (hptypes[mi->mi_type] <= MBDT_RP06) #define RM80 (hptypes[mi->mi_type] == MBDT_RM80) #ifdef INTRLVE daddr_t dkblock(); #endif int hpseek; /*ARGSUSED*/ hpattach(mi, slave) struct mba_device *mi; { register struct hpst *st = &hpst[mi->mi_type]; if (hptypes[mi->mi_type] == MBDT_ML11B) mi->mi_type--; /* A CHEAT - ML11B D.T. SHOULD == ML11A */ if (ML11) { register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv; register int trt, sz; sz = hpaddr->hpmr & HPMR_SZ; if ((hpaddr->hpmr & HPMR_ARRTYP) == 0) sz >>= 2; mlsize[mi->mi_unit] = sz; if (mi->mi_dk >= 0) { trt = (hpaddr->hpmr & HPMR_TRT) >> 8; dk_mspw[mi->mi_dk] = 1.0 / (1<<(20-trt)); } } else if (mi->mi_dk >= 0) { register struct hpdevice *hp; register int type; hp = (struct hpdevice *) mi->mi_drv; type = hp->hpdt & MBDT_TYPE; if (type == MBDT_FUJI) { short maxtrk, maxsect; /* * we have some kind of disk on an Emulex SC750. * We assume it's a little Fuji, and must now check * if it's an Eagle. */ hp->hphr = HPHR_MAXTRK; maxtrk = hp->hphr; if (maxtrk >= hpst[mi->mi_type].ntrak) { mi->mi_type++; /* it's an Eagle. now check # of sectors */ hp->hphr = HPHR_MAXSECT; maxsect = hp->hphr; if (maxsect > hpst[mi->mi_type].nsect) { printf("%d sectors\n", maxsect); mi->mi_type++; } } } st = &hpst[mi->mi_type]; dk_mspw[mi->mi_dk] = 1.0 / 60 / (st->nsect * 256); } } hpstrategy(bp) register struct buf *bp; { register struct mba_device *mi; register struct hpst *st; register int unit; long sz, bn; int xunit = minor(bp->b_dev) & 07; int s; sz = bp->b_bcount; sz = (sz+511) >> 9; unit = dkunit(bp); if (unit >= NHP) goto bad; mi = hpinfo[unit]; if (mi == 0 || mi->mi_alive == 0) goto bad; st = &hpst[mi->mi_type]; if (ML11) { if (bp->b_blkno < 0 || dkblock(bp)+sz > mlsize[mi->mi_unit]) goto bad; bp->b_cylin = 0; } else { if (bp->b_blkno < 0 || (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) goto bad; bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; } s = spl5(); disksort(&mi->mi_tab, bp); if (mi->mi_tab.b_active == 0) mbustart(mi); splx(s); return; bad: bp->b_flags |= B_ERROR; iodone(bp); return; } hpustart(mi) register struct mba_device *mi; { register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv; register struct buf *bp = mi->mi_tab.b_actf; register struct hpst *st = &hpst[mi->mi_type]; daddr_t bn; int sn, dist; hpaddr->hpcs1 = 0; if ((hpaddr->hpcs1&HP_DVA) == 0) return (MBU_BUSY); if ((hpaddr->hpds & HPDS_VV) == 0 || hpinit[mi->mi_unit] == 0) { #ifndef NOBADSECT struct buf *bbp = &bhpbuf[mi->mi_unit]; #endif hpinit[mi->mi_unit] = 1; hpaddr->hpcs1 = HP_DCLR|HP_GO; if (mi->mi_mba->mba_drv[0].mbd_as & (1<<mi->mi_drive)) printf("DCLR attn\n"); hpaddr->hpcs1 = HP_PRESET|HP_GO; if (!ML11) hpaddr->hpof = HPOF_FMT22; mbclrattn(mi); #ifndef NOBADSECT if (!ML11) { bbp->b_flags = B_READ|B_BUSY; bbp->b_dev = bp->b_dev; bbp->b_bcount = 512; bbp->b_un.b_addr = (caddr_t)&hpbad[mi->mi_unit]; bbp->b_blkno = st->ncyl*st->nspc - st->nsect; bbp->b_cylin = st->ncyl - 1; mi->mi_tab.b_actf = bbp; bbp->av_forw = bp; bp = bbp; } #endif } if (mi->mi_tab.b_active || mi->mi_hd->mh_ndrive == 1) return (MBU_DODATA); if (ML11) return (MBU_DODATA); if ((hpaddr->hpds & HPDS_DREADY) != HPDS_DREADY) return (MBU_DODATA); bn = dkblock(bp); sn = bn%st->nspc; sn = (sn+st->nsect-hpSDIST)%st->nsect; if (bp->b_cylin == (hpaddr->hpdc & 0xffff)) { if (hpseek) return (MBU_DODATA); dist = ((hpaddr->hpla & 0xffff)>>6) - st->nsect + 1; if (dist < 0) dist += st->nsect; if (dist > st->nsect - hpRDIST) return (MBU_DODATA); } else hpaddr->hpdc = bp->b_cylin; if (hpseek) hpaddr->hpcs1 = HP_SEEK|HP_GO; else { hpaddr->hpda = sn; hpaddr->hpcs1 = HP_SEARCH|HP_GO; } return (MBU_STARTED); } hpstart(mi) register struct mba_device *mi; { register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv; register struct buf *bp = mi->mi_tab.b_actf; register struct hpst *st = &hpst[mi->mi_type]; daddr_t bn; int sn, tn; bn = dkblock(bp); if (ML11) hpaddr->hpda = bn; else { sn = bn%st->nspc; tn = sn/st->nsect; sn %= st->nsect; hpaddr->hpdc = bp->b_cylin; hpaddr->hpda = (tn << 8) + sn; } if (hphdr[mi->mi_unit]) { if (bp->b_flags & B_READ) return (HP_RHDR|HP_GO); else return (HP_WHDR|HP_GO); } return (0); } hpdtint(mi, mbsr) register struct mba_device *mi; int mbsr; { register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv; register struct buf *bp = mi->mi_tab.b_actf; register int er1, er2; int retry = 0; #ifndef NOBADSECT if (bp->b_flags&B_BAD) { if (hpecc(mi, CONT)) return(MBD_RESTARTED); } #endif if (hpaddr->hpds&HPDS_ERR || mbsr&MBSR_EBITS) { #ifdef HPDEBUG if (hpdebug) { int dc = hpaddr->hpdc, da = hpaddr->hpda; struct hpst *st = &hpst[mi->mi_type]; printf("hperr: bp %x cyl %d blk %d as %o ", bp, bp->b_cylin, bp->b_blkno, hpaddr->hpas&0xff); printf("dc %x da %x\n",dc&0xffff, da&0xffff); printf("errcnt %d ", mi->mi_tab.b_errcnt); printf("mbsr=%b ", mbsr, mbsr_bits); printf("er1=%b er2=%b\n", hpaddr->hper1, HPER1_BITS, hpaddr->hper2, HPER2_BITS); DELAY(1000000); } #endif er1 = hpaddr->hper1; er2 = hpaddr->hper2; if (er1 & HPER1_HCRC) { er1 &= ~(HPER1_HCE|HPER1_FER); er2 &= ~HPER2_BSE; } if (er1&HPER1_WLE) { printf("hp%d: write locked\n", dkunit(bp)); bp->b_flags |= B_ERROR; } else if ((er1&0xffff) == HPER1_FER && RP06 && hphdr[mi->mi_unit] == 0) { #ifndef NOBADSECT if (hpecc(mi, BSE)) { #ifdef HPBDEBUG if (hpdebug) printf("MBD_RESTARTED\n"); #endif return(MBD_RESTARTED); } else #endif goto hard; } else if (++mi->mi_tab.b_errcnt > 27 || mbsr & MBSR_HARD || er1 & HPER1_HARD || hphdr[mi->mi_unit] || (!ML11 && (er2 & HPER2_HARD))) { hard: harderr(bp, "hp"); if (mbsr & (MBSR_EBITS &~ (MBSR_DTABT|MBSR_MBEXC))) printf("mbsr=%b ", mbsr, mbsr_bits); printf("er1=%b er2=%b", hpaddr->hper1, HPER1_BITS, hpaddr->hper2, HPER2_BITS); if (hpaddr->hpmr) printf(" mr=%o", hpaddr->hpmr&0xffff); if (hpaddr->hpmr2) printf(" mr2=%o", hpaddr->hpmr2&0xffff); printf("\n"); bp->b_flags |= B_ERROR; hprecal[mi->mi_unit] = 0; } else if ((er2 & HPER2_BSE) && !ML11) { #ifndef NOBADSECT if (hpecc(mi, BSE)) return(MBD_RESTARTED); else #endif goto hard; } else if (RM80 && er2&HPER2_SSE) { (void) hpecc(mi, SSE); return (MBD_RESTARTED); } else if ((er1&(HPER1_DCK|HPER1_ECH))==HPER1_DCK) { if (hpecc(mi, ECC)) return (MBD_RESTARTED); /* else done */ } else retry = 1; hpaddr->hpcs1 = HP_DCLR|HP_GO; if (ML11) { if (mi->mi_tab.b_errcnt >= 16) goto hard; } else if ((mi->mi_tab.b_errcnt&07) == 4) { hpaddr->hpcs1 = HP_RECAL|HP_GO; hprecal[mi->mi_unit] = 1; return(MBD_RESTARTED); } if (retry) return (MBD_RETRY); } #ifdef HPDEBUG else if (hpdebug && hprecal[mi->mi_unit]) { printf("recal %d ", hprecal[mi->mi_unit]); printf("errcnt %d\n", mi->mi_tab.b_errcnt); printf("mbsr=%b ", mbsr, mbsr_bits); printf("er1=%b er2=%b\n", hpaddr->hper1, HPER1_BITS, hpaddr->hper2, HPER2_BITS); } #endif switch (hprecal[mi->mi_unit]) { case 1: hpaddr->hpdc = bp->b_cylin; hpaddr->hpcs1 = HP_SEEK|HP_GO; hprecal[mi->mi_unit]++; return (MBD_RESTARTED); case 2: if (mi->mi_tab.b_errcnt < 16 || (bp->b_flags & B_READ) == 0) goto donerecal; hpaddr->hpof = hp_offset[mi->mi_tab.b_errcnt & 017]|HPOF_FMT22; hpaddr->hpcs1 = HP_OFFSET|HP_GO; hprecal[mi->mi_unit]++; return (MBD_RESTARTED); donerecal: case 3: hprecal[mi->mi_unit] = 0; return (MBD_RETRY); } hphdr[mi->mi_unit] = 0; bp->b_resid = -(mi->mi_mba->mba_bcr) & 0xffff; if (mi->mi_tab.b_errcnt >= 16) { /* * This is fast and occurs rarely; we don't * bother with interrupts. */ hpaddr->hpcs1 = HP_RTC|HP_GO; while (hpaddr->hpds & HPDS_PIP) ; mbclrattn(mi); } if (!ML11) { hpaddr->hpof = HPOF_FMT22; hpaddr->hpcs1 = HP_RELEASE|HP_GO; } return (MBD_DONE); } hpread(dev) dev_t dev; { register int unit = minor(dev) >> 3; if (unit >= NHP) u.u_error = ENXIO; else physio(hpstrategy, &rhpbuf[unit], dev, B_READ, minphys); } hpwrite(dev) dev_t dev; { register int unit = minor(dev) >> 3; if (unit >= NHP) u.u_error = ENXIO; else physio(hpstrategy, &rhpbuf[unit], dev, B_WRITE, minphys); } /*ARGSUSED*/ hpioctl(dev, cmd, addr, flag) dev_t dev; int cmd; caddr_t addr; int flag; { switch (cmd) { case DKIOCHDR: /* do header read/write */ if (suser()) hphdr[minor(dev)>>3] = 1; return; default: u.u_error = ENXIO; } } hpecc(mi, flag) register struct mba_device *mi; int flag; { register struct mba_regs *mbp = mi->mi_mba; register struct hpdevice *rp = (struct hpdevice *)mi->mi_drv; register struct buf *bp = mi->mi_tab.b_actf; register struct hpst *st = &hpst[mi->mi_type]; int npf, o; int bn, cn, tn, sn; int bcr; static nerr; bcr = mbp->mba_bcr & 0xffff; if (bcr) bcr |= 0xffff0000; /* sxt */ #ifndef NOBADSECT if (flag == CONT) npf = bp->b_error; else #endif npf = btop(bcr + bp->b_bcount); o = (int)bp->b_un.b_addr & PGOFSET; bn = dkblock(bp); #ifdef HPBDEBUG if (hpbdebug) printf("hpecc: mbp->mba_bcr %x bcr %x bp->b_bcount %x bp->b_error %x bn %x npf %x\n", mbp->mba_bcr, bcr, bp->b_bcount, bp->b_error, bn, npf); if (hpbdebug) printf("ber npf: %x\n", ((rp->hpdc & 0xffff) * (st->nspc)) + ((((rp->hpda) >> 8) & 0xff) * st->nsect) + ((rp->hpda) & 0xff) - (((st->sizes[minor(bp->b_dev)&07].cyloff) * st->nspc) + 1 + bn)); #endif cn = bp->b_cylin; sn = bn%(st->nspc) + npf; tn = sn/st->nsect; sn %= st->nsect; cn += tn/st->ntrak; tn %= st->ntrak; switch (flag) { case ECC: { register int i; caddr_t addr; struct pte mpte; int bit, byte, mask; npf--; /* because block in error is previous block */ printf("hp%d%c: soft ecc sn%d\n", dkunit(bp), 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf); nerr++; if ((nerr%100)==0) printf("%d soft errors\n", nerr); mask = rp->hpec2&0xffff; i = (rp->hpec1&0xffff) - 1; /* -1 makes 0 origin */ bit = i&07; i = (i&~07)>>3; byte = i + o; while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { mpte = mbp->mba_map[npf+btop(byte)]; addr = ptob(mpte.pg_pfnum) + (byte & PGOFSET); putmemc(addr, getmemc(addr)^(mask<<bit)); byte++; i++; bit -= 8; } if (bcr == 0) return (0); npf++; break; } case SSE: #ifdef HPBDEBUG if (hpbdebug) printf("hpeccSSE\n"); #endif rp->hpof |= HPOF_SSEI; mbp->mba_bcr = -(bp->b_bcount - (int)ptob(npf)); break; #ifndef NOBADSECT case BSE: #ifdef HPBDEBUG if (hpbdebug) printf("hpeccBSE: bn %d cn %d tn %d sn %d\n", bn, cn, tn, sn); #endif if ((bn = isbad(&hpbad[mi->mi_unit], cn, tn, sn)) < 0) return(0); bp->b_flags |= B_BAD; bp->b_error = npf + 1; bn = st->ncyl*st->nspc - st->nsect - 1 - bn; cn = bn/st->nspc; sn = bn%st->nspc; tn = sn/st->nsect; sn %= st->nsect; mbp->mba_bcr = -512; #ifdef HPBDEBUG if (hpbdebug) printf("revector to cn %d tn %d sn %d\n", cn, tn, sn); #endif break; case CONT: #ifdef HPBDEBUG if (hpbdebug) printf("hpecc, CONT: bn %d cn %d tn %d sn %d\n", bn,cn,tn,sn); #endif npf = bp->b_error; bp->b_flags &= ~B_BAD; mbp->mba_bcr = -(bp->b_bcount - (int)ptob(npf)); if ((mbp->mba_bcr & 0xffff) == 0) return(0); break; #endif } #ifdef HPBDEBUG if (hpbdebug) printf("hpecc, endcase: bn %d\n",bn); #endif rp->hpcs1 = HP_DCLR|HP_GO; if (rp->hpof&HPOF_SSEI) sn++; rp->hpdc = cn; rp->hpda = (tn<<8) + sn; mbp->mba_sr = -1; mbp->mba_var = (int)ptob(npf) + o; rp->hpcs1 = bp->b_flags&B_READ ? HP_RCOM|HP_GO : HP_WCOM|HP_GO; mi->mi_tab.b_errcnt = 0; /* error has been corrected */ return (1); } #define DBSIZE 20 hpdump(dev) dev_t dev; { register struct mba_device *mi; register struct mba_regs *mba; struct hpdevice *hpaddr; char *start; int num, unit; register struct hpst *st; num = physmem; start = 0; unit = minor(dev) >> 3; if (unit >= NHP) return (ENXIO); #define phys(a,b) ((b)((int)(a)&0x7fffffff)) mi = phys(hpinfo[unit],struct mba_device *); if (mi == 0 || mi->mi_alive == 0) return (ENXIO); mba = phys(mi->mi_hd, struct mba_hd *)->mh_physmba; mba->mba_cr = MBCR_INIT; hpaddr = (struct hpdevice *)&mba->mba_drv[mi->mi_drive]; if ((hpaddr->hpds & HPDS_VV) == 0) { hpaddr->hpcs1 = HP_DCLR|HP_GO; hpaddr->hpcs1 = HP_PRESET|HP_GO; hpaddr->hpof = HPOF_FMT22; } st = &hpst[mi->mi_type]; if (dumplo < 0 || dumplo + num >= st->sizes[minor(dev)&07].nblocks) return (EINVAL); while (num > 0) { register struct pte *hpte = mba->mba_map; register int i; int blk, cn, sn, tn; daddr_t bn; blk = num > DBSIZE ? DBSIZE : num; bn = dumplo + btop(start); cn = bn/st->nspc + st->sizes[minor(dev)&07].cyloff; sn = bn%st->nspc; tn = sn/st->nsect; sn = sn%st->nsect; hpaddr->hpdc = cn; hpaddr->hpda = (tn << 8) + sn; for (i = 0; i < blk; i++) *(int *)hpte++ = (btop(start)+i) | PG_V; mba->mba_sr = -1; mba->mba_bcr = -(blk*NBPG); mba->mba_var = 0; hpaddr->hpcs1 = HP_WCOM | HP_GO; while ((hpaddr->hpds & HPDS_DRY) == 0) ; if (hpaddr->hpds&HPDS_ERR) return (EIO); start += blk*NBPG; num -= blk; } return (0); }