2.11BSD/sys/pdpuba/br.c
/*
* BR disk driver
* modified from the UNIX RP03 driver for BR disk drive -JM
* 11/11/84 - Added dump routine for taking 2.9 crash dumps in swap. -SMS
* 9/28/85 - Use brreg.h so as to look more like a 2.9 disk handler. -SMS
* 2/16/86 - Rewrite! Drop the bropen, brclose and brgch functions. Do
* initialization on a per drive basis rather than controller.
* The bropen and brclose functions were only used to perform
* the init'ing of a drive, and there was a problem in single
* user mode where a 'umount' could close the device before all
* data for that filesystem was written out thereby giving offline
* errors and causing corruption of the disc. Also defined a
* disc slice that encompassed the whole drive for ease in copying,
* several other mods made because this was done. Overall, several
* pages of code were removed. -SMS
* Just discovered that bropen() and brclose() were defined as
* nulldev() in c.c! Wasted code all this time! The offline errors
* observed were a result of entry into brstrategy() during a
* 'umount' when bropen() had never been called in the first place!!!
* 12/6/87 - Changes to run under 2.10bsd. Still single controller only.
* Considering we don't make the controller any more that's fairly
* safe to assume. Partitions drastically changed to allow room
* on T300 and T200 to hold the source distribution.
* Autoconfigure logic finally added though. -SMS
* 2/17/89 - For 2.10.1BSD added old 2.9BSD /usr,/userfiles, and /minkie
* partitions as partitions 'e', 'f', and 'g' as an aid in
* converting the systems. BE CAREFUL! For T300 only.
* 8/4/89 - Use the log() function to record soft errors.
* 9/22/91 - remove read and write entry - use common raw read/write routine.
* 12/23/92 - add the partition size routine.
* 1/2/93 - remove unibus map ifdefs, the run time check using 'ubmap' is
* sufficient and does the right thing.
* 1995/04/13 - change reference to dkunit.
*/
#include "br.h"
#if NBR > 0
#include "param.h"
#include "../machine/seg.h"
#include "systm.h"
#include "buf.h"
#include "conf.h"
#include "user.h"
#include "brreg.h"
#include "dk.h"
#include "disklabel.h"
#include "disk.h"
#include "syslog.h"
#include "map.h"
#include "uba.h"
#define BRADDR ((struct brdevice *) 0176710)
#define brunit(dev) ((dev >> 3) & 7)
#define SECTRK brc->sectrk
#define TRKCYL brc->trkcyl
struct br_char {
struct br_dsz {
daddr_t nblocks;
int cyloff;
} br_sizes[8];
int sectrk, trkcyl;
} br_chars[] =
{ /* T300 */
18240, 0, /* cyl 000 - 029 */
12160, 30, /* cyl 030 - 049 */
232256, 50, /* cyl 050 - 431 */
232256, 432, /* cyl 432 - 813 */
154432, 50, /* 'e' is old 2.9 'c' partition */
154432, 304, /* 'f' is old 2.9 'd' partition */
154432, 558, /* 'g' is old 2.9 'e' partition */
495520, 0, /* cyl 000 - 814 */
32, 19, /* 32 sectrk, 19 trkcyl */
/* T200 */
18392, 0, /* cyl 000 - 043 */
12122, 43, /* cyl 044 - 072 */
231990, 73, /* cyl 073 - 627 */
78166, 443, /* cyl 628 - 814 */
0, 0,
0, 0,
0, 0,
340670, 0, /* cyl 000 - 814 */
22, 19, /* 22 sectrk, 19 trkcyl */
/* T80 */
18400, 0, /* cyl 000 - 114 */
12320, 115, /* cyl 115 - 190 */
99840, 191, /* cyl 191 - 814 */
0, 0,
0, 0,
0, 0,
0, 0,
130300, 0,
32, 5, /* 32 sectrk, 5 trkcyl */
/* T50 */
18260, 0, /* cyl 000 - 165 */
12210, 166, /* cyl 166 - 276 */
59180, 277, /* cyl 277 - 814 */
0, 0,
0, 0,
0, 0,
0, 0,
89650, 0,
22, 5, /* 22 sectrk, 5 trkcyl */
};
/*
* Define the recovery strobes and offsets in br_da
*/
static int br_offs[] = {
0, 0, 0, STBE,
STBE, STBL, STBL, OFFP+STBL,
OFFP+STBL, OFFP, OFFP, OFFP+STBE,
OFFP+STBE, OFFM+STBE, OFFM+STBE, OFFP,
OFFP, OFFP+STBL, OFFP+STBL, 0
};
#ifdef UCB_METER
static int br_dkn = -1;
#endif
struct buf brtab;
struct br_char *br_disk[NBR];
struct brdevice *Br_addr;
brroot()
{
brattach((struct brdevice *)BRADDR, 0);
}
brattach(braddr, unit)
register struct brdevice *braddr;
int unit;
{
#ifdef UCB_METER
if (br_dkn < 0)
dk_alloc(&br_dkn, NBR, "br", 0L);
#endif
if (unit >= NBR)
return(0);
if (braddr && (fioword(braddr) != -1)) {
Br_addr = braddr;
return(1);
}
return(0);
}
bropen(dev, flag)
dev_t dev;
int flag;
{
register int dn = brunit(dev);
if (dn >= NBR || !Br_addr)
return(ENXIO);
if (!br_disk[dn])
brinit(dn);
if (!br_disk[dn])
return(EIO);
return(0);
}
brstrategy(bp)
register struct buf *bp;
{
register struct buf *dp;
register int unit;
struct br_char *brc;
struct br_dsz *brz;
long sz;
int drive, s;
unit = bp->b_dev & 07;
drive = brunit(bp->b_dev);
if (!(brc = br_disk[drive])) {
brinit(drive);
if (!(brc = br_disk[drive])) {
bp->b_error = ENODEV;
bp->b_flags |= B_ERROR;
iodone(bp);
return;
}
}
brz = &brc->br_sizes[unit];
sz = (bp->b_bcount + 511L) >> 9;
if (bp->b_blkno == brz->nblocks) {
bp->b_resid = bp->b_bcount;
iodone(bp);
return;
}
if (bp->b_blkno + sz > brz->nblocks) {
bp->b_error = EINVAL;
bp->b_flags |= B_ERROR;
iodone(bp);
return;
}
if (Br_addr->brae >= 0)
mapalloc(bp);
bp->b_cylin = bp->b_blkno/(SECTRK*TRKCYL) + brz->cyloff;
s = splbio();
dp = &brtab;
disksort(dp, bp);
if (dp->b_active == NULL)
brstart();
splx(s);
}
static
brstart()
{
register struct buf *bp;
register int unit;
int com,cn,tn,sn,dn;
daddr_t bn;
struct br_char *brc;
struct br_dsz *brz;
if ((bp = brtab.b_actf) == NULL)
return;
Br_addr->brds = -1;
brtab.b_active++;
if (!(Br_addr->brcs.w & BR_RDY)) {
timeout(brstart, 0, 4);
return;
}
unit = bp->b_dev & 07;
dn = brunit(bp->b_dev);
if (!(brc = br_disk[dn])) {
brinit(dn);
if (!(brc = br_disk[dn])) {
bp->b_flags |= B_ERROR;
brdone(bp);
return;
}
}
brz = &brc->br_sizes[unit];
bn = bp->b_blkno;
cn = bn/(SECTRK*TRKCYL) + brz->cyloff;
sn = bn%(SECTRK*TRKCYL);
tn = sn/SECTRK;
sn = sn%SECTRK;
if (Br_addr->brae < 0)
Br_addr->brae = bp->b_xmem;
Br_addr->brcs.w = (dn<<8);
Br_addr->brda = (tn<<8) | sn;
cn |= br_offs[brtab.b_errcnt];
Br_addr->brca = cn;
Br_addr->brba = bp->b_un.b_addr;
Br_addr->brwc = -(bp->b_bcount>>1);
com = ((bp->b_xmem&3)<<4) | BR_IDE | BR_GO;
if (bp->b_flags & B_READ)
com |= BR_RCOM;
else
com |= BR_WCOM;
Br_addr->brcs.w |= com;
#ifdef UCB_METER
if (br_dkn >= 0) {
dk_busy |= 1 << (br_dkn + dn);
dk_xfer[br_dkn + dn]++;
dk_seek[br_dkn + dn]++;
dk_wds[br_dkn + dn] += (bp->b_bcount >> 6);
}
#endif
}
static
brinit(drive)
register int drive;
{
register int ctr = 0;
register struct br_char **br = &br_disk[drive];
/*
* Clear the drive's entry in br_disk. Select the unit. If the
* unit exists, switch on the spindle type. and set the br_disk
* table entry
*/
*br = (struct br_char *)NULL;
do {
Br_addr->brcs.w = (drive << 8) | BR_HSEEK | BR_GO;
while ((Br_addr->brcs.w & BR_RDY) == 0 && --ctr) ;
} while (Br_addr->brer & BRER_SUBUSY);
if ((Br_addr->brcs.w & BR_HE) == 0) {
switch (Br_addr->brae & AE_DTYP) {
case AE_T300:
*br = &br_chars[0];
break;
case AE_T200:
*br = &br_chars[1];
break;
case AE_T80:
*br = &br_chars[2];
break;
case AE_T50:
*br = &br_chars[3];
break;
}
#ifdef UCB_METER
if (br_dkn >= 0)
dk_wps[br_dkn + drive] =
(long)(*br)->sectrk * (60L * 256L);
#endif
}
}
brintr(dev)
int dev;
{
register struct buf *bp;
register int ctr = 0;
struct brdevice brsave;
if (brtab.b_active == NULL)
return;
brsave = *Br_addr;
bp = brtab.b_actf;
if (!(brsave.brcs.w & BR_RDY))
return;
#ifdef UCB_METER
if (br_dkn >= 0)
dk_busy &= ~(1<<(br_dkn + dev));
#endif
if (brsave.brcs.w < 0) {
if (brsave.brer & BRER_SUBUSY) {
timeout(brstart, 0, 5);
return;
}
if (brsave.brds & (BRDS_SUFU|BRDS_SUSI|BRDS_HNF)) {
Br_addr->brcs.c[0] = BR_HSEEK|BR_GO;
while (((Br_addr->brds&BRDS_SURDY) == 0) && --ctr);
}
Br_addr->brcs.w = BR_IDLE|BR_GO;
ctr = 0;
while (((Br_addr->brcs.w&BR_RDY) == 0) && --ctr) ;
if (brtab.b_errcnt == 0) {
log(LOG_WARNING,"br%d%c ds:%b er:%b cs:%b wc:%o ba:%o ca:%o da:%o bae:%o\n",
dkunit(bp->b_dev), 'a'+ dkpart(bp->b_dev),
brsave.brds, BRDS_BITS, brsave.brer, BRER_BITS,
brsave.brcs.w, BR_BITS, brsave.brwc,brsave.brba,
brsave.brca, brsave.brda, brsave.brae);
}
brtab.b_errcnt++;
if (brtab.b_errcnt < 20) {
brstart();
return;
}
harderr(bp,"br");
bp->b_flags |= B_ERROR;
}
brdone(bp);
}
static
brdone (bp)
register struct buf *bp;
{
brtab.b_active = NULL;
brtab.b_errcnt = 0;
brtab.b_actf = bp->av_forw;
bp->b_resid = 0;
iodone(bp);
brstart();
}
#ifdef BR_DUMP
/*
* Dump routine. Dumps from dumplo to end of memory/end of disk section for
* minor(dev).
*/
#define DBSIZE 16 /* unit of transfer, same number */
brdump(dev)
dev_t dev;
{
struct br_char *brc;
struct ubmap *ubp;
daddr_t bn, dumpsize;
long paddr;
int count, cyl, dn, cn, tn, sn, unit, com;
unit = dev & 07;
dn = brunit(dev);
if ((bdevsw[major(dev)].d_strategy != brstrategy) || dn >= NBR)
return(EINVAL);
if (!Br_addr || !(brc = br_disk[dn]))
return(ENXIO);
dumpsize = brc->br_sizes[unit].nblocks;
cyl = brc->br_sizes[unit].cyloff;
if ((dumplo < 0) || (dumplo >= dumpsize))
return(EINVAL);
dumpsize -= dumplo;
while (!(Br_addr->brcs.w & BR_RDY));
ubp = &UBMAP[0];
for (paddr = 0L; dumpsize > 0; dumpsize -= count) {
count = dumpsize > DBSIZE ? DBSIZE : dumpsize;
bn = dumplo + (paddr >> PGSHIFT);
cn = (bn / (SECTRK * TRKCYL)) + cyl;
sn = bn % (SECTRK * TRKCYL);
tn = sn / SECTRK;
sn = sn % SECTRK;
Br_addr->brca = cn;
Br_addr->brda = (tn << 8) | sn;
Br_addr->brwc = -(count << (PGSHIFT-1));
com = (dn << 8) | BR_GO | BR_WCOM;
if (ubmap && Br_addr->brae >= 0) {
ubp->ub_lo = loint(paddr);
ubp->ub_hi = hiint(paddr);
Br_addr->brba = 0;
}
else {
Br_addr->brba = (caddr_t)loint(paddr);
Br_addr->brae = hiint(paddr);
com |= ((hiint(paddr) & 3) << 4);
}
Br_addr->brcs.w = com;
while (!(Br_addr->brcs.w & BR_RDY));
if (Br_addr->brcs.w < 0) {
if (Br_addr->brer & BRER_NXME)
return(0); /* end of memory */
return(EIO);
}
paddr += (DBSIZE << PGSHIFT);
}
return(0); /* filled disk */
}
#endif /* BR_DUMP */
/*
* Assumes the 'open' entry point has been called to validate the unit
* number and fill in the drive type structure.
*/
daddr_t
brsize(dev)
register dev_t dev;
{
register struct br_char *brc;
brc = br_disk[brunit(dev)];
return(brc->br_sizes[dev & 7].nblocks);
}
#endif /* NBR */