|
|
researchv10 Norman
/*
* UNIBUS SMD disk driver
*
* undone:
* Add bad sector forwarding code
* Check that offset recovery code works
* unibus mapping is suboptimal; if the queue gets long,
* buffered data paths will be underused
*/
#include "sys/param.h"
#include "sys/buf.h"
#include "sys/conf.h"
#include "sys/user.h"
#include "sys/up.h"
#include "sys/ubaddr.h"
#include "sys/subaddr.h"
#include "sys/diskio.h"
#include "sys/file.h"
#define NOUPSEEK 1 /* because emulex doesn't do it right */
/*
* hardware registers
*/
struct updevice
{
unsigned short upcs1; /* control and status register 1 */
short upwc; /* word count register */
unsigned short upba; /* UNIBUS address register */
unsigned short upda; /* desired address register */
unsigned short upcs2; /* control and status register 2 */
unsigned short upds; /* drive status */
unsigned short uper1; /* error register 1 */
unsigned short upas; /* attention summary */
unsigned short upla; /* look ahead */
unsigned short updb; /* data buffer */
unsigned short upmr; /* maintenance */
unsigned short updt; /* drive type */
unsigned short upsn; /* serial number */
unsigned short upof; /* offset register */
unsigned short updc; /* desired cylinder address register */
unsigned short uphr; /* holding register */
unsigned short upmr2; /* maintenance register 2 */
unsigned short uper2; /* error register 2 */
unsigned short upec1; /* burst error bit position */
unsigned short upec2; /* burst error bit pattern */
};
/*
* upcs1
*/
#define UP_SC 0100000 /* special condition */
#define UP_TRE 0040000 /* transfer error */
#define UP_IE 0000100 /* interrupt enable */
#define UP_GO 0000001
#define UP_SEEK 004 /* seek */
#define UP_RECAL 006 /* recalibrate */
#define UP_DCLR 010 /* drive clear */
#define UP_OFFSET 014 /* offset */
#define UP_RTC 016 /* return to center-line */
#define UP_PRESET 020 /* read-in preset */
#define UP_SEARCH 030 /* search */
#define UP_WCOM 060 /* write */
#define UP_RCOM 070 /* read data */
/*
* upcs2
*/
#define UPCS2_NED 0010000 /* nonexistent drive */
#define UPCS2_CLR 0000040 /* controller clear */
#define UPCS2_SEL 0000007 /* unit select */
/*
* upds
*/
#define UPDS_ERR 0040000 /* composite drive error */
#define UPDS_PIP 0020000 /* positioning in progress */
#define UPDS_MOL 0010000 /* medium on line */
#define UPDS_DPR 0000400 /* drive present */
#define UPDS_DRY 0000200 /* drive ready */
#define UPDS_VV 0000100 /* volume valid */
#define UPDS_DREADY (UPDS_DPR|UPDS_DRY|UPDS_MOL|UPDS_VV)
/*
* uper1
*/
#define UPER1_DCK 0100000 /* data check */
#define UPER1_WLE 0004000 /* write lock error */
#define UPER1_ECH 0000100 /* ecc hard error */
/*
* uphr: emulex hack
*/
#define UPHR_MAXCYL 0100027 /* max cyl address */
#define UPHR_MAXTRAK 0100030 /* max track address */
#define UPHR_MAXSECT 0100031 /* max sector address */
/*
* upof
*/
#define UPOF_FMT22 0010000 /* 16 bit format */
/* THE SC21 ACTUALLY JUST IMPLEMENTS ADVANCE/RETARD... */
#define UPOF_P400 0020 /* +400 uinches */
#define UPOF_M400 0220 /* -400 uinches */
#define UPOF_P800 0040 /* +800 uinches */
#define UPOF_M800 0240 /* -800 uinches */
#define UPOF_P1200 0060 /* +1200 uinches */
#define UPOF_M1200 0260 /* -1200 uinches */
#define SECTOR 512 /* size of a hardware sector */
/*
* monstrous size tables
* one per type of drive
*/
struct size
{
daddr_t nblocks;
daddr_t blkoff;
} up_sizes[NUPPART] = {
15884, 0*608, /* A=cyl 0 thru 26 */
33440, 27*608, /* B=cyl 27 thru 81 */
495520, 0*608, /* C=cyl 0 thru 814 */
15884, 562*608, /* D=cyl 562 thru 588 */
55936, 589*608, /* E=cyl 589 thru 680 */
#ifndef NOBADSECT
81376, 681*608, /* F=cyl 681 thru 814 */
153728, 562*608, /* G=cyl 562 thru 814 */
#else
81472, 681*608,
153824, 562*608,
#endif
291346, 82*608, /* H=cyl 82 thru 561 */
}, fj_sizes[8] = {
10240, 0*320, /* A=cyl 0 thru 31 */
20480, 32*320, /* B=cyl 32 thru 95 */
232640, 96*320, /* C=cyl 96 thru 822 */
0, 0*320,
0, 0*320,
0, 0*320,
0, 0*320,
#ifndef NOBADSECT
0, 0*320, /* H=cyl 155 thru 822 */
#else
0, 0*320,
#endif
}, fj3_sizes[8] = {
10240, 0*512, /* A=cyl 0 thru 19 */
20480, 20*512, /* B=cyl 20 thru 59 */
246784, 60*512, /* C=cyl 60 thru 541 */
246784, 542*512, /* D=cyl 542 thru 1024 */
0, 0*512,
0, 0*512,
0, 0*512,
#ifndef NOBADSECT
0, 0*512, /* H=cyl 155 thru 822 */
#else
0, 0*512,
#endif
}, cd_sizes[8] = {
10240, 0*160, /* A=cyl 0 thru 63 */
20480, 64*160, /* B=cyl 64 thru 191 */
100960, 192*160, /* C=cyl 192 thru 822 */
0, 0*160,
0, 0*160,
0, 0*160,
0, 0*160,
#ifndef NOBADSECT
100960, 0*160, /* H=cyl 0 thru 630 */
#else
100960, 0*160,
#endif
}, fj1_sizes[8] = {
1024, 0*256, /* cyl 0 through 3 */
0, 0*256,
0, 0*256,
0, 0*256,
0, 0*256,
0, 0*256,
0, 0*256,
0, 0*256,
};
/*
* tables of per-drive info, mostly sizes of things
* indexed by magic numbers; see uputype
*/
struct upst upst[] = {
32, 19, 3, 4, 32*19, 823, up_sizes, /* 9300/cdc */
/* 9300 actually has 815 cylinders... */
32, 10, 3, 4, 32*10, 823, fj_sizes, /* fujitsu 160m */
32, 5, 3, 4, 32*5, 631, cd_sizes, /* CDC 76 MB */
32, 8, 3, 4, 32*8, 4, fj1_sizes, /* Fixed part of FJ */
32, 16, 3, 4, 32*16, 1024, fj3_sizes, /* fujitsu 330m */
};
unsigned 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
};
/*
* things from config
*/
extern int upcnt, sccnt;
extern struct ubaddr scaddr[];
extern struct subaddr upaddr[];
extern struct scctl scctl[];
extern struct updisk updisk[];
extern struct buf upbuf[];
/*
* controller flags, scctl.flags
*/
#define CACTIVE 01 /* xfer in progress */
#define CWAITING 02 /* xfering and timer has ticked */
/*
* unit flags, updisk.flags
*/
#define UACTIVE 01 /* working on this xfer */
#define URXFR 02 /* done with any seeking; ready to roll */
#define UWOL 04 /* waiting for offline drive */
#define UWAITOL 010 /* waiting and timer has ticked */
/*
* device number
* 0100 in the minor device is (temporarily?)
* usurped to indicate bitmapped file systems
* quietly ignore it for now
* when things improve, change the UNIT mask to 037
*/
#define UNIT(d) ((minor(d)>>3) & 027)
#define PART(d) (minor(d) & 07)
/*
* abuse of spare bits of struct buf
*/
#define b_cylin b_resid /* for disksort */
#define b_ubm av_back /* this buffer's map */
int upwstart, upwatch(); /* Have started guardian */
int upwaitdry;
int upopen(), upstrategy(), upread(), upwrite(), upioctl();
struct cdevsw upcdev = cdinit(upopen, nulldev, upread, upwrite, upioctl);
struct bdevsw upbdev = bdinit(upopen, nulldev, upstrategy, 0);
upopen(dev, flag)
int dev, flag;
{
register struct updisk *up;
register struct upst *st;
register int p;
if (upuinit(UNIT(dev)) == 0) {
u.u_error = ENXIO;
return;
}
up = &updisk[UNIT(dev)];
st = &upst[up->type];
p = PART(dev);
if ((up->pinit & (1<<p)) == 0) {
up->nblocks[p] = st->sizes[p].nblocks;
up->blkoff[p] = st->sizes[p].blkoff;
if ((up->blkoff[p] % st->nspc) != 0) {
printf("up minor %d bad blkoff\n", minor(dev));
u.u_error = EINVAL;
return;
}
up->pinit |= (1<<p);
}
}
upuinit(unit)
register int unit;
{
register struct updevice *reg;
register struct updisk *up;
register struct subaddr *ua;
if (unit < 0 || unit > upcnt)
return (0);
ua = &upaddr[unit];
if (ua->ctl < 0)
return (0);
up = &updisk[unit];
if (up->ctl)
return (1);
if (upcinit(ua->ctl) == 0)
return (0);
reg = scctl[ua->ctl].addr;
if ((up->type = uputype(reg, ua->unit)) < 0) {
printf("up%d absent or bad type\n", unit);
return (0);
}
up->unit = ua->unit;
up->ctl = &scctl[ua->ctl];
up->ctl->drives[ua->unit] = up;
return (1);
}
/*
* determine drive type
* very emulex dependent; should look at drive type register too.
* perhaps there should be a way to change it?
* this is called by updump too;
* be prepared to run without memory management
* unit is the hardware unit
* return is an index into upst
*/
int
uputype(reg, unit)
register struct updevice *reg;
int unit;
{
reg->upcs1 = 0; /* conservative */
reg->upcs2 = unit;
if (reg->upcs2&UPCS2_NED) {
reg->upcs1 = UP_DCLR|UP_GO;
return (-1);
}
reg->uphr = UPHR_MAXTRAK;
switch (reg->uphr) {
default:
reg->upcs1 = UP_DCLR|UP_GO;
return (-1);
case 9:
return (unit >= 4 ? 3 : 1); /* fujitsu hack */
case 4:
return (2); /* CDC 76MB hack */
case 7:
return (3); /* Fixed Fujitsu hack */
case 15:
return (4); /* fuji 330m hack */
case 19:
return (0); /* CDC 300 MB hack */
}
}
upcinit(ctl)
int ctl;
{
register struct scctl *sc;
register struct updevice *reg;
if (ctl < 0 || ctl >= sccnt)
return (0);
sc = &scctl[ctl];
if (sc->addr)
return (1);
if ((reg = (struct updevice *)ubaddr(&scaddr[ctl])) == 0
|| ubbadaddr(scaddr[ctl].ubno, ®->upcs1, sizeof(short))) {
printf("sc%d absent\n", ctl);
return (0);
}
reg->upcs2 = UPCS2_CLR;
sc->addr = reg;
sc->ubno = scaddr[ctl].ubno;
if (upwstart == 0) {
timeout(upwatch, (caddr_t)0, HZ);
upwstart++;
}
return (1);
}
upstrategy(bp)
register struct buf *bp;
{
register struct updisk *up;
register struct upst *st;
register int unit;
register int part;
long sz;
int s;
sz = (bp->b_bcount+SECTOR-1)/SECTOR;
unit = UNIT(bp->b_dev);
up = &updisk[unit];
if (up->ctl == 0) {
bp->b_flags |= B_ERROR;
iodone(bp);
return;
}
st = &upst[up->type];
part = PART(bp->b_dev);
if (bp->b_blkno < 0 || bp->b_blkno+sz > up->nblocks[part]) {
if (bp->b_blkno == up->nblocks[part])
bp->b_resid = bp->b_bcount;
else { /* partial read too hard for now */
bp->b_error = ENXIO;
bp->b_flags |= B_ERROR;
}
iodone(bp);
return;
}
bp->b_cylin = (bp->b_blkno + up->blkoff[part])/st->nspc;
bp->b_ubm = (struct buf *)ubmbuf(up->ctl->ubno, bp, USLP);
s = spl6();
disksort(&up->actf, &up->actl, bp);
if ((up->flags & UACTIVE) == 0) {
upustart(up);
if (up->ctl->actf && (up->ctl->flags & CACTIVE) == 0)
upstart(up->ctl);
}
splx(s);
}
/*
* unit start:
* if there's a block for this drive, start seeking there
*
* up->upcs = UP_IE cancels a pending command in the SC21
* why not up->cs |= UP_IE?
*/
upustart(up)
register struct updisk *up;
{
register struct buf *bp;
register struct updevice *reg;
register struct scctl *sc;
register struct upst *st;
int sn, csn;
int didie = 0;
sc = up->ctl;
if ((bp = up->actf) == NULL)
return (0);
#ifndef NOUPSEEK
if (sc->flags & CACTIVE) { /* can't start seek till xfer done */
sc->softas |= 1<<up->unit;
return (0);
}
#endif
reg = sc->addr;
reg->upcs2 = up->unit;
if ((reg->upds & UPDS_VV) == 0) {
reg->upcs1 = UP_IE|UP_DCLR|UP_GO;
reg->upcs1 = UP_IE|UP_PRESET|UP_GO;
reg->upof = UPOF_FMT22;
didie = 1;
}
if ((reg->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL)) {
up->flags |= UWOL;
return (didie);
}
if ((up->flags & UACTIVE) == 0) { /* start seek if didn't already */
up->flags |= UACTIVE;
#ifndef NOUPSEEK
st = &upst[up->type];
sn = bp->b_blkno%st->nspc;
sn = (sn + st->nsect - st->sdist) % st->nsect; /* sector to seek to */
csn = sn - (reg->upla>>6);
if (csn < 0)
csn += st->nsect;
if (bp->b_cylin != reg->updc /* seek if off cylinder */
|| csn > st->rdist) { /* or not close enough */
reg->updc = bp->b_cylin;
reg->upda = sn;
reg->upcs1 = UP_IE|UP_SEARCH|UP_GO;
return (1);
}
#endif
}
if ((up->flags & URXFR) == 0) { /* seek done, put on ctl queue */
up->next = NULL;
if (sc->actf == NULL)
sc->actf = up;
else
sc->actl->next = up;
sc->actl = up;
up->flags |= URXFR;
}
return (didie);
}
/*
* Start up a transfer on a drive.
*/
upstart(sc)
register struct scctl *sc;
{
register struct buf *bp;
register struct updisk *up;
register struct updevice *reg;
register struct upst *st;
register c;
uaddr_t uad;
int sn, tn;
loop:
if ((up = sc->actf) == NULL)
return (0);
if ((bp = up->actf) == NULL) {
sc->actf = up->next;
goto loop;
}
sc->flags |= CACTIVE;
st = &upst[up->type];
sn = bp->b_blkno%st->nspc;
tn = sn/st->nsect;
sn %= st->nsect;
reg = sc->addr;
reg->upcs2 = up->unit;
c = 0;
while ((reg->upds&UPDS_DRY) == 0) {
if (++c > 512)
break;
upwaitdry++;
}
if ((reg->upds & UPDS_DREADY) != UPDS_DREADY) {
printf("up%d: not ready", UNIT(bp->b_dev));
if ((reg->upds & UPDS_DREADY) != UPDS_DREADY) {
printf("\n");
sc->flags &=~ (CACTIVE|CWAITING);
sc->errcnt = 0;
up->actf = bp->av_forw;
up->flags &=~ (UACTIVE|URXFR);
bp->b_flags |= B_ERROR;
iodone(bp);
goto loop;
}
printf(" (flakey)\n"); /* inscrutable */
}
reg->updc = bp->b_cylin;
reg->upda = (tn << 8) + sn;
reg->upwc = -bp->b_bcount / sizeof(short);
if (bp->b_flags & B_READ)
c = UP_IE|UP_RCOM|UP_GO;
else
c = UP_IE|UP_WCOM|UP_GO;
bp->b_ubm = (struct buf *)ubinspath(ubmapath(sc->ubno), (ubm_t)bp->b_ubm);
uad = ubadbuf(sc->ubno, bp, (ubm_t)bp->b_ubm);
reg->upba = uad;
reg->upcs1 = c|((uad>>8)&0x300);
return (1);
}
/*
* Handle a disk interrupt.
*/
sc0int(ctl)
int ctl;
{
register struct updevice *reg;
register struct scctl *sc;
register struct updisk *up;
register struct buf *bp;
register int unit, i, as;
int needie;
if (ctl < 0 || ctl >= sccnt) {
printf("sc%d bad intr\n");
return;
}
sc = &scctl[ctl];
if ((reg = sc->addr) == 0) {
printf("sc%d: stray intr\n");
return;
}
needie = 1;
as = (reg->upas & 0377) | sc->softas;
sc->softas = 0;
if ((sc->flags & CACTIVE) == 0) { /* must be a seek */
if (reg->upcs1 & UP_TRE)
reg->upcs1 = UP_TRE;
goto doattn;
}
up = sc->actf;
bp = up->actf;
reg->upcs2 = up->unit;
if ((reg->upds&UPDS_ERR) || (reg->upcs1&UP_TRE)) {
i = 0;
while ((reg->upds & UPDS_DRY) == 0) {
if (++i > 512)
break;
upwaitdry++;
}
if (reg->uper1&UPER1_WLE) {
printf("up%d: write locked\n", UNIT(bp->b_dev));
bp->b_flags |= B_ERROR;
} else if (++sc->errcnt > 27) {
harderr(bp, "up");
printf("cs2=%o er1=%o er2=%o\n",
reg->upcs2&0177777, reg->uper1&0177777, reg->uper2&0177777);
bp->b_flags |= B_ERROR;
} else {
/*
* soft ecc, try to correct
*/
sc->flags &=~ (CACTIVE|CWAITING); /* force retry */
if ((reg->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK)
if (upecc(up))
return; /* probably wrong */
}
/*
* `hard' error. clear and try again
*/
reg->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO;
needie = 0;
if ((sc->errcnt&07) == 4 && (sc->flags & CACTIVE) == 0) {
reg->upcs1 = UP_RECAL|UP_IE|UP_GO;
sc->recal = 0;
goto nextrecal;
}
}
/*
* Advance recalibration finite state machine
* if recalibrate in progress, through
* RECAL
* SEEK
* OFFSET (optional)
* RETRY
*/
switch (sc->recal) {
case 1:
reg->updc = bp->b_cylin;
reg->upcs1 = UP_SEEK|UP_IE|UP_GO;
goto nextrecal;
case 2:
if (sc->errcnt < 16 || (bp->b_flags&B_READ) == 0)
goto donerecal;
reg->upof = up_offset[sc->errcnt & 017] | UPOF_FMT22;
reg->upcs1 = UP_IE|UP_OFFSET|UP_GO;
nextrecal:
sc->recal++;
sc->flags |= CACTIVE;
return;
donerecal:
case 3:
sc->recal = 0;
sc->flags &=~ CACTIVE;
break;
}
if (sc->flags & CACTIVE) { /* `active' means we're done */
if (sc->errcnt >= 16) {
reg->upof = UPOF_FMT22;
reg->upcs1 = UP_RTC|UP_GO|UP_IE;
while (reg->upds & UPDS_PIP)
DELAY(25);
needie = 0;
}
sc->flags &=~ (CACTIVE|CWAITING);
sc->errcnt = 0;
sc->actf = up->next;
up->flags &=~ (UACTIVE|URXFR);
up->actf = bp->av_forw;
bp->b_resid = (-reg->upwc * sizeof(short));
ubmfree(sc->ubno, (ubm_t)bp->b_ubm);
iodone(bp);
if (up->actf)
if (upustart(up))
needie = 0;
}
as |= reg->upas;
as &= ~(1<<up->unit);
doattn:
/*
* Process other units which need attention.
*/
for (unit = 0, i = 1; unit < NSCUP && as; i <<= 1, unit++) {
if ((as & i) == 0)
continue;
as &= ~i;
reg->upas = i;
if ((up = sc->drives[unit]) != NULL && upustart(up))
needie = 0;
}
if (sc->actf && (sc->flags & CACTIVE) == 0)
if (upstart(sc))
needie = 0;
if (needie)
reg->upcs1 = UP_IE; /* why bother? */
}
upread(dev)
dev_t dev;
{
physio(upstrategy, &upbuf[UNIT(dev)], dev, B_READ, minphys);
}
upwrite(dev)
dev_t dev;
{
physio(upstrategy, &upbuf[UNIT(dev)], dev, B_WRITE, minphys);
}
upioctl(dev, cmd, addr, flag)
dev_t dev;
int cmd;
caddr_t addr;
int flag;
{
register struct updisk *up;
long parts[2];
up = &updisk[UNIT(dev)];
switch (cmd) {
case DIOSSIZ:
if ((flag & FWRITE) == 0) {
u.u_error = EBADF;
return;
}
if (copyin(addr, (caddr_t)parts, sizeof(parts)) < 0) {
u.u_error = EFAULT;
return;
}
/*
* why test this? see comments above upstrategy
*/
if ((parts[0] % upst[up->type].nspc) != 0) {
u.u_error = EINVAL;
return;
}
up->blkoff[PART(dev)] = parts[0];
up->nblocks[PART(dev)] = parts[1];
return;
case DIOGSIZ:
parts[0] = up->blkoff[PART(dev)];
parts[1] = up->nblocks[PART(dev)];
if (copyout((caddr_t)parts, addr, sizeof(parts)) < 0)
u.u_error = EFAULT;
return;
default:
u.u_error = ENOTTY;
return;
}
}
/*
* correct an ECC error and restart the transfer
* the error is (upec1-1) bits into the current sector;
* at that point, the bits set in upec2 are wrong.
*
* should be able just to set the GO bit and proceed,
* but emulex insists we do DCLR first, or so the book says,
* because DCK sets ERR in upds
*/
upecc(up)
register struct updisk *up;
{
register struct updevice *reg;
register struct scctl *sc;
register struct buf *bp;
register int i;
int nxf;
unsigned int mask;
uaddr_t uad, lastua;
int xc, xa;
if ((bp = up->actf) == NULL || (sc = up->ctl) == NULL)
panic("upecc");
reg = sc->addr;
ubmflush(sc->ubno, ubmpath((ubm_t)bp->b_ubm));
lastua = reg->upba + ((reg->upcs1&0x300)<<8);
nxf = bp->b_bcount + (reg->upwc * sizeof(short));
i = reg->upec1 - 1; /* -1 makes 0 origin */
uad = lastua - (nxf > SECTOR ? SECTOR : nxf) + ((i&~07)>>3);
mask = reg->upec2;
mask <<= i&07;
for (; uad < lastua && mask; mask >>= 8, uad++)
ubputc(sc->ubno, uad, ubgetc(sc->ubno, uad)^mask);
printf("up%d%o: soft ecc sec %ld\n", UNIT(bp->b_dev), PART(bp->b_dev),
bp->b_blkno + nxf/SECTOR - 1);
sc->flags |= CACTIVE; /* either complete or continuing */
if (reg->upwc == 0)
return (0);
#ifdef notdef
reg->uper1 = 0;
reg->upcs1 |= UP_GO;
#else /* clear wretched emulex error */
xc = reg->updc;
xa = reg->upda;
/* ba, wc undisturbed by DCLR */
reg->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO;
reg->updc = xc;
reg->upda = xa;
reg->upba = lastua;
i = (lastua >> 8) & 0x300;
i |= UP_IE|UP_GO|UP_RCOM;
reg->upcs1 = i;
#endif
return (1);
}
/*
* check for offline drives and hung controllers
*/
upwatch()
{
register struct scctl *sc;
register struct updisk *up;
register struct updevice *reg;
register struct buf *bp;
register int ounit;
register int s;
s = spl6();
timeout(upwatch, (caddr_t)0, 15*HZ);
for (up = &updisk[upcnt-1]; up >= updisk; up--) {
if ((up->flags & UWOL) == 0)
continue;
reg = up->ctl->addr;
ounit = reg->upcs2 & UPCS2_SEL;
reg->upcs2 = up->unit;
if ((reg->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL)) {
if ((up->flags & UWAITOL) == 0) {
up->flags |= UWAITOL;
reg->upcs2 = ounit;
continue;
}
printf("up%d offline\n", up - updisk);
while ((bp = up->actf) != NULL) {
bp->b_flags |= B_ERROR;
up->actf = bp->av_forw;
ubmfree(up->ctl->ubno, (ubm_t)bp->b_ubm);
iodone(bp);
}
}
up->flags &=~ (UWAITOL|UWOL);
upustart(up);
reg->upcs2 = ounit;
}
for (sc = &scctl[sccnt-1]; sc >= scctl; sc--) {
if (sc->flags & CACTIVE) {
if ((sc->flags & CWAITING) == 0)
sc->flags |= CWAITING;
else {
sc->addr->upcs2 = UPCS2_CLR;
printf("sc%d hung, kicked\n", sc - scctl);
sc->flags &=~ (CWAITING|CACTIVE);
}
}
if (sc->actf && (sc->flags & CACTIVE) == 0)
upstart(sc);
}
splx(s);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.