123308Smckusick /* 229264Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 323308Smckusick * All rights reserved. The Berkeley software License Agreement 423308Smckusick * specifies the terms and conditions for redistribution. 523308Smckusick * 6*30538Skarels * @(#)hp.c 7.3 (Berkeley) 02/20/87 723308Smckusick */ 83706Sroot 93706Sroot #ifdef HPDEBUG 103289Swnj int hpdebug; 113706Sroot #endif 123706Sroot #ifdef HPBDEBUG 133706Sroot int hpbdebug; 143706Sroot #endif 1521Sbill 161939Swnj #include "hp.h" 171565Sbill #if NHP > 0 1821Sbill /* 195726Sroot * HP disk driver for RP0x+RMxx+ML11 202827Swnj * 212827Swnj * TODO: 223706Sroot * see if DCLR and/or RELEASE set attention status 2321Sbill */ 249786Ssam #include "../machine/pte.h" 2521Sbill 2617120Sbloom #include "param.h" 2717120Sbloom #include "systm.h" 2830535Skarels #include "dkstat.h" 2917120Sbloom #include "buf.h" 3017120Sbloom #include "conf.h" 3117120Sbloom #include "dir.h" 3230535Skarels #include "file.h" 3317120Sbloom #include "user.h" 3417120Sbloom #include "map.h" 358468Sroot #include "../vax/mtpr.h" 3617120Sbloom #include "vm.h" 3717120Sbloom #include "cmap.h" 3817120Sbloom #include "dkbad.h" 3930535Skarels #include "disklabel.h" 4017120Sbloom #include "ioctl.h" 4117120Sbloom #include "uio.h" 4218411Skarels #include "syslog.h" 4321Sbill 448988Sroot #include "../vax/dkio.h" 4517120Sbloom #include "mbareg.h" 4617120Sbloom #include "mbavar.h" 4717120Sbloom #include "hpreg.h" 4821Sbill 4930535Skarels #define COMPAT_42 5030535Skarels #define B_FORMAT B_XXX 5121Sbill 526927Ssam /* 5330535Skarels * Table of supported Massbus drive types. 5430535Skarels * When using unlabeled packs, slot numbers here 5530535Skarels * are used as indices into the partition tables. 5630535Skarels * Slots are left for those drives divined from other means 576927Ssam * (e.g. SI, AMPEX, etc.). 586927Ssam */ 596927Ssam short hptypes[] = { 606927Ssam #define HPDT_RM03 0 616927Ssam MBDT_RM03, 626927Ssam #define HPDT_RM05 1 636927Ssam MBDT_RM05, 646927Ssam #define HPDT_RP06 2 656927Ssam MBDT_RP06, 666927Ssam #define HPDT_RM80 3 676927Ssam MBDT_RM80, 6813157Ssam #define HPDT_RP04 4 6913157Ssam MBDT_RP04, 7013157Ssam #define HPDT_RP05 5 716927Ssam MBDT_RP05, 7213157Ssam #define HPDT_RP07 6 736927Ssam MBDT_RP07, 7413157Ssam #define HPDT_ML11A 7 756927Ssam MBDT_ML11A, 7613157Ssam #define HPDT_ML11B 8 776927Ssam MBDT_ML11B, 7813157Ssam #define HPDT_9775 9 796927Ssam -1, 8013157Ssam #define HPDT_9730 10 816927Ssam -1, 8213157Ssam #define HPDT_CAPRICORN 11 836927Ssam -1, 8413157Ssam #define HPDT_EAGLE 12 859175Ssam -1, 8613157Ssam #define HPDT_9300 13 8711281Ssam -1, 8813157Ssam #define HPDT_RM02 14 8928908Skarels MBDT_RM02, /* beware, actually mapped */ 9028908Skarels #define HPDT_2361 15 9128908Skarels -1, 926927Ssam 0 936927Ssam }; 9430535Skarels 952978Swnj struct mba_device *hpinfo[NHP]; 9614145Shelge int hpattach(),hpustart(),hpstart(),hpdtint(); 972383Swnj struct mba_driver hpdriver = 982978Swnj { hpattach, 0, hpustart, hpstart, hpdtint, 0, 992978Swnj hptypes, "hp", 0, hpinfo }; 1002383Swnj 1012624Swnj u_char hp_offset[16] = { 1023093Swnj HPOF_P400, HPOF_M400, HPOF_P400, HPOF_M400, 1033093Swnj HPOF_P800, HPOF_M800, HPOF_P800, HPOF_M800, 1043093Swnj HPOF_P1200, HPOF_M1200, HPOF_P1200, HPOF_M1200, 1053093Swnj 0, 0, 0, 0, 10621Sbill }; 10721Sbill 1082624Swnj struct buf rhpbuf[NHP]; 10930535Skarels struct disklabel hplabel[NHP]; 1103706Sroot struct dkbad hpbad[NHP]; 11121Sbill 11210857Ssam struct hpsoftc { 11310857Ssam u_char sc_recal; /* recalibrate state */ 11410857Ssam u_char sc_doseeks; /* perform explicit seeks */ 11530535Skarels int sc_state; /* open fsm */ 11630535Skarels long sc_openpart; /* bit mask of open subunits */ 11710857Ssam daddr_t sc_mlsize; /* ML11 size */ 11825198Skarels int sc_blkdone; /* amount sucessfully transfered */ 11917071Sralph daddr_t sc_badbn; /* replacement block number */ 12010857Ssam } hpsoftc[NHP]; 12110857Ssam 12230535Skarels /* 12330535Skarels * Drive states. Used during steps of open/initialization. 12430535Skarels * States < OPEN (> 0) are transient, during an open operation. 12530535Skarels * OPENRAW is used for unlabeled disks, 12630535Skarels * to inhibit bad-sector forwarding or allow format operations. 12730535Skarels */ 12830535Skarels #define CLOSED 0 /* disk is closed. */ 12930535Skarels #define WANTOPEN 1 /* open requested, not started */ 13030535Skarels #define WANTOPENRAW 2 /* open requested, no label */ 13130535Skarels #define RDLABEL 3 /* reading pack label */ 13230535Skarels #define RDBADTBL 4 /* reading bad-sector table */ 13330535Skarels #define OPEN 5 /* initialized and ready */ 13430535Skarels #define OPENRAW 6 /* open, no label or badsect */ 13530535Skarels 13621Sbill #define b_cylin b_resid 13721Sbill 1385726Sroot /* #define ML11 0 to remove ML11 support */ 13930535Skarels #define ML11(type) ((type) == HPDT_ML11A) 14030535Skarels #define RP06(type) (hptypes[type] <= MBDT_RP06) 14130535Skarels #define RM80(type) ((type) == HPDT_RM80) 1425726Sroot 14324738Sbloom #define hpunit(dev) (minor(dev) >> 3) 14430535Skarels #define hppart(dev) (minor(dev) & 07) 14530535Skarels #define hpminor(unit, part) (((unit) << 3) | (part)) 14630535Skarels 14711202Ssam #define MASKREG(reg) ((reg)&0xffff) 14826375Skarels #ifdef lint 14926375Skarels #define HPWAIT(mi, addr) (hpwait(mi)) 15026375Skarels #else 15118411Skarels #define HPWAIT(mi, addr) (((addr)->hpds & HPDS_DRY) || hpwait(mi)) 15226375Skarels #endif 15311202Ssam 1542978Swnj /*ARGSUSED*/ 1552978Swnj hpattach(mi, slave) 15630535Skarels struct mba_device *mi; 1572604Swnj { 15830535Skarels register int unit = mi->mi_unit; 15910734Ssam 16030535Skarels /* 16130535Skarels * Try to initialize device and read pack label. 16230535Skarels */ 16330535Skarels if (hpinit(hpminor(unit, 0), 0) == 0) { 164*30538Skarels printf(": %s", hplabel[unit].d_typename); 16530535Skarels #ifdef notyet 16630535Skarels addswap(makedev(HPMAJOR, hpminor(unit, 0)), &hplabel[unit]); 16730535Skarels #endif 16830535Skarels } else 169*30538Skarels printf(": offline"); 17010734Ssam } 17110734Ssam 17230535Skarels hpopen(dev, flags) 17330535Skarels dev_t dev; 17430535Skarels int flags; 17510734Ssam { 17630535Skarels register int unit = hpunit(dev); 17730535Skarels register struct hpsoftc *sc; 17830535Skarels register struct disklabel *lp; 17930535Skarels register struct partition *pp; 18030535Skarels struct mba_device *mi; 18130535Skarels int s, error, part = hppart(dev); 18230535Skarels daddr_t start, end; 1836927Ssam 18430535Skarels if (unit >= NHP || (mi = hpinfo[unit]) == 0 || mi->mi_alive == 0) 18530535Skarels return (ENXIO); 18630535Skarels sc = &hpsoftc[unit]; 18730535Skarels lp = &hplabel[unit]; 18830535Skarels 18930535Skarels s = spl5(); 19030535Skarels while (sc->sc_state != OPEN && sc->sc_state != OPENRAW && 19130535Skarels sc->sc_state != CLOSED) 19230535Skarels sleep ((caddr_t)sc, PZERO+1); 19330535Skarels splx(s); 19430535Skarels if (sc->sc_state != OPEN && sc->sc_state != OPENRAW) 19530535Skarels if (error = hpinit(dev, flags)) 19630535Skarels return (error); 19730535Skarels if (part >= lp->d_npartitions) 19830535Skarels return (ENXIO); 1996927Ssam /* 20030535Skarels * Warn if a partion is opened 20130535Skarels * that overlaps another partition which is open 20230535Skarels * unless one is the "raw" partition (whole disk). 2036927Ssam */ 20430535Skarels #define RAWPART 2 /* 'c' partition */ /* XXX */ 20530535Skarels if ((sc->sc_openpart & (1 << part)) == 0 && 20630535Skarels part != RAWPART) { 20730535Skarels pp = &lp->d_partitions[part]; 20830535Skarels start = pp->p_offset; 20930535Skarels end = pp->p_offset + pp->p_size; 21030535Skarels for (pp = lp->d_partitions; 21130535Skarels pp < &lp->d_partitions[lp->d_npartitions]; pp++) { 21230535Skarels if (pp->p_offset + pp->p_size <= start || 21330535Skarels pp->p_offset >= end) 21430535Skarels continue; 21530535Skarels if (pp - lp->d_partitions == RAWPART) 21630535Skarels continue; 21730535Skarels if (sc->sc_openpart & (1 << (pp - lp->d_partitions))) 21830535Skarels log(LOG_WARNING, 21930535Skarels "hp%d%c: overlaps open partition (%c)\n", 22030535Skarels unit, part + 'a', 22130535Skarels pp - lp->d_partitions + 'a'); 2226927Ssam } 22310734Ssam } 22430535Skarels sc->sc_openpart |= 1 << part; 22530535Skarels return (0); 22630535Skarels } 2276927Ssam 22830535Skarels hpclose(dev, flags) 22930535Skarels dev_t dev; 23030535Skarels int flags; 23130535Skarels { 23230535Skarels register int unit = hpunit(dev); 23330535Skarels register struct hpsoftc *sc; 23430535Skarels struct mba_device *mi; 23530535Skarels int s; 23630535Skarels 23730535Skarels sc = &hpsoftc[unit]; 23830535Skarels mi = hpinfo[unit]; 23930535Skarels sc->sc_openpart &= ~(1 << hppart(dev)); 24030535Skarels #ifdef notdef 2416927Ssam /* 24230535Skarels * Should wait for I/O to complete on this partition 24330535Skarels * even if others are open, but wait for work on blkflush(). 2446927Ssam */ 24530535Skarels if (sc->sc_openpart == 0) { 24630535Skarels s = spl5(); 24730535Skarels /* Can't sleep on b_actf, it might be async. */ 24830535Skarels while (mi->mi_tab.b_actf) 24930535Skarels sleep((caddr_t)&mi->mi_tab.b_actf, PZERO - 1); 25030535Skarels splx(s); 25130535Skarels sc->sc_state = CLOSED; 25230535Skarels } 25330535Skarels #endif 25430535Skarels } 25510734Ssam 25630535Skarels hpinit(dev, flags) 25730535Skarels dev_t dev; 25830535Skarels int flags; 25930535Skarels { 26030535Skarels register struct hpsoftc *sc; 26130535Skarels register struct buf *bp; 26230535Skarels register struct disklabel *lp; 26330535Skarels struct disklabel *dlp; 26430535Skarels struct mba_device *mi; 26530535Skarels struct hpdevice *hpaddr; 26630535Skarels struct dkbad *db; 26730535Skarels int unit, i, error = 0; 268*30538Skarels extern int cold; 26928908Skarels 27030535Skarels unit = hpunit(dev); 27130535Skarels sc = &hpsoftc[unit]; 27230535Skarels lp = &hplabel[unit]; 27330535Skarels mi = hpinfo[unit]; 27430535Skarels hpaddr = (struct hpdevice *)mi->mi_drv; 2756927Ssam 27630535Skarels if (flags & O_NDELAY) 27730535Skarels sc->sc_state = WANTOPENRAW; 27830535Skarels else 27930535Skarels sc->sc_state = WANTOPEN; 28010734Ssam /* 28130535Skarels * Use the default sizes until we've read the label, 28230535Skarels * or longer if there isn't one there. 28330535Skarels */ 28430535Skarels lp->d_secsize = DEV_BSIZE; 28530535Skarels lp->d_nsectors = 32; 28630535Skarels lp->d_ntracks = 20; 28730535Skarels lp->d_secpercyl = 32*20; 28830535Skarels lp->d_secperunit = 0x1fffffff; 28930535Skarels lp->d_npartitions = 1; 29030535Skarels lp->d_partitions[0].p_size = 0x1fffffff; 29130535Skarels lp->d_partitions[0].p_offset = 0; 29230535Skarels 29330535Skarels /* 29410734Ssam * Map all ML11's to the same type. Also calculate 29510734Ssam * transfer rates based on device characteristics. 29630535Skarels * Set up dummy label with all that's needed. 29710734Ssam */ 29830535Skarels if (mi->mi_type == MBDT_ML11A || mi->mi_type == MBDT_ML11B) { 29910857Ssam register struct hpsoftc *sc = &hpsoftc[mi->mi_unit]; 30010857Ssam register int trt; 3012604Swnj 30210857Ssam sc->sc_mlsize = hpaddr->hpmr & HPMR_SZ; 3035726Sroot if ((hpaddr->hpmr & HPMR_ARRTYP) == 0) 30410857Ssam sc->sc_mlsize >>= 2; 3055726Sroot if (mi->mi_dk >= 0) { 3065726Sroot trt = (hpaddr->hpmr & HPMR_TRT) >> 8; 3075726Sroot dk_mspw[mi->mi_dk] = 1.0 / (1<<(20-trt)); 3085726Sroot } 30930535Skarels mi->mi_type = MBDT_ML11A; 31030535Skarels lp->d_partitions[0].p_size = sc->sc_mlsize; 31130535Skarels lp->d_secpercyl = sc->sc_mlsize; 31230535Skarels sc->sc_state = WANTOPENRAW; 3136927Ssam } 3142604Swnj 31530535Skarels /* 31630535Skarels * Preset, pack acknowledge will be done in hpstart 31730535Skarels * during first read operation. 31830535Skarels */ 31930535Skarels bp = geteblk(DEV_BSIZE); /* max sector size */ 32030535Skarels bp->b_dev = dev; 32130535Skarels bp->b_blkno = LABELSECTOR; 32230535Skarels bp->b_bcount = DEV_BSIZE; 32330535Skarels bp->b_flags = B_BUSY | B_READ; 32430535Skarels hpstrategy(bp); 32530535Skarels biowait(bp); 32630535Skarels if (bp->b_flags & B_ERROR) { 32730535Skarels error = u.u_error; /* XXX */ 32830535Skarels u.u_error = 0; 32930535Skarels sc->sc_state = CLOSED; 33030535Skarels goto done; 33130535Skarels } 33230535Skarels if (sc->sc_state == OPENRAW) 33330535Skarels goto done; 3348579Sroot 33530535Skarels dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET); 33630535Skarels if (dlp->d_magic == DISKMAGIC && 33730535Skarels dlp->d_magic2 == DISKMAGIC && dkcksum(dlp) == 0) { 33830535Skarels *lp = *dlp; 33930535Skarels } else { 340*30538Skarels if (cold) 341*30538Skarels printf(": no disk label"); 342*30538Skarels else 343*30538Skarels log(LOG_ERR, "hp%d: no disk label\n", unit); 34430535Skarels #ifdef COMPAT_42 34530535Skarels mi->mi_type = hpmaptype(mi, lp); 34630535Skarels #else 34730535Skarels sc->sc_state = OPENRAW; 34830535Skarels goto done; 34930535Skarels #endif 35030535Skarels } 35130535Skarels 35230535Skarels /* 35330535Skarels * Seconds per word = (60 / rpm) / (nsectors * secsize/2) 35430535Skarels */ 35530535Skarels if (mi->mi_dk >= 0 && lp->d_rpm) 35630535Skarels dk_mspw[mi->mi_dk] = 120.0 / 35730535Skarels (lp->d_rpm * lp->d_nsectors * lp->d_secsize); 35830535Skarels /* 35930535Skarels * Read bad sector table into memory. 36030535Skarels */ 36130535Skarels sc->sc_state = RDBADTBL; 36230535Skarels i = 0; 36330535Skarels do { 36430535Skarels u.u_error = 0; /* XXX */ 36530535Skarels bp->b_flags = B_BUSY | B_READ; 36630535Skarels bp->b_blkno = lp->d_secperunit - lp->d_nsectors + i; 36730535Skarels bp->b_bcount = lp->d_secsize; 36830535Skarels bp->b_cylin = lp->d_ncylinders - 1; 36930535Skarels hpstrategy(bp); 37030535Skarels biowait(bp); 37130535Skarels } while ((bp->b_flags & B_ERROR) && (i += 2) < 10 && 37230535Skarels i < lp->d_nsectors); 37330535Skarels db = (struct dkbad *)(bp->b_un.b_addr); 37430535Skarels if ((bp->b_flags & B_ERROR) == 0 && db->bt_mbz == 0 && 37530535Skarels db->bt_flag == 0) { 37630535Skarels hpbad[unit] = *db; 37730535Skarels sc->sc_state = OPEN; 37830535Skarels } else { 37930535Skarels log(LOG_ERR, "hp%d: %s bad-sector file\n", unit, 38030535Skarels (bp->b_flags & B_ERROR) ? "can't read" : "format error in"); 38130535Skarels u.u_error = 0; /* XXX */ 38230535Skarels sc->sc_state = OPENRAW; 38330535Skarels } 38430535Skarels done: 38530535Skarels bp->b_flags = B_INVAL | B_AGE; 38630535Skarels brelse(bp); 38730535Skarels wakeup((caddr_t)sc); 38830535Skarels return (error); 3898579Sroot } 3908579Sroot 39121Sbill hpstrategy(bp) 3922383Swnj register struct buf *bp; 39321Sbill { 3942978Swnj register struct mba_device *mi; 39530535Skarels register struct disklabel *lp; 39630535Skarels register struct hpsoftc *sc; 3972383Swnj register int unit; 39830535Skarels daddr_t sz, maxsz; 39930535Skarels int xunit = hppart(bp->b_dev); 4005432Sroot int s; 40121Sbill 40230535Skarels sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT; 40324738Sbloom unit = hpunit(bp->b_dev); 40424738Sbloom if (unit >= NHP) { 40524738Sbloom bp->b_error = ENXIO; 4062383Swnj goto bad; 40724738Sbloom } 4082383Swnj mi = hpinfo[unit]; 40930535Skarels sc = &hpsoftc[unit]; 41030535Skarels lp = &hplabel[unit]; 41124738Sbloom if (mi == 0 || mi->mi_alive == 0) { 41224738Sbloom bp->b_error = ENXIO; 4132383Swnj goto bad; 41424738Sbloom } 41530535Skarels if (sc->sc_state < OPEN) 41630535Skarels goto q; 41730535Skarels if ((sc->sc_openpart & (1 << xunit)) == 0) { 41830535Skarels bp->b_error = ENODEV; 41930535Skarels goto bad; 42030535Skarels } 42130535Skarels maxsz = lp->d_partitions[xunit].p_size; 42230535Skarels if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) { 42330535Skarels if (bp->b_blkno == maxsz) { 42430535Skarels bp->b_resid = bp->b_bcount; 42530535Skarels goto done; 42624738Sbloom } 42730535Skarels sz = maxsz - bp->b_blkno; 42830535Skarels if (sz <= 0) { 42924738Sbloom bp->b_error = EINVAL; 4305726Sroot goto bad; 43124738Sbloom } 43230535Skarels bp->b_bcount = sz << DEV_BSHIFT; 4335726Sroot } 43430535Skarels bp->b_cylin = (bp->b_blkno + lp->d_partitions[xunit].p_offset) / 43530535Skarels lp->d_secpercyl; 43630535Skarels q: 4375432Sroot s = spl5(); 4382383Swnj disksort(&mi->mi_tab, bp); 4392383Swnj if (mi->mi_tab.b_active == 0) 4402383Swnj mbustart(mi); 4415432Sroot splx(s); 4422383Swnj return; 4432383Swnj 4442383Swnj bad: 4452383Swnj bp->b_flags |= B_ERROR; 44624738Sbloom done: 44730535Skarels biodone(bp); 4482383Swnj return; 44921Sbill } 45021Sbill 4512383Swnj hpustart(mi) 4522978Swnj register struct mba_device *mi; 45321Sbill { 4542624Swnj register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv; 4552383Swnj register struct buf *bp = mi->mi_tab.b_actf; 45630535Skarels register struct disklabel *lp; 45710857Ssam struct hpsoftc *sc = &hpsoftc[mi->mi_unit]; 45821Sbill daddr_t bn; 45916791Skarels int sn, tn, dist; 46021Sbill 46130535Skarels lp = &hplabel[mi->mi_unit]; 4623706Sroot hpaddr->hpcs1 = 0; 4632624Swnj if ((hpaddr->hpcs1&HP_DVA) == 0) 4642383Swnj return (MBU_BUSY); 46525198Skarels 46625198Skarels switch (sc->sc_recal) { 46725198Skarels 46825198Skarels case 1: 46926375Skarels (void)HPWAIT(mi, hpaddr); 47025198Skarels hpaddr->hpdc = bp->b_cylin; 47125198Skarels hpaddr->hpcs1 = HP_SEEK|HP_GO; 47225198Skarels sc->sc_recal++; 47325198Skarels return (MBU_STARTED); 47425198Skarels case 2: 47525198Skarels break; 47625198Skarels } 47725198Skarels sc->sc_recal = 0; 47830535Skarels if ((hpaddr->hpds & HPDS_VV) == 0) { 47930535Skarels if (sc->sc_state == OPEN && lp->d_flags & D_REMOVABLE) { 48030535Skarels if (sc->sc_openpart) 48130535Skarels log(LOG_ERR, "hp%d: volume changed\n", 48230535Skarels mi->mi_unit); 48330535Skarels sc->sc_openpart = 0; 48430535Skarels bp->b_flags |= B_ERROR; 48530535Skarels return (MBU_NEXT); 48630535Skarels } 4872624Swnj hpaddr->hpcs1 = HP_DCLR|HP_GO; 4883140Swnj if (mi->mi_mba->mba_drv[0].mbd_as & (1<<mi->mi_drive)) 4893140Swnj printf("DCLR attn\n"); 4902624Swnj hpaddr->hpcs1 = HP_PRESET|HP_GO; 49130535Skarels if (!ML11(mi->mi_type)) 4925726Sroot hpaddr->hpof = HPOF_FMT22; 4933140Swnj mbclrattn(mi); 49430535Skarels if (sc->sc_state == WANTOPENRAW) { 49530535Skarels sc->sc_state = OPENRAW; 49630535Skarels return (MBU_NEXT); 4975726Sroot } 49830535Skarels if (sc->sc_state == WANTOPEN) 49930535Skarels sc->sc_state = RDLABEL; 50021Sbill } 50125198Skarels if (mi->mi_tab.b_active || mi->mi_hd->mh_ndrive == 1) { 50225198Skarels if (mi->mi_tab.b_errcnt >= 16 && (bp->b_flags & B_READ)) { 50325198Skarels hpaddr->hpof = 50425198Skarels hp_offset[mi->mi_tab.b_errcnt & 017]|HPOF_FMT22; 50525198Skarels hpaddr->hpcs1 = HP_OFFSET|HP_GO; 50626375Skarels (void)HPWAIT(mi, hpaddr); 50725198Skarels mbclrattn(mi); 50825198Skarels } 5092383Swnj return (MBU_DODATA); 51025198Skarels } 51130535Skarels if (ML11(mi->mi_type)) 5125726Sroot return (MBU_DODATA); 5133093Swnj if ((hpaddr->hpds & HPDS_DREADY) != HPDS_DREADY) 5142383Swnj return (MBU_DODATA); 51524738Sbloom bn = bp->b_blkno; 51630535Skarels sn = bn % lp->d_secpercyl; 51730535Skarels tn = sn / lp->d_nsectors; 51830535Skarels sn = sn % lp->d_nsectors; 51911202Ssam if (bp->b_cylin == MASKREG(hpaddr->hpdc)) { 52010908Ssam if (sc->sc_doseeks) 5212383Swnj return (MBU_DODATA); 52216225Skarels dist = sn - (MASKREG(hpaddr->hpla) >> 6) - 1; 5232383Swnj if (dist < 0) 52430535Skarels dist += lp->d_nsectors; 52530535Skarels if (dist > lp->d_maxdist || dist < lp->d_mindist) 5262383Swnj return (MBU_DODATA); 5272614Swnj } else 5282614Swnj hpaddr->hpdc = bp->b_cylin; 52910908Ssam if (sc->sc_doseeks) 5302624Swnj hpaddr->hpcs1 = HP_SEEK|HP_GO; 531305Sbill else { 53230535Skarels sn = (sn + lp->d_nsectors - lp->d_sdist) % lp->d_nsectors; 53316791Skarels hpaddr->hpda = (tn << 8) + sn; 5342624Swnj hpaddr->hpcs1 = HP_SEARCH|HP_GO; 535305Sbill } 5362383Swnj return (MBU_STARTED); 53721Sbill } 53821Sbill 5392383Swnj hpstart(mi) 5402978Swnj register struct mba_device *mi; 54121Sbill { 5422624Swnj register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv; 5432383Swnj register struct buf *bp = mi->mi_tab.b_actf; 54430535Skarels register struct disklabel *lp = &hplabel[mi->mi_unit]; 54510857Ssam struct hpsoftc *sc = &hpsoftc[mi->mi_unit]; 54621Sbill daddr_t bn; 54725198Skarels int sn, tn, cn; 54821Sbill 54930535Skarels if (ML11(mi->mi_type)) 55025198Skarels hpaddr->hpda = bp->b_blkno + sc->sc_blkdone; 5515726Sroot else { 55225198Skarels if (bp->b_flags & B_BAD) { 55325198Skarels bn = sc->sc_badbn; 55430535Skarels cn = bn / lp->d_secpercyl; 55525198Skarels } else { 55625198Skarels bn = bp->b_blkno; 55725198Skarels cn = bp->b_cylin; 55825198Skarels } 55930535Skarels sn = bn % lp->d_secpercyl; 56025198Skarels if ((bp->b_flags & B_BAD) == 0) 56125198Skarels sn += sc->sc_blkdone; 56230535Skarels tn = sn / lp->d_nsectors; 56330535Skarels sn %= lp->d_nsectors; 56430535Skarels cn += tn / lp->d_ntracks; 56530535Skarels tn %= lp->d_ntracks; 5665726Sroot hpaddr->hpda = (tn << 8) + sn; 56725198Skarels hpaddr->hpdc = cn; 5685726Sroot } 56926041Skarels mi->mi_tab.b_bdone = dbtob(sc->sc_blkdone); 57030535Skarels if (bp->b_flags & B_FORMAT) { 5715726Sroot if (bp->b_flags & B_READ) 5725726Sroot return (HP_RHDR|HP_GO); 5735726Sroot else 5745726Sroot return (HP_WHDR|HP_GO); 5755726Sroot } 5765726Sroot return (0); 57721Sbill } 57821Sbill 5793102Swnj hpdtint(mi, mbsr) 5802978Swnj register struct mba_device *mi; 5813102Swnj int mbsr; 58221Sbill { 5832624Swnj register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv; 5842383Swnj register struct buf *bp = mi->mi_tab.b_actf; 5855893Swnj register int er1, er2; 58610857Ssam struct hpsoftc *sc = &hpsoftc[mi->mi_unit]; 58726289Skarels int retry = 0; 58826041Skarels int npf; 58926041Skarels daddr_t bn; 59026041Skarels int bcr; 59121Sbill 59226041Skarels bcr = MASKREG(-mi->mi_mba->mba_bcr); 5933102Swnj if (hpaddr->hpds&HPDS_ERR || mbsr&MBSR_EBITS) { 59414145Shelge er1 = hpaddr->hper1; 59514145Shelge er2 = hpaddr->hper2; 59626041Skarels if (bp->b_flags & B_BAD) { 59726041Skarels npf = bp->b_error; 59826041Skarels bn = sc->sc_badbn; 59926041Skarels } else { 60026041Skarels npf = btop(bp->b_bcount - bcr); 60126041Skarels if (er1 & (HPER1_DCK | HPER1_ECH)) 60226041Skarels npf--; 60326041Skarels bn = bp->b_blkno + npf; 60426041Skarels } 60518411Skarels if (HPWAIT(mi, hpaddr) == 0) 60618411Skarels goto hard; 6073706Sroot #ifdef HPDEBUG 6083289Swnj if (hpdebug) { 6093706Sroot int dc = hpaddr->hpdc, da = hpaddr->hpda; 6103706Sroot 61125198Skarels log(LOG_DEBUG, 61225198Skarels "hperr: bp %x cyl %d blk %d blkdone %d as %o dc %x da %x\n", 61326041Skarels bp, bp->b_cylin, bn, sc->sc_blkdone, 61425198Skarels hpaddr->hpas&0xff, MASKREG(dc), MASKREG(da)); 61526041Skarels log(LOG_DEBUG, 61626041Skarels "errcnt %d mbsr=%b er1=%b er2=%b bcr -%d\n", 61725198Skarels mi->mi_tab.b_errcnt, mbsr, mbsr_bits, 61825198Skarels MASKREG(er1), HPER1_BITS, 61926041Skarels MASKREG(er2), HPER2_BITS, bcr); 6203289Swnj } 6213706Sroot #endif 6225893Swnj if (er1 & HPER1_HCRC) { 6235858Swnj er1 &= ~(HPER1_HCE|HPER1_FER); 6245893Swnj er2 &= ~HPER2_BSE; 6255893Swnj } 62616791Skarels if (er1 & HPER1_WLE) { 62724844Seric log(LOG_WARNING, "hp%d: write locked\n", 62824738Sbloom hpunit(bp->b_dev)); 6292826Swnj bp->b_flags |= B_ERROR; 63030535Skarels } else if (bp->b_flags & B_FORMAT) { 63116791Skarels goto hard; 63230535Skarels } else if (RM80(mi->mi_type) && er2&HPER2_SSE) { 63317071Sralph (void) hpecc(mi, SSE); 63417071Sralph return (MBD_RESTARTED); 63530535Skarels } else if ((er2 & HPER2_BSE) && !ML11(mi->mi_type)) { 6365726Sroot if (hpecc(mi, BSE)) 63711202Ssam return (MBD_RESTARTED); 63811202Ssam goto hard; 63930535Skarels } else if (MASKREG(er1) == HPER1_FER && RP06(mi->mi_type)) { 64016791Skarels if (hpecc(mi, BSE)) 64116791Skarels return (MBD_RESTARTED); 64216791Skarels goto hard; 64317071Sralph } else if ((er1 & (HPER1_DCK | HPER1_ECH)) == HPER1_DCK && 64425198Skarels mi->mi_tab.b_errcnt >= 3) { 64516791Skarels if (hpecc(mi, ECC)) 64616791Skarels return (MBD_RESTARTED); 64725398Skarels /* 64825398Skarels * ECC corrected. Only log retries below 64925398Skarels * if we got errors other than soft ECC 65025398Skarels * (as indicated by additional retries). 65125398Skarels */ 65225398Skarels if (mi->mi_tab.b_errcnt == 3) 65325398Skarels mi->mi_tab.b_errcnt = 0; 65430535Skarels } else if ((er1 & HPER1_HCRC) && !ML11(mi->mi_type) && 65530535Skarels hpecc(mi, BSE)) { 65624780Skarels /* 65724780Skarels * HCRC means the header is screwed up and the sector 65824780Skarels * might well exist in the bad sector table, 65924780Skarels * better check.... 66024780Skarels */ 66124780Skarels return (MBD_RESTARTED); 6622826Swnj } else if (++mi->mi_tab.b_errcnt > 27 || 66330535Skarels (ML11(mi->mi_type) && mi->mi_tab.b_errcnt > 15) || 6643102Swnj mbsr & MBSR_HARD || 6655858Swnj er1 & HPER1_HARD || 66630535Skarels (!ML11(mi->mi_type) && (er2 & HPER2_HARD))) { 6673706Sroot hard: 66826041Skarels bp->b_blkno = bn; /* XXX */ 6692925Swnj harderr(bp, "hp"); 6703271Swnj if (mbsr & (MBSR_EBITS &~ (MBSR_DTABT|MBSR_MBEXC))) 6713271Swnj printf("mbsr=%b ", mbsr, mbsr_bits); 6723706Sroot printf("er1=%b er2=%b", 67314145Shelge MASKREG(hpaddr->hper1), HPER1_BITS, 67414145Shelge MASKREG(hpaddr->hper2), HPER2_BITS); 67530535Skarels if (bp->b_flags & B_FORMAT) 67614134Shelge printf(" (hdr i/o)"); 6773706Sroot printf("\n"); 6782826Swnj bp->b_flags |= B_ERROR; 67917071Sralph bp->b_flags &= ~B_BAD; 6802826Swnj } else 6812826Swnj retry = 1; 6822826Swnj hpaddr->hpcs1 = HP_DCLR|HP_GO; 68325506Skarels if (retry && (mi->mi_tab.b_errcnt & 07) == 4) { 6842826Swnj hpaddr->hpcs1 = HP_RECAL|HP_GO; 68510857Ssam sc->sc_recal = 1; 68625198Skarels return (MBD_REPOSITION); 68721Sbill } 6882826Swnj } 6893706Sroot #ifdef HPDEBUG 6903289Swnj else 69110857Ssam if (hpdebug && sc->sc_recal) { 69225198Skarels log(LOG_DEBUG, 69325198Skarels "recal %d errcnt %d mbsr=%b er1=%b er2=%b\n", 69425198Skarels sc->sc_recal, mi->mi_tab.b_errcnt, mbsr, mbsr_bits, 6953289Swnj hpaddr->hper1, HPER1_BITS, 6963289Swnj hpaddr->hper2, HPER2_BITS); 6973289Swnj } 6983706Sroot #endif 69926375Skarels (void)HPWAIT(mi, hpaddr); 70025198Skarels if (retry) 7012892Swnj return (MBD_RETRY); 7023640Swnj if (mi->mi_tab.b_errcnt >= 16) { 7033093Swnj /* 7043093Swnj * This is fast and occurs rarely; we don't 7053093Swnj * bother with interrupts. 7063093Swnj */ 7072624Swnj hpaddr->hpcs1 = HP_RTC|HP_GO; 70826375Skarels (void)HPWAIT(mi, hpaddr); 7092383Swnj mbclrattn(mi); 71021Sbill } 71125398Skarels if (mi->mi_tab.b_errcnt && (bp->b_flags & B_ERROR) == 0) 71225198Skarels log(LOG_INFO, "hp%d%c: %d retries %sing sn%d\n", 71325198Skarels hpunit(bp->b_dev), 'a'+(minor(bp->b_dev)&07), 71425198Skarels mi->mi_tab.b_errcnt, 71525198Skarels (bp->b_flags & B_READ) ? "read" : "writ", 71625198Skarels (bp->b_flags & B_BAD) ? 71725198Skarels sc->sc_badbn : bp->b_blkno + sc->sc_blkdone); 71817071Sralph if ((bp->b_flags & B_BAD) && hpecc(mi, CONT)) 71917071Sralph return (MBD_RESTARTED); 72025198Skarels sc->sc_blkdone = 0; 72126041Skarels bp->b_resid = bcr; 72230535Skarels if (!ML11(mi->mi_type)) { 7235726Sroot hpaddr->hpof = HPOF_FMT22; 7245726Sroot hpaddr->hpcs1 = HP_RELEASE|HP_GO; 7255726Sroot } 7262383Swnj return (MBD_DONE); 72721Sbill } 72821Sbill 72918411Skarels /* 73018411Skarels * Wait (for a bit) for a drive to come ready; 73118411Skarels * returns nonzero on success. 73218411Skarels */ 73318411Skarels hpwait(mi) 73418411Skarels register struct mba_device *mi; 73518411Skarels { 73618411Skarels register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv; 73718411Skarels register i = 100000; 73818411Skarels 73918411Skarels while ((hpaddr->hpds & HPDS_DRY) == 0 && --i) 74018411Skarels DELAY(10); 74118411Skarels if (i == 0) 74218411Skarels printf("hp%d: intr, not ready\n", mi->mi_unit); 74318411Skarels return (i); 74418411Skarels } 74518411Skarels 7467738Sroot hpread(dev, uio) 7472624Swnj dev_t dev; 7487738Sroot struct uio *uio; 74921Sbill { 75024738Sbloom register int unit = hpunit(dev); 75121Sbill 7522624Swnj if (unit >= NHP) 7538156Sroot return (ENXIO); 7548156Sroot return (physio(hpstrategy, &rhpbuf[unit], dev, B_READ, minphys, uio)); 75521Sbill } 75621Sbill 7577831Sroot hpwrite(dev, uio) 7582624Swnj dev_t dev; 7597831Sroot struct uio *uio; 76021Sbill { 76124738Sbloom register int unit = hpunit(dev); 76221Sbill 7632624Swnj if (unit >= NHP) 7648156Sroot return (ENXIO); 7658156Sroot return (physio(hpstrategy, &rhpbuf[unit], dev, B_WRITE, minphys, uio)); 76621Sbill } 76721Sbill 7687635Ssam hpioctl(dev, cmd, data, flag) 7695726Sroot dev_t dev; 7705726Sroot int cmd; 7717635Ssam caddr_t data; 7725726Sroot int flag; 7735726Sroot { 77430535Skarels int unit = hpunit(dev); 77530535Skarels register struct disklabel *lp; 77630535Skarels register struct format_op *fop; 77730535Skarels int error = 0; 77830535Skarels int hpformat(); 7795726Sroot 78030535Skarels lp = &hplabel[unit]; 78130535Skarels 7825726Sroot switch (cmd) { 7837635Ssam 78430535Skarels case DIOCGDINFO: 78530535Skarels *(struct disklabel *)data = *lp; 78630535Skarels break; 7875726Sroot 78830535Skarels case DIOCGDINFOP: 78930535Skarels *(struct disklabel **)data = lp; 79030535Skarels break; 79130535Skarels 79230535Skarels case DIOCSDINFO: 79330535Skarels if ((flag & FWRITE) == 0) 79430535Skarels error = EBADF; 79530535Skarels else 79630535Skarels *lp = *(struct disklabel *)data; 79730535Skarels break; 79830535Skarels 79930535Skarels case DIOCWDINFO: 80030535Skarels if ((flag & FWRITE) == 0) { 80130535Skarels error = EBADF; 80230535Skarels break; 80330535Skarels } 80430535Skarels { 80530535Skarels struct buf *bp; 80630535Skarels struct disklabel *dlp; 80730535Skarels 80830535Skarels *lp = *(struct disklabel *)data; 80930535Skarels bp = geteblk(lp->d_secsize); 81030535Skarels bp->b_dev = dev; 81130535Skarels bp->b_blkno = LABELSECTOR; 81230535Skarels bp->b_bcount = lp->d_secsize; 81330535Skarels bp->b_flags = B_READ; 81430535Skarels dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET); 81530535Skarels hpstrategy(bp); 81630535Skarels biowait(bp); 81730535Skarels if (bp->b_flags & B_ERROR) { 81830535Skarels error = u.u_error; /* XXX */ 81930535Skarels u.u_error = 0; 82030535Skarels goto bad; 82130535Skarels } 82230535Skarels *dlp = *lp; 82330535Skarels bp->b_flags = B_WRITE; 82430535Skarels hpstrategy(bp); 82530535Skarels biowait(bp); 82630535Skarels if (bp->b_flags & B_ERROR) { 82730535Skarels error = u.u_error; /* XXX */ 82830535Skarels u.u_error = 0; 82930535Skarels } 83030535Skarels bad: 83130535Skarels brelse(bp); 83230535Skarels } 83330535Skarels break; 83430535Skarels 83530535Skarels #ifdef notyet 83630535Skarels case DIOCWFORMAT: 83730535Skarels if ((flag & FWRITE) == 0) { 83830535Skarels error = EBADF; 83930535Skarels break; 84030535Skarels } 84130535Skarels { 84230535Skarels struct uio auio; 84330535Skarels struct iovec aiov; 84430535Skarels 84530535Skarels fop = (struct format_op *)data; 84630535Skarels aiov.iov_base = fop->df_buf; 84730535Skarels aiov.iov_len = fop->df_count; 84830535Skarels auio.uio_iov = &aiov; 84930535Skarels auio.uio_iovcnt = 1; 85030535Skarels auio.uio_resid = fop->df_count; 85130535Skarels auio.uio_segflg = 0; 85230535Skarels auio.uio_offset = fop->df_startblk * lp->d_secsize; 85330535Skarels error = physio(hpformat, &rhpbuf[unit], dev, B_WRITE, 85430535Skarels minphys, &auio); 85530535Skarels fop->df_count -= auio.uio_resid; 85630535Skarels fop->df_reg[0] = sc->sc_status; 85730535Skarels fop->df_reg[1] = sc->sc_error; 85830535Skarels } 85930535Skarels break; 86030535Skarels #endif 86130535Skarels 8625726Sroot default: 86330535Skarels error = ENOTTY; 86430535Skarels break; 8655726Sroot } 86630535Skarels return (0); 8675726Sroot } 8685726Sroot 86930535Skarels hpformat(bp) 87030535Skarels struct buf *bp; 87130535Skarels { 87230535Skarels 87330535Skarels bp->b_flags |= B_FORMAT; 87430535Skarels return (hpstrategy(bp)); 87530535Skarels } 87630535Skarels 8773706Sroot hpecc(mi, flag) 8782978Swnj register struct mba_device *mi; 8793706Sroot int flag; 88021Sbill { 8812383Swnj register struct mba_regs *mbp = mi->mi_mba; 8822624Swnj register struct hpdevice *rp = (struct hpdevice *)mi->mi_drv; 8832383Swnj register struct buf *bp = mi->mi_tab.b_actf; 88430535Skarels register struct disklabel *lp = &hplabel[mi->mi_unit]; 88517071Sralph struct hpsoftc *sc = &hpsoftc[mi->mi_unit]; 8863706Sroot int npf, o; 8872383Swnj int bn, cn, tn, sn; 888914Sbill int bcr; 88921Sbill 89018411Skarels bcr = MASKREG(-mbp->mba_bcr); 89117071Sralph if (bp->b_flags & B_BAD) 8923706Sroot npf = bp->b_error; 89328987Skarels else { 89428987Skarels npf = bp->b_bcount - bcr; 89528987Skarels /* 89628987Skarels * Watch out for fractional sector at end of transfer; 89728987Skarels * want to round up if finished, otherwise round down. 89828987Skarels */ 89928987Skarels if (bcr == 0) 90028987Skarels npf += 511; 90128987Skarels npf = btodb(npf); 90228987Skarels } 903420Sbill o = (int)bp->b_un.b_addr & PGOFSET; 90424738Sbloom bn = bp->b_blkno; 905420Sbill cn = bp->b_cylin; 90630535Skarels sn = bn % lp->d_secpercyl + npf; 90730535Skarels tn = sn / lp->d_nsectors; 90830535Skarels sn %= lp->d_nsectors; 90930535Skarels cn += tn / lp->d_ntracks; 91030535Skarels tn %= lp->d_ntracks; 91124187Skarels bn += npf; 9123706Sroot switch (flag) { 91310856Ssam case ECC: { 9143706Sroot register int i; 9153706Sroot caddr_t addr; 9163706Sroot struct pte mpte; 9173706Sroot int bit, byte, mask; 9183706Sroot 9193706Sroot npf--; /* because block in error is previous block */ 92018411Skarels bn--; 92117071Sralph if (bp->b_flags & B_BAD) 92217071Sralph bn = sc->sc_badbn; 92324844Seric log(LOG_WARNING, "hp%d%c: soft ecc sn%d\n", hpunit(bp->b_dev), 92417071Sralph 'a'+(minor(bp->b_dev)&07), bn); 92511202Ssam mask = MASKREG(rp->hpec2); 92611202Ssam i = MASKREG(rp->hpec1) - 1; /* -1 makes 0 origin */ 9273706Sroot bit = i&07; 9283706Sroot i = (i&~07)>>3; 9293706Sroot byte = i + o; 93026041Skarels while (i < 512 && (int)dbtob(npf)+i < bp->b_bcount && bit > -11) { 9313706Sroot mpte = mbp->mba_map[npf+btop(byte)]; 9323706Sroot addr = ptob(mpte.pg_pfnum) + (byte & PGOFSET); 9333706Sroot putmemc(addr, getmemc(addr)^(mask<<bit)); 9343706Sroot byte++; 9353706Sroot i++; 9363706Sroot bit -= 8; 9373706Sroot } 93818411Skarels if (bcr == 0) 9393706Sroot return (0); 9403847Sroot npf++; 9413706Sroot break; 9423706Sroot } 9433706Sroot 9443706Sroot case SSE: 9453706Sroot rp->hpof |= HPOF_SSEI; 94617071Sralph if (bp->b_flags & B_BAD) { 94717071Sralph bn = sc->sc_badbn; 94817071Sralph goto fixregs; 94917071Sralph } 9503706Sroot mbp->mba_bcr = -(bp->b_bcount - (int)ptob(npf)); 9513706Sroot break; 9523706Sroot 9533706Sroot case BSE: 95430535Skarels if (sc->sc_state == OPENRAW) 95530535Skarels return (0); 95617071Sralph if (rp->hpof & HPOF_SSEI) 95717071Sralph sn++; 9583706Sroot #ifdef HPBDEBUG 9593706Sroot if (hpbdebug) 96025198Skarels log(LOG_DEBUG, "hpecc, BSE: bn %d cn %d tn %d sn %d\n", bn, cn, tn, sn); 9613706Sroot #endif 96217071Sralph if (bp->b_flags & B_BAD) 96317071Sralph return (0); 9643706Sroot if ((bn = isbad(&hpbad[mi->mi_unit], cn, tn, sn)) < 0) 96511202Ssam return (0); 9663706Sroot bp->b_flags |= B_BAD; 9673706Sroot bp->b_error = npf + 1; 96817071Sralph rp->hpof &= ~HPOF_SSEI; 96930535Skarels bn = lp->d_ncylinders * lp->d_secpercyl - 97030535Skarels lp->d_nsectors - 1 - bn; 97117071Sralph sc->sc_badbn = bn; 97217071Sralph fixregs: 97330535Skarels cn = bn / lp->d_secpercyl; 97430535Skarels sn = bn % lp->d_secpercyl; 97530535Skarels tn = sn / lp->d_nsectors; 97630535Skarels sn %= lp->d_nsectors; 97726375Skarels bcr = bp->b_bcount - (int)ptob(npf); 97826375Skarels bcr = MIN(bcr, 512); 97926375Skarels mbp->mba_bcr = -bcr; 9803706Sroot #ifdef HPBDEBUG 9813706Sroot if (hpbdebug) 98225198Skarels log(LOG_DEBUG, "revector to cn %d tn %d sn %d\n", cn, tn, sn); 9833706Sroot #endif 9843706Sroot break; 9853706Sroot 9863706Sroot case CONT: 9873706Sroot #ifdef HPBDEBUG 9883706Sroot if (hpbdebug) 98925198Skarels log(LOG_DEBUG, "hpecc, CONT: bn %d cn %d tn %d sn %d\n", bn,cn,tn,sn); 9903706Sroot #endif 9913706Sroot bp->b_flags &= ~B_BAD; 99224780Skarels if ((int)ptob(npf) >= bp->b_bcount) 99324780Skarels return (0); 9943706Sroot mbp->mba_bcr = -(bp->b_bcount - (int)ptob(npf)); 9953706Sroot break; 9963706Sroot } 9973706Sroot rp->hpcs1 = HP_DCLR|HP_GO; 99817071Sralph if (rp->hpof & HPOF_SSEI) 9992883Swnj sn++; 1000420Sbill rp->hpdc = cn; 1001420Sbill rp->hpda = (tn<<8) + sn; 1002420Sbill mbp->mba_sr = -1; 10033706Sroot mbp->mba_var = (int)ptob(npf) + o; 10043706Sroot rp->hpcs1 = bp->b_flags&B_READ ? HP_RCOM|HP_GO : HP_WCOM|HP_GO; 10053706Sroot mi->mi_tab.b_errcnt = 0; /* error has been corrected */ 100625198Skarels sc->sc_blkdone = npf; 1007420Sbill return (1); 100821Sbill } 10092362Swnj 10102362Swnj #define DBSIZE 20 10112362Swnj 10122362Swnj hpdump(dev) 10132362Swnj dev_t dev; 10142362Swnj { 10152978Swnj register struct mba_device *mi; 10162383Swnj register struct mba_regs *mba; 10172624Swnj struct hpdevice *hpaddr; 10182362Swnj char *start; 10192383Swnj int num, unit; 102030535Skarels register struct disklabel *lp; 10212362Swnj 10222362Swnj num = maxfree; 10232362Swnj start = 0; 102424738Sbloom unit = hpunit(dev); 10252827Swnj if (unit >= NHP) 10262827Swnj return (ENXIO); 10272383Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 10282978Swnj mi = phys(hpinfo[unit],struct mba_device *); 10292827Swnj if (mi == 0 || mi->mi_alive == 0) 10302827Swnj return (ENXIO); 103130535Skarels lp = &hplabel[unit]; 10322383Swnj mba = phys(mi->mi_hd, struct mba_hd *)->mh_physmba; 10333102Swnj mba->mba_cr = MBCR_INIT; 10342624Swnj hpaddr = (struct hpdevice *)&mba->mba_drv[mi->mi_drive]; 10353093Swnj if ((hpaddr->hpds & HPDS_VV) == 0) { 10362624Swnj hpaddr->hpcs1 = HP_DCLR|HP_GO; 10372624Swnj hpaddr->hpcs1 = HP_PRESET|HP_GO; 10383093Swnj hpaddr->hpof = HPOF_FMT22; 10392362Swnj } 104024224Sbloom if (dumplo < 0) 10412827Swnj return (EINVAL); 104230535Skarels if (dumplo + num >= lp->d_partitions[hppart(dev)].p_size) 104330535Skarels num = lp->d_partitions[hppart(dev)].p_size - dumplo; 10442362Swnj while (num > 0) { 10452383Swnj register struct pte *hpte = mba->mba_map; 10462362Swnj register int i; 10472383Swnj int blk, cn, sn, tn; 10482362Swnj daddr_t bn; 10492362Swnj 10502362Swnj blk = num > DBSIZE ? DBSIZE : num; 10512362Swnj bn = dumplo + btop(start); 105230535Skarels cn = (bn + lp->d_partitions[hppart(dev)].p_offset) / 105330535Skarels lp->d_secpercyl; 105430535Skarels sn = bn % lp->d_secpercyl; 105530535Skarels tn = sn / lp->d_nsectors; 105630535Skarels sn = sn % lp->d_nsectors; 10572362Swnj hpaddr->hpdc = cn; 10582362Swnj hpaddr->hpda = (tn << 8) + sn; 10592362Swnj for (i = 0; i < blk; i++) 10602362Swnj *(int *)hpte++ = (btop(start)+i) | PG_V; 10612383Swnj mba->mba_sr = -1; 10622383Swnj mba->mba_bcr = -(blk*NBPG); 10632383Swnj mba->mba_var = 0; 10642624Swnj hpaddr->hpcs1 = HP_WCOM | HP_GO; 10653093Swnj while ((hpaddr->hpds & HPDS_DRY) == 0) 106616791Skarels DELAY(10); 10673093Swnj if (hpaddr->hpds&HPDS_ERR) 10682827Swnj return (EIO); 10692362Swnj start += blk*NBPG; 10702362Swnj num -= blk; 10712362Swnj } 10722362Swnj return (0); 10732362Swnj } 107412506Ssam 107512506Ssam hpsize(dev) 107612506Ssam dev_t dev; 107712506Ssam { 107830535Skarels register int unit = hpunit(dev); 107912506Ssam struct mba_device *mi; 108012506Ssam 108130535Skarels if (unit >= NHP || (mi = hpinfo[unit]) == 0 || mi->mi_alive == 0 || 108230535Skarels hpsoftc[unit].sc_state != OPEN) 108312506Ssam return (-1); 108430535Skarels return ((int)hplabel[unit].d_partitions[hppart(dev)].p_size); 108512506Ssam } 108630535Skarels 108730535Skarels #ifdef COMPAT_42 108830535Skarels /* 108930535Skarels * Compatibility code to fake up pack label 109030535Skarels * for unlabeled disks. 109130535Skarels */ 109230535Skarels struct size { 109330535Skarels daddr_t nblocks; 109430535Skarels int cyloff; 109530535Skarels } rp06_sizes[8] = { 109630535Skarels 15884, 0, /* A=cyl 0 thru 37 */ 109730535Skarels 33440, 38, /* B=cyl 38 thru 117 */ 109830535Skarels 340670, 0, /* C=cyl 0 thru 814 */ 109930535Skarels 15884, 118, /* D=cyl 118 thru 155 */ 110030535Skarels 55936, 156, /* E=cyl 156 thru 289 */ 110130535Skarels 219384, 290, /* F=cyl 290 thru 814 */ 110230535Skarels 291280, 118, /* G=cyl 118 thru 814 */ 110330535Skarels 0, 0, 110430535Skarels }, rp05_sizes[8] = { 110530535Skarels 15884, 0, /* A=cyl 0 thru 37 */ 110630535Skarels 33440, 38, /* B=cyl 38 thru 117 */ 110730535Skarels 171798, 0, /* C=cyl 0 thru 410 */ 110830535Skarels 15884, 118, /* D=cyl 118 thru 155 */ 110930535Skarels 55936, 156, /* E=cyl 156 thru 289 */ 111030535Skarels 50512, 290, /* F=cyl 290 thru 410 */ 111130535Skarels 122408, 118, /* G=cyl 118 thru 410 */ 111230535Skarels 0, 0, 111330535Skarels }, rm03_sizes[8] = { 111430535Skarels 15884, 0, /* A=cyl 0 thru 99 */ 111530535Skarels 33440, 100, /* B=cyl 100 thru 308 */ 111630535Skarels 131680, 0, /* C=cyl 0 thru 822 */ 111730535Skarels 15884, 309, /* D=cyl 309 thru 408 */ 111830535Skarels 55936, 409, /* E=cyl 409 thru 758 */ 111930535Skarels 10144, 759, /* F=cyl 759 thru 822 */ 112030535Skarels 82144, 309, /* G=cyl 309 thru 822 */ 112130535Skarels 0, 0, 112230535Skarels }, rm05_sizes[8] = { 112330535Skarels 15884, 0, /* A=cyl 0 thru 26 */ 112430535Skarels 33440, 27, /* B=cyl 27 thru 81 */ 112530535Skarels 500384, 0, /* C=cyl 0 thru 822 */ 112630535Skarels 15884, 562, /* D=cyl 562 thru 588 */ 112730535Skarels 55936, 589, /* E=cyl 589 thru 680 */ 112830535Skarels 86240, 681, /* F=cyl 681 thru 822 */ 112930535Skarels 158592, 562, /* G=cyl 562 thru 822 */ 113030535Skarels 291346, 82, /* H=cyl 82 thru 561 */ 113130535Skarels }, rm80_sizes[8] = { 113230535Skarels 15884, 0, /* A=cyl 0 thru 36 */ 113330535Skarels 33440, 37, /* B=cyl 37 thru 114 */ 113430535Skarels 242606, 0, /* C=cyl 0 thru 558 */ 113530535Skarels 15884, 115, /* D=cyl 115 thru 151 */ 113630535Skarels 55936, 152, /* E=cyl 152 thru 280 */ 113730535Skarels 120559, 281, /* F=cyl 281 thru 558 */ 113830535Skarels 192603, 115, /* G=cyl 115 thru 558 */ 113930535Skarels 0, 0, 114030535Skarels }, rp07_sizes[8] = { 114130535Skarels 15884, 0, /* A=cyl 0 thru 9 */ 114230535Skarels 66880, 10, /* B=cyl 10 thru 51 */ 114330535Skarels 1008000, 0, /* C=cyl 0 thru 629 */ 114430535Skarels 15884, 235, /* D=cyl 235 thru 244 */ 114530535Skarels 307200, 245, /* E=cyl 245 thru 436 */ 114630535Skarels 308650, 437, /* F=cyl 437 thru 629 */ 114730535Skarels 631850, 235, /* G=cyl 235 thru 629 */ 114830535Skarels 291346, 52, /* H=cyl 52 thru 234 */ 114930535Skarels }, cdc9775_sizes[8] = { 115030535Skarels 15884, 0, /* A=cyl 0 thru 12 */ 115130535Skarels 66880, 13, /* B=cyl 13 thru 65 */ 115230535Skarels 1077760, 0, /* C=cyl 0 thru 841 */ 115330535Skarels 15884, 294, /* D=cyl 294 thru 306 */ 115430535Skarels 307200, 307, /* E=cyl 307 thru 546 */ 115530535Skarels 377440, 547, /* F=cyl 547 thru 841 */ 115630535Skarels 701280, 294, /* G=cyl 294 thru 841 */ 115730535Skarels 291346, 66, /* H=cyl 66 thru 293 */ 115830535Skarels }, cdc9730_sizes[8] = { 115930535Skarels 15884, 0, /* A=cyl 0 thru 49 */ 116030535Skarels 33440, 50, /* B=cyl 50 thru 154 */ 116130535Skarels 263360, 0, /* C=cyl 0 thru 822 */ 116230535Skarels 15884, 155, /* D=cyl 155 thru 204 */ 116330535Skarels 55936, 205, /* E=cyl 205 thru 379 */ 116430535Skarels 141664, 380, /* F=cyl 380 thru 822 */ 116530535Skarels 213664, 155, /* G=cyl 155 thru 822 */ 116630535Skarels 0, 0, 116730535Skarels }, capricorn_sizes[8] = { 116830535Skarels 15884, 0, /* A=cyl 0 thru 31 */ 116930535Skarels 33440, 32, /* B=cyl 32 thru 97 */ 117030535Skarels 524288, 0, /* C=cyl 0 thru 1023 */ 117130535Skarels 15884, 668, /* D=cyl 668 thru 699 */ 117230535Skarels 55936, 700, /* E=cyl 700 thru 809 */ 117330535Skarels 109472, 810, /* F=cyl 810 thru 1023 */ 117430535Skarels 182176, 668, /* G=cyl 668 thru 1023 */ 117530535Skarels 291346, 98, /* H=cyl 98 thru 667 */ 117630535Skarels }, eagle_sizes[8] = { 117730535Skarels 15884, 0, /* A=cyl 0 thru 16 */ 117830535Skarels 66880, 17, /* B=cyl 17 thru 86 */ 117930535Skarels 808320, 0, /* C=cyl 0 thru 841 */ 118030535Skarels 15884, 391, /* D=cyl 391 thru 407 */ 118130535Skarels 307200, 408, /* E=cyl 408 thru 727 */ 118230535Skarels 109296, 728, /* F=cyl 728 thru 841 */ 118330535Skarels 432816, 391, /* G=cyl 391 thru 841 */ 118430535Skarels 291346, 87, /* H=cyl 87 thru 390 */ 118530535Skarels }, ampex_sizes[8] = { 118630535Skarels 15884, 0, /* A=cyl 0 thru 26 */ 118730535Skarels 33440, 27, /* B=cyl 27 thru 81 */ 118830535Skarels 495520, 0, /* C=cyl 0 thru 814 */ 118930535Skarels 15884, 562, /* D=cyl 562 thru 588 */ 119030535Skarels 55936, 589, /* E=cyl 589 thru 680 */ 119130535Skarels 81312, 681, /* F=cyl 681 thru 814 */ 119230535Skarels 153664, 562, /* G=cyl 562 thru 814 */ 119330535Skarels 291346, 82, /* H=cyl 82 thru 561 */ 119430535Skarels }, fj2361_sizes[8] = { 119530535Skarels 15884, 0, /* A=cyl 0 thru 12 */ 119630535Skarels 66880, 13, /* B=cyl 13 thru 65 */ 119730535Skarels 1077760, 0, /* C=cyl 0 thru 841 */ 119830535Skarels 15884, 294, /* D=cyl 294 thru 306 */ 119930535Skarels 307200, 307, /* E=cyl 307 thru 546 */ 120030535Skarels 377408, 547, /* F=cyl 547 thru 841 */ 120130535Skarels 701248, 294, /* G=cyl 294 thru 841 */ 120230535Skarels 291346, 66, /* H=cyl 66 thru 293 */ 120330535Skarels }; 120430535Skarels 120530535Skarels /* 120630535Skarels * These variable are all measured in sectors. 120730535Skarels * Sdist is how much to "lead" in the search for a desired sector 120830535Skarels * (i.e. if want N, search for N-sdist.) 120930535Skarels * Maxdist and mindist define the region right before our desired sector within 121030535Skarels * which we don't bother searching. We don't search when we are already less 121130535Skarels * then maxdist and more than mindist sectors "before" our desired sector. 121230535Skarels * Maxdist should be >= sdist. 121330535Skarels * 121430535Skarels * Beware, sdist, mindist and maxdist are not well tuned 121530535Skarels * for many of the drives listed in this table. 121630535Skarels * Try patching things with something i/o intensive 121730535Skarels * running and watch iostat. 121830535Skarels */ 121930535Skarels struct hpst { 122030535Skarels short nsect; /* # sectors/track */ 122130535Skarels short ntrak; /* # tracks/cylinder */ 122230535Skarels short nspc; /* # sector/cylinders */ 122330535Skarels short ncyl; /* # cylinders */ 122430535Skarels struct size *sizes; /* partition tables */ 122530535Skarels short sdist; /* seek distance metric */ 122630535Skarels short maxdist; /* boundaries of non-searched area */ 122730535Skarels short mindist; /* preceding the target sector */ 122830535Skarels char *name; /* name of disk type */ 122930535Skarels } hpst[] = { 123030535Skarels { 32, 5, 32*5, 823, rm03_sizes, 7, 4, 1, "RM03" }, 123130535Skarels { 32, 19, 32*19, 823, rm05_sizes, 7, 4, 1, "RM05" }, 123230535Skarels { 22,19, 22*19, 815, rp06_sizes, 7, 4, 1, "RP06"}, 123330535Skarels { 31, 14, 31*14, 559, rm80_sizes, 7, 4, 1, "RM80"}, 123430535Skarels { 22, 19, 22*19, 411, rp05_sizes, 7, 4, 1, "RP04"}, 123530535Skarels { 22, 19, 22*19, 411, rp05_sizes, 7, 4, 1, "RP05"}, 123630535Skarels { 50, 32, 50*32, 630, rp07_sizes, 15, 8, 3, "RP07"}, 123730535Skarels { 1, 1, 1, 1, 0, 0, 0, 0, "ML11A"}, 123830535Skarels { 1, 1, 1, 1, 0, 0, 0, 0, "ML11B" }, 123930535Skarels { 32, 40, 32*40, 843, cdc9775_sizes, 7, 4, 1, "9775" }, 124030535Skarels { 32, 10, 32*10, 823, cdc9730_sizes, 7, 4, 1, "9730-160" }, 124130535Skarels { 32, 16, 32*16, 1024, capricorn_sizes,10,4, 3, "capricorn" }, 124230535Skarels { 48, 20, 48*20, 842, eagle_sizes, 15, 8, 3, "eagle" }, 124330535Skarels { 32, 19, 32*19, 815, ampex_sizes, 7, 4, 1, "9300" }, 124430535Skarels { 64, 20, 64*20, 842, fj2361_sizes, 15, 8, 3, "2361" }, 124530535Skarels }; 124630535Skarels 124730535Skarels /* 124830535Skarels * Map apparent MASSBUS drive type into manufacturer 124930535Skarels * specific configuration. For SI controllers this is done 125030535Skarels * based on codes in the serial number register. For 125130535Skarels * EMULEX controllers, the track and sector attributes are 125230535Skarels * used when the drive type is an RM02 (not supported by DEC). 125330535Skarels */ 125430535Skarels hpmaptype(mi, lp) 125530535Skarels register struct mba_device *mi; 125630535Skarels register struct disklabel *lp; 125730535Skarels { 125830535Skarels register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv; 125930535Skarels register int type = mi->mi_type; 126030535Skarels register struct hpst *st; 126130535Skarels register i; 126230535Skarels 126330535Skarels /* 126430535Skarels * Model-byte processing for SI controllers. 126530535Skarels * NB: Only deals with RM03 and RM05 emulations. 126630535Skarels */ 126730535Skarels if (type == HPDT_RM03 || type == HPDT_RM05) { 126830535Skarels int hpsn = hpaddr->hpsn; 126930535Skarels 127030535Skarels if ((hpsn & SIMB_LU) == mi->mi_drive) 127130535Skarels switch ((hpsn & SIMB_MB) & ~(SIMB_S6|SIRM03|SIRM05)) { 127230535Skarels 127330535Skarels case SI9775D: 127430535Skarels type = HPDT_9775; 127530535Skarels break; 127630535Skarels 127730535Skarels case SI9730D: 127830535Skarels type = HPDT_9730; 127930535Skarels break; 128030535Skarels 128130535Skarels case SI9766: 128230535Skarels type = HPDT_RM05; 128330535Skarels break; 128430535Skarels 128530535Skarels case SI9762: 128630535Skarels type = HPDT_RM03; 128730535Skarels break; 128830535Skarels 128930535Skarels case SICAPD: 129030535Skarels type = HPDT_CAPRICORN; 129130535Skarels break; 129230535Skarels 129330535Skarels case SI9751D: 129430535Skarels type = HPDT_EAGLE; 129530535Skarels break; 129630535Skarels } 129730535Skarels } 129830535Skarels 129930535Skarels /* 130030535Skarels * EMULEX SC750 or SC780. Poke the holding register. 130130535Skarels */ 130230535Skarels if (type == HPDT_RM02) { 130330535Skarels int nsectors, ntracks, ncyl; 130430535Skarels 130530535Skarels hpaddr->hpof = HPOF_FMT22; 130630535Skarels mbclrattn(mi); 130730535Skarels hpaddr->hpcs1 = HP_NOP; 130830535Skarels hpaddr->hphr = HPHR_MAXTRAK; 130930535Skarels ntracks = MASKREG(hpaddr->hphr) + 1; 131030535Skarels DELAY(100); 131130535Skarels hpaddr->hpcs1 = HP_NOP; 131230535Skarels hpaddr->hphr = HPHR_MAXSECT; 131330535Skarels nsectors = MASKREG(hpaddr->hphr) + 1; 131430535Skarels DELAY(100); 131530535Skarels hpaddr->hpcs1 = HP_NOP; 131630535Skarels hpaddr->hphr = HPHR_MAXCYL; 131730535Skarels ncyl = MASKREG(hpaddr->hphr) + 1; 131830535Skarels for (type = 0; hptypes[type] != 0; type++) 131930535Skarels if (hpst[type].nsect == nsectors && 132030535Skarels hpst[type].ntrak == ntracks && 132130535Skarels hpst[type].ncyl == ncyl) 132230535Skarels break; 132330535Skarels 132430535Skarels if (hptypes[type] == 0) { 132530535Skarels printf("hp%d: %d sectors, %d tracks, %d cylinders: unknown device\n", 132630535Skarels mi->mi_unit, nsectors, ntracks, ncyl); 132730535Skarels type = HPDT_RM02; 132830535Skarels } 132930535Skarels hpaddr->hpcs1 = HP_DCLR|HP_GO; 133030535Skarels mbclrattn(mi); /* conservative */ 133130535Skarels } 133230535Skarels 133330535Skarels /* 133430535Skarels * set up minimal disk label. 133530535Skarels */ 133630535Skarels st = &hpst[type]; 133730535Skarels lp->d_nsectors = st->nsect; 133830535Skarels lp->d_ntracks = st->ntrak; 133930535Skarels lp->d_secpercyl = st->nspc; 134030535Skarels lp->d_ncylinders = st->ncyl; 134130535Skarels lp->d_secperunit = st->nspc * st->ncyl; 134230535Skarels lp->d_sdist = st->sdist; 134330535Skarels lp->d_mindist = st->mindist; 134430535Skarels lp->d_maxdist = st->maxdist; 134530535Skarels bcopy(hpst[type].name, lp->d_typename, sizeof(lp->d_typename)); 134630535Skarels lp->d_npartitions = 8; 134730535Skarels for (i = 0; i < 8; i++) { 134830535Skarels lp->d_partitions[i].p_offset = st->sizes[i].cyloff * 134930535Skarels lp->d_secpercyl; 135030535Skarels lp->d_partitions[i].p_size = st->sizes[i].nblocks; 135130535Skarels } 135230535Skarels return (type); 135330535Skarels } 135430535Skarels #endif COMPAT_42 13551565Sbill #endif 1356