4.3BSD-Reno/src/sys/vaxuba/up.c.disklabel
/*
* Copyright (c) 1982, 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*
* %W% (Berkeley) %D%
*/
/*
* up.c, driver for Emulex SC21, SC31 disk controllers
* with support for disklabels.
* UNTESTED.
*/
#ifdef UPDEBUG
int updebug;
#endif
#ifdef UPBDEBUG
int upbdebug;
#endif
#include "up.h"
#if NSC > 0
/*
* UNIBUS disk driver with:
* overlapped seeks,
* ECC recovery, and
* bad sector forwarding.
*
* TODO:
* Check that offset recovery code works
*/
#include "../machine/pte.h"
#include "param.h"
#include "systm.h"
#include "dkstat.h"
#include "dkbad.h"
#include "ioctl.h"
#include "disklabel.h"
#include "buf.h"
#include "conf.h"
#include "dir.h"
#include "file.h"
#include "user.h"
#include "map.h"
#include "vm.h"
#include "cmap.h"
#include "uio.h"
#include "kernel.h"
#include "syslog.h"
#include "stat.h"
#include "../vax/mtpr.h"
#include "../vax/cpu.h"
#include "../vax/nexus.h"
#include "ubavar.h"
#include "ubareg.h"
#include "upreg.h"
#define COMPAT_42
#define B_FORMAT B_XXX
#define upunit(dev) (minor(dev) >> 3)
#define uppart(dev) (minor(dev) & 07)
#define upminor(unit, part) (((unit) << 3) | (part))
int upprobe(), upslave(), upattach(), updgo(), upintr();
struct uba_ctlr *upminfo[NSC];
struct uba_device *updinfo[NUP];
#define UPIPUNITS 8
struct uba_device *upip[NSC][UPIPUNITS]; /* fuji w/fixed head gives n,n+4 */
u_short upstd[] = { 0776700, 0774400, 0776300, 0 };
struct uba_driver scdriver =
{ upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo };
struct buf uputab[NUP];
char upinit[NUP];
u_char up_offset[16] = {
UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400,
UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800,
UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200,
0, 0, 0, 0
};
struct buf bupbuf[NUP];
struct dkbad upbad[NUP];
struct upsoftc {
u_char sc_recal; /* recalibrate state */
u_char sc_doseeks; /* perform explicit seeks */
#ifdef COMPAT_42
u_char sc_hdr; /* next i/o includes header */
#endif
short sc_state; /* open fsm */
short sc_wlabel; /* label sector is currently writeable */
u_long sc_openpart; /* bit mask of open subunits */
u_long sc_copenpart; /* bit mask of open character subunits */
u_long sc_bopenpart; /* bit mask of open block subunits */
int sc_blkdone; /* amount sucessfully transfered */
daddr_t sc_badbn; /* replacement block number */
short sc_softas; /* bitmask of drives needing attention */
short sc_ndrive; /* count of drives */
int sc_wticks; /* watchdog timer */
int sc_status; /* copy of drive status reg after format */
int sc_upds; /* copy of upds reg after format */
int sc_er1; /* copy of error reg 1 after format */
int sc_er2; /* copy of error reg 2 after format */
} upsoftc[NSC];
/*
* Drive states. Used during steps of open/initialization.
* States < OPEN (> 0) are transient, during an open operation.
* OPENRAW is used for unlabeled disks,
* to inhibit bad-sector forwarding or allow format operations.
*/
#define CLOSED 0 /* disk is closed. */
#define WANTOPEN 1 /* open requested, not started */
#define WANTOPENRAW 2 /* open requested, no label */
#define RDLABEL 3 /* reading pack label */
#define RDBADTBL 4 /* reading bad-sector table */
#define OPEN 5 /* initialized and ready */
#define OPENRAW 6 /* open, no label or badsect */
#define b_cylin b_resid /* cyl number, for disksort */
#define b_bufsiz b_bdone /* amount done, in ui_tab only */
int upwstart, upwatch(); /* Have started guardian */
int upseek;
int upwaitdry;
upprobe(reg)
caddr_t reg;
{
register int br, cvec;
#ifdef lint
br = 0; cvec = br; br = cvec; upintr(0);
#endif
((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY;
DELAY(10);
((struct updevice *)reg)->upcs1 = 0;
return (sizeof (struct updevice));
}
upslave(ui, reg)
struct uba_device *ui;
caddr_t reg;
{
register struct updevice *upaddr = (struct updevice *)reg;
upaddr->upcs1 = 0; /* conservative */
upaddr->upcs2 = ui->ui_slave;
upaddr->upcs1 = UP_NOP|UP_GO;
if (upaddr->upcs2&UPCS2_NED) {
upaddr->upcs1 = UP_DCLR|UP_GO;
return (0);
}
return (1);
}
upattach(ui)
register struct uba_device *ui;
{
register int unit = ui->ui_unit;
if (upwstart == 0) {
timeout(upwatch, (caddr_t)0, hz);
upwstart++;
}
upip[ui->ui_ctlr][ui->ui_slave] = ui;
up_softc[ui->ui_ctlr].sc_ndrive++;
/*
* Try to initialize device and read pack label.
*/
if (upinit(upminor(unit, 0), 0) == 0) {
printf(": %s", uplabel[unit].d_typename);
#ifdef notyet
addswap(makedev(UPMAJOR, upminor(unit, 0)), &uplabel[unit]);
#endif
} else
printf(": offline");
}
upopen(dev, flags, fmt)
dev_t dev;
int flags, fmt;
{
register int unit = upunit(dev);
register struct upsoftc *sc;
register struct disklabel *lp;
register struct partition *pp;
struct uba_device *ui;
int s, error, part = uppart(dev), mask = 1 << part;
daddr_t start, end;
if (unit >= NUP || (ui = updinfo[unit]) == 0 || ui->ui_alive == 0)
return (ENXIO);
sc = &upsoftc[unit];
lp = &uplabel[unit];
s = spl5();
while (sc->sc_state != OPEN && sc->sc_state != OPENRAW &&
sc->sc_state != CLOSED)
sleep ((caddr_t)sc, PZERO+1);
splx(s);
if (sc->sc_state != OPEN && sc->sc_state != OPENRAW)
if (error = upinit(dev, flags))
return (error);
if (part >= lp->d_npartitions)
return (ENXIO);
/*
* Warn if a partion is opened
* that overlaps another partition which is open
* unless one is the "raw" partition (whole disk).
*/
#define RAWPART 2 /* 'c' partition */ /* XXX */
if ((sc->sc_openpart & mask) == 0 && part != RAWPART) {
pp = &lp->d_partitions[part];
start = pp->p_offset;
end = pp->p_offset + pp->p_size;
for (pp = lp->d_partitions;
pp < &lp->d_partitions[lp->d_npartitions]; pp++) {
if (pp->p_offset + pp->p_size <= start ||
pp->p_offset >= end)
continue;
if ((s = pp - lp->d_partitions) == RAWPART)
continue;
if (sc->sc_openpart & (1 << s))
log(LOG_WARNING,
"up%d%c: overlaps open partition (%c)\n",
unit, part + 'a', s + 'a');
}
}
switch (fmt) {
case S_IFCHR:
sc->sc_copenpart |= mask;
break;
case S_IFBLK:
sc->sc_bopenpart |= mask;
break;
}
sc->sc_openpart |= mask;
return (0);
}
/* ARGSUSED */
upclose(dev, flags, fmt)
dev_t dev;
int flags, fmt;
{
register int unit = upunit(dev);
register struct upsoftc *sc = &upsoftc[unit];
struct uba_device *ui = updinfo[unit];
int s;
switch (fmt) {
case S_IFCHR:
sc->sc_copenpart &= ~(1 << uppart(dev));
break;
case S_IFBLK:
sc->sc_bopenpart &= ~(1 << uppart(dev));
break;
}
if (sc->sc_openpart)
sc->sc_openpart = sc->sc_copenpart | sc->sc_bopenpart;
/*
* If this was the last open partition on the drive, then
* we must wait for the i/o to complete (so caller knows its
* ok to turn the drive off). If not the last, no problem,
* as some other partition must still be active. (Potential
* problem is some part of the "drive" can be spun down
* while leaving other part of same drive running ..)
*
* (this will also happen if we have disabled the drive because
* of an unanticipated pack change, but no harm there)
*/
if (sc->sc_openpart == 0) {
s = spl5();
while (ui->ui_tab.b_actf)
sleep((caddr_t)sc, PZERO - 1);
splx(s);
sc->sc_state = CLOSED;
}
return (0);
}
upinit(dev, flags)
dev_t dev;
int flags;
{
register struct upsoftc *sc;
register struct buf *bp;
register struct disklabel *lp;
struct uba_device *ui;
struct dkbad *db;
char *msg, *readdisklabel();
int unit, i, error = 0;
extern int cold;
unit = upunit(dev);
sc = &upsoftc[unit];
lp = &uplabel[unit];
ui = updinfo[unit];
sc->sc_state = WANTOPEN;
/*
* Obtain the physical drive characteristics from the
* controller, for use until the label overrides them.
*/
upphysical(ui->ui_addr, lp);
if (flags & O_NDELAY)
goto raw;
/*
* Preset, pack acknowledge will be done in upstart
* during first read operation.
*/
if (msg = readdisklabel(dev, upstrategy, lp)) {
if (cold)
printf(": %s", msg);
else
log(LOG_ERR, "up%d: %s\n", unit, msg);
#ifdef COMPAT_42
if (upmaptype(ui, lp) == 0)
#endif
goto raw;
}
/*
* Seconds per word = (60 / rpm) / (nsectors * secsize/2)
*/
if (ui->ui_dk >= 0 && lp->d_rpm)
dk_mspw[ui->ui_dk] = 120.0 /
(lp->d_rpm * lp->d_nsectors * lp->d_secsize);
/*
* Read bad sector table into memory.
*/
bp = geteblk(DEV_BSIZE); /* max sector size */
bp->b_dev = dev;
sc->sc_state = RDBADTBL;
i = 0;
do {
u.u_error = 0; /* XXX */
bp->b_flags = B_BUSY | B_READ;
bp->b_blkno = lp->d_secperunit - lp->d_nsectors + i;
bp->b_bcount = lp->d_secsize;
bp->b_cylin = lp->d_ncylinders - 1;
upstrategy(bp);
biowait(bp);
} while ((bp->b_flags & B_ERROR) && (i += 2) < 10 &&
i < lp->d_nsectors);
db = (struct dkbad *)(bp->b_un.b_addr);
if ((bp->b_flags & B_ERROR) == 0 && db->bt_mbz == 0 &&
db->bt_flag == 0) {
upbad[unit] = *db;
sc->sc_state = OPEN;
} else {
log(LOG_ERR, "up%d: %s bad-sector file\n", unit,
(bp->b_flags & B_ERROR) ? "can't read" : "format error in");
u.u_error = 0; /* XXX */
sc->sc_state = OPENRAW;
}
bp->b_flags = B_INVAL | B_AGE;
brelse(bp);
done:
wakeup((caddr_t)sc);
return (error);
raw:
sc->sc_state = OPENRAW;
wakeup((caddr_t)sc);
return (error);
}
/*
* obtain the physical drive layout from the controller prom
* (we know this isn't a dec controller, so we can assume sanity)
*/
upphysical(upaddr, lp)
register struct updevice *upaddr;
register struct disklabel *lp;
{
upaddr->upcs1 = 0;
upaddr->upcs2 = ui->ui_slave;
upaddr->uphr = UPHR_MAXTRAK;
lp->d_ntracks = upaddr->uphr + 1;
upaddr->uphr = UPHR_MAXSECT;
lp->d_nsectors = upaddr->uphr + 1;
upaddr->uphr = UPHR_MAXCYL;
lp->d_ncylinders = upaddr->uphr + 1;
lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
lp->d_npartitions = 1; /* ??? (allow label write) */
lp->d_partitions[0].p_offset = 0;
lp->d_partitions[0].p_size = lp->d_secperunit;
lp->d_secsize = DEV_BSIZE; /* assume this */
upaddr->upcs2 = UPCS2_CLR;
}
upstrategy(bp)
register struct buf *bp;
{
register struct uba_device *ui;
register struct disklabel *lp;
register struct upsoftc *sc;
register int unit;
register struct buf *dp;
long bn, sz;
daddr_t maxsz;
int xunit = uppart(bp->b_dev);
int s;
sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;
unit = hpunit(bp->b_dev);
if (unit >= NUP) {
bp->b_error = ENXIO;
goto bad;
}
ui = updinfo[unit];
if (ui == 0 || ui->ui_alive == 0) {
bp->b_error = ENXIO;
goto bad;
}
sc = &upsoftc[unit];
lp = &uplabel[unit];
if (sc->sc_state < OPEN)
goto q;
if ((sc->sc_openpart & (1 << xunit)) == 0) {
bp->b_error = ENODEV;
goto bad;
}
maxsz = lp->d_partitions[xunit].p_size;
if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) {
if (bp->b_blkno == maxsz) {
bp->b_resid = bp->b_bcount;
goto done;
}
sz = maxsz - bp->b_blkno;
if (sz <= 0) {
bp->b_error = EINVAL;
goto bad;
}
bp->b_bcount = sz << DEV_BSHIFT;
}
bp->b_cylin = (bp->b_blkno + lp->d_partitions[xunit].p_offset) /
lp->d_secpercyl;
q:
s = spl5();
dp = &uputab[ui->ui_unit];
disksort(dp, bp);
if (dp->b_active == 0) {
(void) upustart(ui);
bp = &ui->ui_mi->um_tab;
if (bp->b_actf && bp->b_active == 0)
(void) upstart(ui->ui_mi);
}
splx(s);
return;
bad:
bp->b_flags |= B_ERROR;
done:
biodone(bp);
return;
}
/*
* Unit start routine.
* Seek the drive to be where the data is
* and then generate another interrupt
* to actually start the transfer.
* If there is only one drive on the controller,
* or we are very close to the data, don't
* bother with the search. If called after
* searching once, don't bother to look where
* we are, just queue for transfer (to avoid
* positioning forever without transferrring.)
*/
upustart(ui)
register struct uba_device *ui;
{
register struct buf *bp, *dp;
register struct uba_ctlr *um;
register struct updevice *upaddr;
register struct disklabel *lp;
struct upsoftc *sc = &upsoftc[ui->ui_unit];
daddr_t bn;
int sn, tn, dist;
/*
* The SC21 cancels commands if you just say
* cs1 = UP_IE
* so we are cautious about handling of cs1.
* Also don't bother to clear as bits other than in upintr().
*/
int didie = 0;
if (ui == 0)
return (0);
um = ui->ui_mi;
dk_busy &= ~(1<<ui->ui_dk);
dp = &uputab[ui->ui_unit];
retry:
if ((bp = dp->b_actf) == NULL)
return (0);
/*
* If the controller is active, just remember
* that this device would like to be positioned...
* if we tried to position now we would confuse the SC21.
*/
if (um->um_tab.b_active) {
up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave;
return (0);
}
/*
* If we have already positioned this drive,
* then just put it on the ready queue.
*/
if (dp->b_active)
goto done;
dp->b_active = 1;
lp = &uplabel[ui->ui_unit];
upaddr = (struct updevice *)um->um_addr;
upaddr->upcs2 = ui->ui_slave;
switch (sc->sc_recal) {
case 1:
(void)HPWAIT(mi, hpaddr);
upaddr->updc = bp->b_cylin;
upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO;
sc->sc_recal++;
return (1);
case 2:
break;
}
sc->sc_recal = 0;
/*
* If drive has just come up,
* setup the pack.
*/
if ((upaddr->upds & UPDS_VV) == 0) {
struct buf *bbp = &bupbuf[ui->ui_unit];
if (sc->sc_state == OPEN && lp->d_flags & D_REMOVABLE) {
if (sc->sc_openpart)
log(LOG_ERR, "up%d: volume changed\n",
ui->ui_unit);
sc->sc_openpart = 0;
do {
dp->b_actf = bp->b_forw;
bp->b_flags |= B_ERROR;
bp->b_errno = ENXIO;
iodone(bp);
} while (bp = dp->b_actf);
return (0);
}
upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO;
upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO;
upaddr->upof = UPOF_FMT22;
if (sc->sc_state == WANTOPENRAW) {
sc->sc_state = OPENRAW;
return (1);
}
if (sc->sc_state == WANTOPEN)
sc->sc_state = RDLABEL;
didie = 1;
}
/*
* If drive is offline, forget about positioning.
*/
if ((upaddr->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL))
goto done;
/*
* If there is only one drive,
* dont bother searching.
*/
if (up_softc[um->um_ctlr].sc_ndrive == 1)
goto done;
/*
* Figure out where this transfer is going to
* and see if we are close enough to justify not searching.
*/
st = &upst[ui->ui_type];
bn = bp->b_blkno;
sn = bn % lp->d_secpercyl;
tn = sn / lp->d_nsectors;
sn = sn % lp->d_nsectors;
if (bp->b_cylin == upaddr->updc) {
if (sc->sc_doseeks)
goto done; /* Ok just to be on-cylinder */
dist = sn - (upaddr->upla>>6) - 1;
if (dist < 0)
dist += lp->d_nsectors;
if (dist <= lp->d_maxdist && dist >= lp->d_mindist)
goto done;
} else
upaddr->updc = bp->b_cylin;
/*
* Not on cylinder at correct position,
* seek/search.
*/
if (sc->sc_doseeks)
upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO;
else {
sn = (sn + lp->d_nsectors - lp->d_sdist) % lp->d_nsectors;
upaddr->upda = sn;
upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO;
}
didie = 1;
/*
* Mark unit busy for iostat.
*/
if (ui->ui_dk >= 0) {
dk_busy |= 1<<ui->ui_dk;
dk_seek[ui->ui_dk]++;
}
goto out;
done:
/*
* Device is ready to go.
* Put it on the ready queue for the controller
* (unless its already there.)
*/
if (dp->b_active != 2) {
dp->b_forw = NULL;
if (um->um_tab.b_actf == NULL)
um->um_tab.b_actf = dp;
else
um->um_tab.b_actl->b_forw = dp;
um->um_tab.b_actl = dp;
dp->b_active = 2;
}
out:
return (didie);
}
/*
* Start up a transfer on a drive.
*/
upstart(um)
register struct uba_ctlr *um;
{
register struct buf *bp, *dp;
register struct uba_device *ui;
register struct updevice *upaddr;
register struct disklabel *lp = &uplabel[ui->ui_unit];
struct upsoftc *sc = &upsoftc[ui->ui_unit];
daddr_t bn;
int cn, dn, sn, tn, cmd, waitdry;
loop:
/*
* Pull a request off the controller queue
*/
if ((dp = um->um_tab.b_actf) == NULL)
return (0);
if ((bp = dp->b_actf) == NULL) {
um->um_tab.b_actf = dp->b_forw;
goto loop;
}
/*
* Mark controller busy, and
* determine destination of this request.
*/
um->um_tab.b_active++;
ui = updinfo[upunit(bp->b_dev)];
bn = bp->b_blkno;
dn = ui->ui_slave;
st = &upst[ui->ui_type];
sn = bn%st->nspc;
tn = sn/st->nsect;
sn %= st->nsect;
upaddr = (struct updevice *)ui->ui_addr;
/*
* Select drive if not selected already.
*/
if ((upaddr->upcs2&07) != dn)
upaddr->upcs2 = dn;
/*
* Check that it is ready and online
*/
waitdry = 0;
while ((upaddr->upds&UPDS_DRY) == 0) {
log(LOG_ERR, "up%d: ds wait ds=%o\n", upunit(bp->b_dev),
upaddr->upds);
if (++waitdry > 512)
break;
upwaitdry++;
}
if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) {
/*
* this should be "log()", but log with split
* messages is very messy, and we also depend here
* on there being a real (measureable) time taken
* doing the printf, to give the drive a chance to
* recover .. printf polls the terminal, so takes ages
*/
printf("up%d: not ready", upunit(bp->b_dev));
if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) {
printf("\n");
um->um_tab.b_active = 0;
um->um_tab.b_errcnt = 0;
dp->b_actf = bp->av_forw;
dp->b_active = 0;
bp->b_flags |= B_ERROR;
iodone(bp);
goto loop;
}
/*
* Oh, well, sometimes this
* happens, for reasons unknown.
*/
printf(" (flakey)\n");
}
/*
* Setup for the transfer, and get in the
* UNIBUS adaptor queue.
*/
if (bp->b_flags & B_BAD) {
bn = sc->sc_badbn;
cn = bn / lp->d_secpercyl;
} else {
bn = bp->b_blkno;
cn = bp->b_cylin;
}
sn = bn % lp->d_secpercyl;
if ((bp->b_flags & B_BAD) == 0)
sn += sc->sc_blkdone;
tn = sn / lp->d_nsectors;
sn %= lp->d_nsectors;
cn += tn / lp->d_ntracks;
tn %= lp->d_ntracks;
upaddr->updc = cn;
upaddr->upda = (tn << 8) + sn;
if (bp->b_bcount >= 0)
upaddr->upwc = (-bp->b_bcount + ui->ui_tab.b_bdone) /
sizeof (short);
else
upaddr->upwc = (bp->b_wcount + ui->ui_tab.b_bdone) /
sizeof (short);
switch (bp->b_flags & (B_READ|B_WRITE|B_FORMAT)) {
case B_READ:
cmd = UP_IE|UP_RCOM|UP_GO;
break;
case B_WRITE:
cmd = UP_IE|UP_WCOM|UP_GO;
break;
case B_READ|B_FORMAT:
cmd = UP_IE|UP_RHDR|UP_GO;
break;
case B_WRITE|B_FORMAT:
cmd = UP_IE|UP_WHDR|UP_GO;
break;
}
um->um_cmd = cmd;
ui->ui_tab.b_bdone = dbtob(sc->sc_blkdone);
(void) ubago(ui);
return (1);
}
/*
* Now all ready to go, stuff the registers.
*/
updgo(um)
struct uba_ctlr *um;
{
register struct updevice *upaddr = (struct updevice *)um->um_addr;
um->um_tab.b_active = 2; /* should now be 2 */
upaddr->upba = um->um_ubinfo;
upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300);
}
/*
* Handle a disk interrupt.
*/
upintr(sc21)
register sc21;
{
register struct buf *bp, *dp;
register struct uba_ctlr *um = upminfo[sc21];
register struct uba_device *ui;
register struct updevice *upaddr = (struct updevice *)um->um_addr;
register unit;
struct up_softc *sc = &up_softc[um->um_ctlr];
int as = (upaddr->upas & 0377) | sc->sc_softas;
int needie = 1, waitdry;
sc->sc_wticks = 0;
sc->sc_softas = 0;
/*
* If controller wasn't transferring, then this is an
* interrupt for attention status on seeking drives.
* Just service them.
*/
if (um->um_tab.b_active != 2 && !sc->sc_recal) {
if (upaddr->upcs1 & UP_TRE)
upaddr->upcs1 = UP_TRE;
goto doattn;
}
um->um_tab.b_active = 1;
/*
* Get device and block structures, and a pointer
* to the uba_device for the drive. Select the drive.
*/
dp = um->um_tab.b_actf;
bp = dp->b_actf;
ui = updinfo[upunit(bp->b_dev)];
dk_busy &= ~(1 << ui->ui_dk);
if ((upaddr->upcs2&07) != ui->ui_slave)
upaddr->upcs2 = ui->ui_slave;
/*
* Check for and process errors on
* either the drive or the controller.
*/
if ((upaddr->upds&UPDS_ERR) || (upaddr->upcs1&UP_TRE)) {
er1 = upaddr->uper1;
er2 = upaddr->uper2;
if (bp->b_flags & B_BAD) {
npf = bp->b_error;
bn = sc->sc_badbn;
} else {
npf = btop(bp->b_bcount + upaddr->upwc * sizeof(short));
if (er1 & (UPER_DCK | UPER_ECH))
npf--;
bn = bp->b_blkno + npf;
}
if (UPWAIT(upaddr, upunit(bp->b_dev)) == 0)
goto hard;
#ifdef UPDEBUG
if (updebug) {
log(LOG_DEBUG,
"uperr: bp %x cyl %d blk %d blkdone %d as %o dc %x da %x\n",
bp, bp->b_cylin, bn, sc->sc_blkdone,
upaddr->upas, upaddr->updc, upaddr->upda);
log(LOG_DEBUG,
"errcnt %d er1 %b er2 %b wc -%d (bc %d)\n",
um->um_tab.b_errcnt, er1, UPER1_BITS,
er2, UPER2_BITS, -up->upwc,-up->upwc*sizeof(short));
}
#endif
if (er1 & UPER1_HCRC) {
er1 &= ~(UPER1_HCE|UPER1_FER);
er2 &= ~UPER2_BSE;
}
if (er1 & UPER1_WLE) {
/*
* Give up on write locked devices
* immediately.
*/
log(LOG_WARNING, "up%d: write locked\n",
upunit(bp->b_dev));
bp->b_flags |= B_ERROR;
} else if (bp->b_flags & B_FORMAT) {
goto hard;
} else if (er2 & UPER2_BSE) {
if (upecc(ui, BSW))
return;
goto hard;
} else if ((er1 & (UPER1_DCK|UPER1_ECH)) == UPER1_DCK &&
um->um_tab.b_errcnt >= 3) {
if (upecc(ui, ECC))
return;
/* see comment in hp.c */
if (ui->ui_tab.b_errcnt == 3)
ui->ui_tab.b_errcnt = 0;
} else if (er1 & UPER1_HCRC && upecc(ui, BSE)) {
return;
} else if (++um->um_tab.b_errcnt > 27 || er1 & HPER1_HARD) {
hard:
bp->b_blkno = bn; /* XXX */
harderr(bp, "up");
printf("cn=%d tn=%d sn=%d cs2=%b er1=%b er2=%b",
upaddr->updc, ((upaddr->upda)>>8)&077,
(upaddr->upda)&037,
upaddr->upcs2, UPCS2_BITS,
upaddr->uper1, UPER1_BITS,
upaddr->uper2, UPER2_BITS);
if (bp->b_flags & B_FORMAT)
printf(" (hdr i/o)");
printf("\n");
bp->b_flags |= B_ERROR;
bp->b_flags &= ~B_BAD;
} 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;
}
}
#ifdef UPDEBUG
else if (updebug && sc->sc_recal) {
log(LOG_DEBUG, "up: recal %d errcnt %d er1=%b er2=%b\n",
sc->sc_recal, um->um_tab.b_errcnt,
upaddr->uper1, UPER1_BITS,
upaddr->uper2, UPER2_BITS);
}
#endif
/*
* 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));
sc->sc_blkdone = 0;
if (sc->sc_openpart == 0)
wakeup((caddr_t)sc);
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((long)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;
}
upioctl(dev, cmd, data, flag)
dev_t dev;
int cmd;
caddr_t data;
int flag;
{
int unit = upunit(dev);
register struct disklabel *lp;
register struct format_op *fop;
int error = 0;
int upformat();
lp = &uplabel[unit];
switch (cmd) {
case DIOCGDINFO:
*(struct disklabel *)data = *lp;
break;
case DIOCGPART:
((struct partinfo *)data)->disklab = lp;
((struct partinfo *)data)->part =
&lp->d_partitions[uppart(dev)];
break;
case DIOCSDINFO:
if ((flag & FWRITE) == 0)
error = EBADF;
else
*lp = *(struct disklabel *)data;
break;
case DIOCWDINFO:
if ((flag & FWRITE) == 0) {
error = EBADF;
break;
}
{
struct buf *bp;
struct disklabel *dlp;
*lp = *(struct disklabel *)data;
bp = geteblk(lp->d_secsize);
bp->b_dev = makedev(major(dev), upminor(upunit(dev), 0));
bp->b_blkno = LABELSECTOR;
bp->b_bcount = lp->d_secsize;
bp->b_flags = B_READ;
dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET);
upstrategy(bp);
biowait(bp);
if (bp->b_flags & B_ERROR) {
error = u.u_error; /* XXX */
u.u_error = 0;
goto bad;
}
*dlp = *lp;
bp->b_flags = B_WRITE;
upstrategy(bp);
biowait(bp);
if (bp->b_flags & B_ERROR) {
error = u.u_error; /* XXX */
u.u_error = 0;
}
bad:
brelse(bp);
break;
}
#ifdef notyet
case DIOCWFORMAT:
if ((flag & FWRITE) == 0) {
error = EBADF;
break;
}
{
struct uio auio;
struct iovec aiov;
fop = (struct format_op *)data;
aiov.iov_base = fop->df_buf;
aiov.iov_len = fop->df_count;
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
auio.uio_resid = fop->df_count;
auio.uio_segflg = 0;
auio.uio_offset = fop->df_startblk * lp->d_secsize;
error = physio(upformat, &rupbuf[unit], dev, B_WRITE,
minphys, &auio);
fop->df_count -= auio.uio_resid;
fop->df_reg[0] = sc->sc_status;
fop->df_reg[1] = sc->sc_error;
}
break;
#endif
default:
error = ENOTTY;
break;
}
return (error);
}
upformat(bp)
struct buf *bp;
{
bp->b_flags |= B_FORMAT;
return (upstrategy(bp));
}
/*
* 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 disklabel *lp = &hplabel[mi->mi_unit];
struct uba_regs *ubp = ui->ui_hd->uh_uba;
struct hpsoftc *sc = &hpsoftc[mi->mi_unit];
register int i;
caddr_t addr;
int reg, bit, byte, npf, mask, o, cmd, ubaddr;
int bn, cn, tn, sn;
int bcr;
/*
* 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.
*/
bcr = -up->upwc * sizeof(short);
if (flag == CONT)
npf = bp->b_error;
else {
npf = bp->b_bcount - bcr;
/*
* Watch out for fractional sector at end of transfer;
* want to round up if finished, otherwise round down.
*/
if (bcr == 0)
npf += 511;
npf = btodb(npf);
}
reg = btop(um->um_ubinfo&0x3ffff) + npf;
o = (int)bp->b_un.b_addr & PGOFSET;
mask = up->upec2;
#ifdef UPECCDEBUG
if (upeccdebug)
log(LOG_DEBUG, "npf %d reg %x o %d mask %o pos %d\n",
npf, reg, o, mask, up->upec1);
#endif
bn = bp->b_blkno;
cn = bp->b_cylin;
sn = bn % lp->d_secpercyl + npf;
tn = sn / lp->d_nsectors;
sn %= lp->d_nsectors;
cn += tn / lp->d_ntracks;
tn %= lp->d_ntracks;
bn += npf;
ubapurge(um);
um->um_tab.b_active = 2;
/*
* action taken depends on the flag
*/
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 */
bn--;
reg--;
if (bp->b_flags & B_BAD)
bn = sc->sc_badbn;
log(LOG_WARNING, "up%d%c: soft ecc sn%d\n", upunit(bp->b_dev),
'a' + uppart(bp->b_dev), 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 */
mask = up->upec2;
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)dbtob(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 (bcr == 0)
return (0);
npf++;
reg++;
break;
}
case BSE:
if (sc->sc_state == OPENRAW)
return (0);
#ifdef UPBDEBUG
if (upbdebug)
log(LOG_DEBUG, "upecc, BSE: bn %d cn %d tn %d sn %d\n",
bn, cn, tn, sn);
#endif
if (bp->b_flags & B_BAD)
return (0);
/*
* 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 UPBDEBUG
if (upbdebug)
log(LOG_DEBUG "BSE: restart at %d\n",npf+1);
#endif
bn = lp->d_ncylinders * lp->d_secpercyl -
lp->d_nsectors - 1 - bn;
sc->sc_badbn = bn;
fixregs:
cn = bn / lp->d_secpercyl;
sn = bn % lp->d_secpercyl;
tn = sn / lp->d_nsectors;
sn %= lp->d_nsectors;
bcr = bp->b_bcount - (int)ptob(npf);
bcr = MIN(bcr, 512);
up->upwc = -bcr;
#ifdef UPBDEBUG
if (upbdebug)
log(LOG_DEBUG, "revector to cn %d tn %d sn %d\n",
cn, tn, sn);
#endif
break;
case CONT:
#ifdef UPBDEBUG
if (upbdebug)
log(LOG_DEBUG, "upecc, CONT: bn %d cn %d tn %d sn %d\n",
bn, cn, tn, sn);
#endif
bp->b_flags &= ~B_BAD;
if ((int)ptob(npf) >= bp->b_bcount)
return (0);
up->upwc = -((bp->b_bcount - (int)ptob(npf)) / sizeof(short));
break;
}
if (up->upwc == 0) {
um->um_tab.b_active = 0; /* retry */
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
sc->sc_blkdone = npf;
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 < NSC; 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 < NUP; 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 < NSC; 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 < NUP; 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 20
updump(dev)
dev_t dev;
{
struct updevice *upaddr;
char *start;
int num, blk, unit;
struct size *sizes;
register struct uba_regs *uba;
register struct uba_device *ui;
register short *rp;
struct upst *st;
register int retry;
register struct disklabel *lp;
unit = upunit(dev);
if (unit >= NUP)
return (ENXIO);
#define phys(cast, addr) ((cast)((int)addr & 0x7fffffff))
ui = phys(struct uba_device *, updinfo[unit]);
if (ui == 0 || ui->ui_alive == 0)
return (ENXIO);
uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba;
ubainit(uba);
upaddr = (struct updevice *)ui->ui_physaddr;
DELAY(5000000);
num = maxfree;
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 = 0;
if (dumplo < 0)
return (EINVAL);
lp = &uplabel[unit];
/* should check uupart(dev) < lp->p_npartitions ? */
if (dumplo + num >= lp->d_partitions[uppart(dev)].p_size)
num = lp->d_partitions[uppart(dev)].p_size - dumplo;
while (num > 0) {
register struct pte *io;
register int i;
int blk, cn, sn, tn;
daddr_t bn;
blk = num > DBSIZE ? DBSIZE : num;
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);
cn = (bn + lp->d_partitions[hppart(dev)].p_offset) /
lp->d_secpercyl;
sn = bn % lp->d_secpercyl;
tn = sn / lp->d_nsectors;
sn = sn % lp->d_nsectors;
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;
num -= blk;
}
return (0);
}
upsize(dev)
dev_t dev;
{
register int unit = upunit(dev);
struct uba_device *ui;
if (unit >= NUP || (ui = updinfo[unit]) == 0 || ui->ui_alive == 0 ||
upsoftc[unit].sc_state != OPEN)
return (-1);
return ((int)uplabel[unit].d_partitions[uppart(dev)].p_size);
}
#ifdef COMPAT_42
/*
* Compatibility code to fake up pack label
* for unlabeled disks.
*/
struct size {
daddr_t nblocks;
int cyloff;
} up9300_sizes[8] = {
15884, 0, /* A=cyl 0 thru 26 */
33440, 27, /* B=cyl 27 thru 81 */
495520, 0, /* C=cyl 0 thru 814 */
15884, 562, /* D=cyl 562 thru 588 */
55936, 589, /* E=cyl 589 thru 680 */
81376, 681, /* F=cyl 681 thru 814 */
153728, 562, /* G=cyl 562 thru 814 */
291346, 82, /* H=cyl 82 thru 561 */
}, up9766_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 */
86240, 681, /* F=cyl 681 thru 822 */
158592, 562, /* G=cyl 562 thru 822 */
291346, 82, /* H=cyl 82 thru 561 */
}, up160_sizes[8] = {
15884, 0, /* A=cyl 0 thru 49 */
33440, 50, /* B=cyl 50 thru 154 */
263360, 0, /* C=cyl 0 thru 822 */
15884, 155, /* D=cyl 155 thru 204 */
55936, 205, /* E=cyl 205 thru 379 */
141664, 380, /* F=cyl 380 thru 822 */
213664, 155, /* G=cyl 155 thru 822 */
0, 0,
}, upam_sizes[8] = {
15884, 0, /* A=cyl 0 thru 31 */
33440, 32, /* B=cyl 32 thru 97 */
524288, 0, /* C=cyl 0 thru 1023 */
15884, 668, /* D=cyl 668 thru 699 */
55936, 700, /* E=cyl 700 thru 809 */
109472, 810, /* F=cyl 810 thru 1023 */
182176, 668, /* G=cyl 668 thru 1023 */
291346, 98, /* H=cyl 98 thru 667 */
}, up980_sizes[8] = {
15884, 0, /* A=cyl 0 thru 99 */
33440, 100, /* B=cyl 100 thru 308 */
131680, 0, /* C=cyl 0 thru 822 */
15884, 309, /* D=cyl 309 thru 408 */
55936, 409, /* E=cyl 409 thru 758 */
10080, 759, /* F=cyl 759 thru 822 */
82080, 309, /* G=cyl 309 thru 822 */
0, 0,
}, upeagle_sizes[8] = {
15884, 0, /* A=cyl 0 thru 16 */
66880, 17, /* B=cyl 17 thru 86 */
808320, 0, /* C=cyl 0 thru 841 */
15884, 391, /* D=cyl 391 thru 407 */
307200, 408, /* E=cyl 408 thru 727 */
109296, 728, /* F=cyl 728 thru 841 */
432816, 391, /* G=cyl 391 thru 841 */
291346, 87, /* H=cyl 87 thru 390 */
};
struct upst {
short nsect; /* # sectors/track */
short ntrak; /* # tracks/cylinder */
short nspc; /* # sectors/cylinder */
short ncyl; /* # cylinders */
struct size *sizes; /* partition tables */
short sdist; /* seek distance metric */
short rdist; /* rotational distance metric */
short mdist; /* min rotation (all guesswork) */
} upst[] = {
{ 32, 19, 32*19, 815, up9300_sizes, 3, 4, 1 }, /*9300*/
{ 32, 19, 32*19, 823, up9766_sizes, 3, 4, 1 }, /*9766*/
{ 32, 10, 32*10, 823, up160_sizes, 3, 4, 1 }, /*fuji160m*/
{ 32, 16, 32*16, 1024, upam_sizes, 7, 8, 2 }, /*Capricorn*/
{ 32, 5, 32*5, 823, up980_sizes, 3, 4, 1 }, /*DM980*/
{ 48, 20, 48*20, 842, upeagle_sizes, 15, 8, 3 }, /*EAGLE*/
{ 0, 0, 0, 0, 0, 0, 0, 0 }
};
/*
* These variable are all measured in sectors.
* Sdist is how much to "lead" in the search for a desired sector
* (i.e. if want N, search for N-sdist.)
* Maxdist and mindist define the region right before our desired sector within
* which we don't bother searching. We don't search when we are already less
* then maxdist and more than mindist sectors "before" our desired sector.
* Maxdist should be >= sdist.
*
* Beware, sdist, mindist and maxdist are not well tuned
* for many of the drives listed in this table.
* Try patching things with something i/o intensive
* running and watch iostat.
*/
/*
* Map apparent SC[23]1 drive type into manufacturer
* specific configuration.
*/
upmaptype(ui, lp)
register struct uba_device *ui;
register struct disklabel *lp;
{
register int type;
register struct upst *st;
upphysical(ui->ui_addr, lp); /* get the real drive numbers */
for (st = upst, type = 0; st->nsect != 0; st++, type++)
if (lp->d_ntracks == st->ntrak &&
lp->d_nsectors == st->nsect &&
lp->d_ncylinders == st->ncyl)
break;
if (st->nsect == 0) {
printf(": %dx%dx%d (s,t,c)?", lp->d_nsectors,
lp->d_ntracks, lp->d_ncylinders);
return (0);
}
ui->ui_type = type;
/*
* set up minimal disk label.
*/
st = &hpst[type];
lp->d_secsize = 512;
lp->d_nsectors = st->nsect;
lp->d_ntracks = st->ntrak;
lp->d_secpercyl = st->nspc;
lp->d_ncylinders = st->ncyl;
lp->d_secperunit = st->nspc * st->ncyl;
lp->d_sdist = st->sdist;
lp->d_mindist = st->rdist;
lp->d_maxdist = st->mdist;
bcopy(hpst[type].name, lp->d_typename, sizeof(lp->d_typename));
lp->d_npartitions = 8;
for (i = 0; i < 8; i++) {
lp->d_partitions[i].p_offset = st->sizes[i].cyloff *
lp->d_secpercyl;
lp->d_partitions[i].p_size = st->sizes[i].nblocks;
}
return (1);
}
#endif /* COMPAT_42 */
#endif /* NSC > 0 */