Ultrix-3.1/sys/dev/hp.c
/**********************************************************************
* Copyright (c) Digital Equipment Corporation 1984, 1985, 1986. *
* All Rights Reserved. *
* Reference "/usr/src/COPYRIGHT" for applicable restrictions. *
**********************************************************************/
/*
* SCCSID: @(#)hp.c 3.0 4/21/86
*/
/*
* ULTRIX-11 General Massbus Disk Driver (hp.c).
* Supports up to four RH11/RH70 massbus controllers,
* (hp, hm, hl, hj). Each controller may have up to 8
* drives of type: ML11, RP04/5/6, RM02/3/5.
*
* This driver contains what on the surface may appear
* to be strangeness, HOWEVER it is really some very
* carefully designed and tested code, which allows
* the driver to handle dual ported drives and to recognize
* when drives are taken off/on line via removing/replacing the LAP
* (logical assignment plug). It also handles the case where the LAPs
* are exchanged between unlike drive types, for example RM03 & RP06.
* The LAP feature will not function properly for the ML11,
* which has no LAP anyway !
* The ML11 cannot be dual ported, GOOD !
* WARNING !, testing of the dual port code was limited to
* allowing the driver to work with dual ported drives having
* the port switch in any of the three positions, A, B, or A/B.
* Actual dynamic (A/B) operation with two systems will NOT work,
* because the drive is treated as nonexistent if it is seized
* by the controller on the other port.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/conf.h>
#include <sys/dir.h>
#include <sys/user.h>
#include <sys/seg.h>
#include <sys/errlog.h>
#include <sys/devmaj.h>
#include <sys/bads.h>
#include <sys/hpbad.h>
#include <sys/hp_info.h>
#include <sys/uba.h>
char hp_index[]; /* non-semetrical array index (see conf/rh.c) */
int io_csr[]; /* (c.c) I/O page CSR address for each cntlr */
/* Index is HP_RMAJ + ctrl */
char io_bae[]; /* (c.c) BAE register offset for each cntlr, */
/* or 0 if cntlr is an RH11 */
/* Index is HP_BMAJ + ctrl */
char nhp[]; /* (c.c) Number of units configured for each cntlr */
char *hp_dct[] = {"HP", "HM", "HJ"}; /* cntlr type for error msg */
/*
* Instrumentation (iostat) structures
*/
struct ios hp_ios[];
#define DK_N 0
/*
* Disk overlapped seek definitions
*/
#define SDIST 2
#define RDIST 6
/*
* HP disk information structure
*
* WARNING!, the order and values of things in this
* structure are hardwired into the HPX disk exerciser.
* DO NOT change this table without checking HPX.
* WARNING!, same deal with /usr/sys/sas/setup.c!
*/
#define RP456 0
#define RM23 1
#define RM5 2
#define ML 3
struct hpdi {
int nsect; /* sectors per track */
int ntrac; /* tracks per cylinder */
int nbpc; /* blocks per cylinder */
int sti; /* sizes table index */
} hpdi[] = {
22, 19, 22*19, RP456*8, /* RP04/5/6 */
32, 5, 32*5, RM23*8, /* RM02/3 */
32, 19, 32*19, RM5*8, /* RM05 */
1, 1, 1, ML*8, /* ML11 */
};
/*
* The size structures determine the starting cylinder
* number and length in blocks of the disk partitions.
* For the RM02/3/5 and RP04/5/6 disks, each entry describes
* a partition, for the ML11 each entry contains the size in
* blocks of that unit, the ML11 is not partitioned.
* The size of the ML11 unit is determined by reading
* the ML maintenance register the first time the drive
* is accessed.
* The last two tracks of each are reserved for the bad
* block (sector) file and can only be accessed by the driver.
*/
/*
* Sizes table now in /usr/sys/conf/dksizes.c
*/
extern struct {
daddr_t nblocks;
int cyloff;
} hp_sizes[];
/*
* Block device error log buffer, holds one
* error log record until error retry sequence
* has been completed.
* One for each RH11/RH70 controller.
*/
struct hp_ebuf hp_ebuf[];
#define P400 020
#define M400 0220
#define P800 040
#define M800 0240
#define P1200 060
#define M1200 0260
int hp_offset[16] =
{
P400, M400, P400, M400,
P800, M800, P800, M800,
P1200, M1200, P1200, M1200,
0, 0, 0, 0,
};
struct buf hptab[]; /* Head of I/O queue for each cntlr */
struct buf rhpbuf[]; /* RAW I/O buffer header for each cntlr */
struct buf hputab[]; /* Drive queue (overlap seek) one per unit */
/*
* Drive types, required by HPX
* 0 = nonexistent drive
* otherwise equals the drive type.
*/
char hp_dt[]; /* see conf/rh.c */
/*
* Structures for bad block revectoring
*/
struct hpbad hp_bads[]; /* Buffer for bad block file, one per unit */
struct dkres hp_res[]; /* Bads revector and continue structure, */
/* one per controller. */
struct hp_badr hp_r[]; /* Flags & base block, one per unit (hp_info.h) */
char hp_openf[]; /* HP open flag, one per cntlr */
#define GO 01
#define PRESET 020
#define RTC 016
#define OFFSET 014
#define SEARCH 030
#define RECAL 06
#define DCLR 010
#define DPRLS 012
#define CCLR 040
#define WCOM 060
#define RCOM 070
#define IE 0100
#define NED 010000
#define PIP 020000
#define DRY 0200
#define ERR 040000
#define TRE 040000
#define DCK 0100000
#define WLE 04000
#define ECH 0100
#define VV 0100
#define DPR 0400
#define MOL 010000
#define FMT22 010000
#define b_cylin b_resid
/*
* On the first call to hpopen only,
* determine the existence and type of all possible drives.
* A dual ported drive that is locked on the opposite port
* will be treated and nonexistent until it is unlocked.
* This code assumes that the interrupt enable in HPCS1 is off.
*/
hpopen(dev)
{
register struct hp_regs *hpaddr;
register int ctrl, dn;
int fs, ind, pri;
ctrl = hpctrl(dev);
if(hp_openf[ctrl])
return;
hp_openf[ctrl]++;
hpaddr = io_csr[HP_RMAJ+ctrl]; /* Get RH11/RH70 CSR address (HPCS1) */
for(dn=0; dn<nhp[ctrl]; dn++) { /* look at all drives */
ind = hp_index[ctrl] + dn;
hpaddr->hpcs2.w = dn; /* select drive */
hpaddr->hpcs1.w = GO; /* NOP, attempt seize dual port drive */
hp_dt[ind] = hpaddr->hpdt & 0377; /* save drive type, 0 = NED */
if(hp_dt[ind] == 0) /* clear the world if NED */
hpaddr->hpcs2.w = CCLR;
/*
* Find the size of the ML11 unit by reading the
* number of array modules from the ML maintenance register.
* There are 512 blocks per array.
*/
if(hp_dt[ind] == ML11) {
hp_sizes[dn+(ML*8)].nblocks = (hpaddr->hpmr>>2)&037000;
/*
* Check the ML11 transfer rate.
* 2mb is too fast for any pdp11
* 1mb allowed on pdp11/70 only
* .5mb & .25mb ok on any processor.
*/
fs = hpaddr->hpmr & 01400;
if((fs == 0) || ((fs == 0400) && (cputype != 70))) {
printf("\n%s unit %d ML11 too fast for CPU\n",
hp_dct[ctrl], dn);
hp_dt[ind] = 0;
} else
hp_ios[ind].dk_tr = ((fs >> 8) & 3) + 4;
}
}
/*
* Initialize disk I/O instrumentation pointers
*/
pri = spl6();
fs = DK_N + ctrl;
dk_iop[fs] = &hp_ios[hp_index[ctrl]];
dk_nd[fs] = nhp[ctrl];
splx(pri);
}
hpstrategy(bp)
register struct buf *bp;
{
register struct buf *dp;
register int ctrl;
long sz, bn;
int dn, dip, fs, pri, unit, ind;
ctrl = hpctrl(bp->b_dev);
if(!io_bae[HP_BMAJ+ctrl])
mapalloc(bp);
unit = minor(bp->b_dev) & 077;
dn = (unit >> 3) & 07; /* get drive number */
ind = hp_index[ctrl] + dn;
if(hp_dt[ind] == 0)
goto bad; /* NED - can't even touch ! */
/*
* Set the drive information pointer according to drive type.
* 0 = RP04/5/6, 1 = RM02/3, 2 = RM05, 3 = ML11
*/
dip = hp_dipset(ind);
/*
* Set disk xfer rates for iostat
*/
switch(dip) {
case RP456:
case RM23:
hp_ios[ind].dk_tr = 1;
if(hp_dt[ind] == RM03)
hp_ios[ind].dk_tr++;
break;
case RM5:
hp_ios[ind].dk_tr = 2;
case ML: /* ML rate set in hpopen() */
break;
default:
goto bad;
}
sz = bp->b_bcount;
sz = (sz+511) >> 9;
fs = unit & 07; /* For RP & RM, fs is partition */
if(dip == ML) { /* For ML, fs is unit number */
fs = dn;
if(unit & 7)
goto bad; /* ML11 is not partitioned */
}
if(dn >= nhp[ctrl] ||
bp->b_blkno < 0 ||
(bn = bp->b_blkno)+sz > hp_sizes[fs+hpdi[dip].sti].nblocks) {
bad:
bp->b_error = ENXIO;
bp->b_flags |= B_ERROR;
iodone(bp);
return;
}
if(dip == ML)
bp->b_cylin = 0; /* fake out dsort for ML11 */
else
bp->b_cylin = bn/hpdi[dip].nbpc + hp_sizes[fs+hpdi[dip].sti].cyloff;
dp = &hputab[ind];
pri = spl5();
disksort(dp, bp);
if (dp->b_active == 0) {
hpustart(ctrl, dn);
if(hptab[ctrl].b_active == 0)
hpstart(ctrl);
}
splx(pri);
}
static
hpustart(ctrl, unit)
int ctrl;
int unit;
{
register struct buf *bp, *dp;
register struct hp_regs *hpaddr;
daddr_t bn;
int sn, cn, csn, dip, ind;
ind = hp_index[ctrl] + unit;
hpaddr = io_csr[HP_RMAJ+ctrl];
/*
* Check for nonexistent drive !
* This could cause a NED error interrupt,
* which must be handled by hpintr().
* The drive type reads as zeros on NEDs.
*/
hpaddr->hpcs2.w = unit;
hpaddr->hpcs1.c[0] = IE|GO; /* NOP attempt seize dual port drive */
hp_dt[ind] = hpaddr->hpdt & 0377;
if(hp_dt[ind] == 0)
goto done; /* NED */
hpaddr->hpcs1.c[0] = IE;
hpaddr->hpas = 1<<unit;
if(unit >= nhp[ctrl])
return;
dip = hp_dipset(ind);
hp_ios[ind].dk_busy = 0; /* device not busy */
el_bdact |= (1 << (HP_BMAJ+ctrl)); /* XXX */
dp = &hputab[ind];
if((bp=dp->b_actf) == NULL)
return;
hpaddr->hpcs2.w = unit; /* NED interrupt could change CS2 */
if((hpaddr->hpds & VV) == 0) {
hpaddr->hpcs1.c[0] = IE|PRESET|GO;
hp_r[ind].bads &= ~BAD_LOA;
}
if(dip != ML)
hpaddr->hpof = FMT22;
if(dp->b_active)
goto done;
if(dip == ML) {
sn = bp->b_blkno;
dp->b_active++;
goto mlsrch;
}
if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL))
goto done;
dp->b_active++;
bn = bp->b_blkno;
cn = bp->b_cylin;
sn = bn%hpdi[dip].nbpc;
sn = (sn+hpdi[dip].nsect-SDIST)%hpdi[dip].nsect;
if(hpaddr->hpcc != cn)
goto search;
csn = (hpaddr->hpla>>6) - sn + SDIST - 1;
if(csn < 0)
csn += hpdi[dip].nsect;
if(csn > hpdi[dip].nsect-RDIST)
goto done;
search:
hpaddr->hpdc = cn;
mlsrch:
hpaddr->hpda = sn;
hp_ios[ind].dk_busy++; /* device active */
el_bdact |= (1 << (HP_BMAJ+ctrl));
hpaddr->hpcs1.c[0] = IE|SEARCH|GO;
return;
done:
dp->b_forw = NULL;
if(hptab[ctrl].b_actf == NULL)
hptab[ctrl].b_actf = dp; else
hptab[ctrl].b_actl->b_forw = dp;
hptab[ctrl].b_actl = dp;
}
static
hpstart(ctrl)
{
register struct buf *bp, *dp;
register struct hp_regs *hpaddr;
int unit, ind;
daddr_t bn;
int dn, sn, tn, cn, dt, pri;
int dip, bae;
hpaddr = io_csr[HP_RMAJ+ctrl];
bae = io_bae[HP_BMAJ+ctrl];
loop:
if ((dp = hptab[ctrl].b_actf) == NULL)
return;
if ((bp = dp->b_actf) == NULL) {
hptab[ctrl].b_actf = dp->b_forw;
goto loop;
}
hptab[ctrl].b_active++;
unit = minor(bp->b_dev) & 077;
dn = unit >> 3;
bn = 0;
/*
* Do not attempt to access a NED !
*/
ind = hp_index[ctrl] + dn;
if(hp_dt[ind] == 0)
goto bad; /* NED */
if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL)) {
bad:
hptab[ctrl].b_active = 0;
bp->b_error = ENXIO; /* NED */
hptab[ctrl].b_errcnt = 0;
dp->b_actf = bp->av_forw;
bp->b_flags |= B_ERROR;
iodone(bp);
goto loop;
}
dip = hp_dipset(ind);
if((hp_r[ind].bads & BAD_LOA) == 0 && dip != ML){
/* don't have Bad Sector Info. Need to load it. */
bn = hp_r[ind].vcyl;
for(pri = 0; pri < 5; pri++){
cn = bn/hpdi[dip].nbpc;
sn = bn%hpdi[dip].nbpc;
tn = sn/hpdi[dip].nsect;
sn = sn%hpdi[dip].nsect;
hpaddr->hpcs2.w = dn;
hpaddr->hpdc = cn;
hpaddr->hpda = (tn<<8)+ sn;
if(ubmaps && !bae)
hpaddr->hpba = (char *)&hp_bads[ind]-(char *)&cfree;
else
hpaddr->hpba = &hp_bads[ind];
hpaddr->hpwc = -((sizeof(struct hpbad)-64)>>1);
if(bae)
hpaddr->hpbae = 0;
hpaddr->hpcs1.w = RCOM|GO;
while((hpaddr->hpcs1.w & DRY) == 0)
;
if(hpaddr->hpcs1.w & TRE){
if((pri==0) && (hptab[ctrl].b_errcnt==0)) {
if(!bae)
cn = (NHPREG - 2);
else
cn = NHPREG;
fmtbde(bp, &hp_ebuf[ctrl], hpaddr, cn, HPDBOFF);
hp_ebuf[ctrl].hp_reg[4] &= ~7; /* correct unit # */
hp_ebuf[ctrl].hp_reg[4] |= dn;
}
bn += 2;
}
else{
hp_r[ind].bads |= BAD_LOA;
break;
}
}
}
if((dip != ML) &&
(hptab[ctrl].b_errcnt == 0) &&
((hp_r[ind].bads & BAD_LOA) == 0)) {
hp_ebuf[ctrl].hp_bdh.bd_errcnt = 0;
if(!logerr(E_BD,&hp_ebuf[ctrl],sizeof(struct hp_ebuf)))
deverror(bp,hp_ebuf[ctrl].hp_reg[4],hp_ebuf[ctrl].hp_reg[6]);
}
hpaddr->hpcs2.w = dn;
switch(hp_r[ind].bads & 060){
case BAD_VEC:
bn = hp_res[ctrl].r_vbn;
hpaddr->hpba = hp_res[ctrl].r_vma;
if(bae)
hpaddr->hpbae = hp_res[ctrl].r_vxm;
hpaddr->hpwc = -(hp_res[ctrl].r_vcc>>1);
pri = ((hp_res[ctrl].r_vxm&03)<<8) | IE | GO;
break;
case BAD_CON:
hp_r[ind].bads &= ~BAD_CON;
bn = hp_res[ctrl].r_bn;
hpaddr->hpba = hp_res[ctrl].r_ma;
if(bae)
hpaddr->hpbae = hp_res[ctrl].r_xm;
hpaddr->hpwc = -(hp_res[ctrl].r_cc>>1);
pri = ((hp_res[ctrl].r_xm&03)<<8) | IE | GO;
break;
default:
bn = bp->b_blkno;
hpaddr->hpba = bp->b_un.b_addr;
if(bae)
hpaddr->hpbae = bp->b_xmem;
hpaddr->hpwc = -(bp->b_bcount>>1);
pri = ((bp->b_xmem&3) << 8) | IE | GO;
break;
}
if(dip != ML) {
cn = bn/hpdi[dip].nbpc;
if((hp_r[ind].bads & BAD_VEC) == 0)
cn += hp_sizes[(unit&7)+hpdi[dip].sti].cyloff;
sn = bn%hpdi[dip].nbpc;
tn = sn/hpdi[dip].nsect;
sn = sn%hpdi[dip].nsect;
}
if((hptab[ctrl].b_errcnt >= 16) && (dip != ML)) {
hpaddr->hpof = hp_offset[hptab[ctrl].b_errcnt & 017] | FMT22;
hpaddr->hpcs1.w = OFFSET|GO;
while(hpaddr->hpds & PIP)
;
}
if(dip == ML)
hpaddr->hpda = bn;
else {
hpaddr->hpdc = cn;
hpaddr->hpda = (tn << 8) + sn;
}
if(bp->b_flags & B_READ)
pri |= RCOM; else
pri |= WCOM;
hpaddr->hpcs1.w = pri;
el_bdact |= (1 << (HP_BMAJ+ctrl));
hp_ios[ind].dk_busy++; /* Instrumentation - disk active, */
hp_ios[ind].dk_numb++; /* count number of transfers, */
unit = bp->b_bcount >> 6; /* transfer size in 32 word chunks, */
hp_ios[ind].dk_wds += unit; /* count total words transferred */
}
hpintr(dev)
{
register struct buf *bp, *dp;
register struct hp_regs *hpaddr;
int unit, ctrl, ind;
int seg, uba;
int as;
int tpuis[2], tpbad[2], tppos, tpofst;
int bsp;
int pri, ctr, dn;
ctrl = dev & 3;
ind = hp_index[ctrl];
hpaddr = io_csr[HP_RMAJ+ctrl];
/*
* Must handle the NED error interrupt which could
* be generated by the NED check in hpustart above.
*/
if(hptab[ctrl].b_active == 0) {
ctr = hpaddr->hpcs2.w & 7;
if(hpaddr->hpcs2.w & NED) {
printf("\n%s unit %d nonexistent\n", hp_dct[ctrl], ctr);
/* XXX */ hpaddr->hpcs2.w = 0; /* assumes drive 0 exists !!! */
hpaddr->hpcs1.w = TRE|IE;
hp_dt[ind+ctr] = 0; /* NED */
return;
}
as = hpaddr->hpas & 0377;
if(as == 0) {
logsi(hpaddr);
return;
}
} else
as = hpaddr->hpas & 0377;
if(hptab[ctrl].b_active) {
dp = hptab[ctrl].b_actf;
bp = dp->b_actf;
unit = (bp->b_dev >> 3) & 7;
dn = unit;
if(hpaddr->hpcs2.w & NED) {
ctr = hpaddr->hpcs2.w & 7;
if(ctr != unit) {
hp_dt[ind+ctr] = 0; /* NED */
dn = ctr;
}
}
ind += unit;
hpaddr->hpcs2.c[0] = unit;
hp_ios[ind].dk_busy = 0; /* device no longer active */
if (hpaddr->hpcs1.w & TRE) { /* error bit */
while((hpaddr->hpds & DRY) == 0)
;
if(hptab[ctrl].b_errcnt == 0) {
if(!io_bae[HP_BMAJ+ctrl])
ctr = (NHPREG - 2);
else
ctr = NHPREG;
fmtbde(bp, &hp_ebuf[ctrl], hpaddr, ctr, HPDBOFF);
hp_ebuf[ctrl].hp_reg[4] &= ~7; /* correct unit # */
hp_ebuf[ctrl].hp_reg[4] |= dn;
}
if((hp_dt[ind] == ML11) && (hptab[ctrl].b_errcnt == 0))
hptab[ctrl].b_errcnt = 18;
if(++hptab[ctrl].b_errcnt > 28 || hpaddr->hper1&WLE) {
if(hpaddr->hper1 & WLE)
hptab[ctrl].b_errcnt = 0;
bp->b_flags |= B_ERROR;
} else
hptab[ctrl].b_active = 0;
/* Start of ECC code, please excuse the improper indentation */
if(((hpaddr->hper1&(DCK|ECH)) == DCK) && (hp_dt[ind] != ML11))
{
fixbad(&hp_res[ctrl], bp, hpaddr->hpwc, 0);
pri = spl7();
tpuis[0] = UISA->r[0]; /* save User I space PAR */
tpuis[1] = UISD->r[0]; /* save User I space PDR */
if(io_bae[HP_BMAJ+ctrl])
uba = (hpaddr->hpbae << 10) & 0176000;
else
uba = (hpaddr->hpcs1.w & 01400) << 2;
uba += ((((int)hpaddr->hpba >> 1) & ~0100000) >> 5);
uba -= 8;
if(bp->b_flags & B_MAP) {
ctr = ((uba >> 7) & 037);
seg = (UBMAP + ctr)->ub_hi << 10;
seg |= ((UBMAP + ctr)->ub_lo >> 6) & 01777;
UISA->r[0] = seg + (uba & 0177);
/* ECC FIX */ bsp = (UBMAP + ctr)->ub_lo & 077;
} else
UISA->r[0] = uba;
UISD->r[0] = 077406; /* Set User I space PDR */
tppos = (hpaddr->hpec1 - 1)/16; /* word addr of error burst */
tpofst = (hpaddr->hpec1 - 1)%16; /* bit in word */
/* ECC FIX */ if((bp->b_flags&B_MAP) == 0)
bsp = ((int)hpaddr->hpba & 077);
bsp += (tppos*2);
tpbad[0] = fuiword(bsp);
tpbad[1] = fuiword(bsp+2);
tpbad[0] ^= (hpaddr->hpec2 << tpofst); /* xor first word */
if(tpofst > 5) { /* must fix second word */
ctr = (hpaddr->hpec2 >> 1) & ~0100000;
if(tpofst < 15)
ctr = ctr >> (15 - tpofst);
tpbad[1] ^= ctr; /* xor second word */
}
suiword(bsp,tpbad[0]);
suiword((bsp+2),tpbad[1]);
UISD->r[0] = tpuis[1]; /* restore User PDR */
UISA->r[0] = tpuis[0]; /* restore User PAR */
splx(pri);
/* now see if transfer finished. */
/* If not then reset;track,sector,etc. */
if(hpaddr->hpwc != 0)
{
hpaddr->hpcs1.w = TRE|DCLR|GO;
hp_r[ind].bads |= BAD_CON;
hpstart(ctrl); /* Continue transfer */
return;
}
hptab[ctrl].b_active++;
}
/* End of ECC code */
switch(hp_dt[ind]){
case RP04:
case RP05:
case RP06:
if(hpaddr->hper1 & 020)/* Fmt Error */
if(hpvector(bp, ctrl, ind, hpaddr->hpwc)){
hp_r[ind].bads |= BAD_VEC;
hptab[ctrl].b_errcnt--;
hpaddr->hper1 = 0;
hpstart(ctrl);
return;
}
break;
case RM02:
case RM03:
case RM05:
if(hpaddr->hper3 & DCK) /* BSE Error */
if(hpvector(bp, ctrl, ind, hpaddr->hpwc)){
hp_r[ind].bads |= BAD_VEC;
hptab[ctrl].b_errcnt--;
hpaddr->hper3 = 0;
hpstart(ctrl);
return;
}
break;
default:
break;
}
hpaddr->hpcs1.w = TRE|IE|DCLR|GO;
if(((hptab[ctrl].b_errcnt&07) == 4)&& (hp_dt[ind] != ML11)) {
hpaddr->hpcs1.w = RECAL|IE|GO;
while(hpaddr->hpds & PIP)
;
}
}
if(hptab[ctrl].b_active) {
if((hptab[ctrl].b_errcnt) && (hp_dt[ind] != ML11)) {
hpaddr->hpcs1.w = RTC|GO;
while(hpaddr->hpds & PIP)
;
}
if(hptab[ctrl].b_errcnt || (bp->b_flags & B_ERROR))
{
if(hp_ebuf[ctrl].hp_reg[6] & WLE)
printf("\n%s unit %d Write Locked\n",
hp_dct[ctrl], unit);
else {
hp_ebuf[ctrl].hp_bdh.bd_errcnt = hptab[ctrl].b_errcnt;
if(!logerr(E_BD, &hp_ebuf[ctrl], sizeof(struct hp_ebuf)))
deverror(bp, hp_ebuf[ctrl].hp_reg[4], hp_ebuf[ctrl].hp_reg[6]);
}
}
if(hp_r[ind].bads&BAD_VEC &&(bp->b_flags&B_ERROR)==0){
hp_r[ind].bads &= ~BAD_VEC;
if(hp_res[ctrl].r_cc > 0){
hp_r[ind].bads |= BAD_CON;
hpstart(ctrl);
return;
}
}
el_bdact &= ~(1 << (HP_BMAJ+ctrl));
hp_r[ind].bads &= ~(BAD_VEC|BAD_CON);
hptab[ctrl].b_active = 0;
hptab[ctrl].b_errcnt = 0;
hptab[ctrl].b_actf = dp->b_forw;
dp->b_active = 0;
dp->b_errcnt = 0;
dp->b_actf = bp->av_forw;
bp->b_resid = -(hpaddr->hpwc<<1);
iodone(bp);
hpaddr->hpcs1.w = DPRLS|GO; /* usseize dual port drive*/
hpaddr->hpcs1.w = IE;
if(dp->b_actf)
hpustart(ctrl, unit);
}
as &= ~(1<<unit);
} else {
if(as == 0)
hpaddr->hpcs1.w = IE;
hpaddr->hpcs1.c[1] = TRE>>8;
}
for(unit=0; unit<8; unit++)
if(as & (1<<unit)) {
hpaddr->hpcs2.w = unit;
hpaddr->hpcs1.w = (DCLR|GO);
/*
* In case the attention came from
* a drive that is seized by the other
* port, clear the attention summary bit.
*/
hpaddr->hpas = (1<<unit); /* clear attn bit */
if(unit >= nhp[ctrl])
hpaddr->hpcs1.c[0] = IE;
else
hpustart(ctrl, unit);
}
hpstart(ctrl);
}
static
hpvector(bp, ctrl, ind, wc)
struct buf *bp;
{
register int dt, cn, tn;
int sn, j;
long bn;
fixbad(&hp_res[ctrl], bp, wc, 1);
dt = hp_dipset(ind);
bn = bp->b_blkno;
bn += ((bp->b_bcount - hp_res[ctrl].r_cc)/512)-1;
cn = bn/hpdi[dt].nbpc
+ hp_sizes[(minor(bp->b_dev)&7)+hpdi[dt].sti].cyloff;
sn = bn%hpdi[dt].nbpc;
tn = (sn/hpdi[dt].nsect)<<8;
tn |= sn%hpdi[dt].nsect;
if((j = isbad(&hp_bads[ind], cn, tn, hpdi[dt].nsect)) >= 0){
hp_res[ctrl].r_vbn = (hp_r[ind].vcyl - 1) - j;
#ifdef HPBAD
hp_bads[ind].pbt_vec[j]++;
#endif
return(1);
}
return(0);
}
hpread(dev)
{
physio(hpstrategy, &rhpbuf[hpctrl(dev)], dev, B_READ);
}
hpwrite(dev)
{
physio(hpstrategy, &rhpbuf[hpctrl(dev)], dev, B_WRITE);
}
/*
* Set the drive information pointer
* according to the drive type.
*/
static
hp_dipset(ind)
{
switch(hp_dt[ind]) {
case RP04:
case RP05:
hp_r[ind].vcyl = 171798L - 22;
return(0);
case RP06:
hp_r[ind].vcyl = 340670L - 22;
return(0);
case RM02:
case RM03:
hp_r[ind].vcyl = 131680L - 32;
return(1);
case RM05:
hp_r[ind].vcyl = 500384L - 32;
return(2);
case ML11:
return(3);
}
}
/*
* Determine the RH11/RH70 controller number
* based on the major device.
*/
static
hpctrl(dev)
{
register int maj;
maj = (dev>>8) & 077;
if(maj < nblkdev)
return(maj - HP_BMAJ);
else
return(maj - HP_RMAJ);
}
hpclose(dev,flag)
dev_t dev;
{
bflclose(dev);
}