V10/lsys/md/comethpdump.c
/*
* code to take a crash dump
* on a disk attached to an SMD disk controller
* calls hp.c (unfortunately) to figure out disk geometry
* unit number is drive | (mba number << 8)
*/
#include "sys/param.h"
#include "sys/hp.h"
#include "sys/mbsts.h"
#define MBANO(u) (((u)>>8)&0xf)
#define DRVNO(u) ((u)&0xf)
/*
* hardware parameters
*/
#define PHYS(x) ((long)(x)&~KSTART)
#define MAXMBA 4
static long mbxaddr[] = {0xf28000, 0xf2a000, 0xf2c000, 0xf2e000};
#define MBAUNITS 8
#define NMAP 256
struct mbaregs {
long conf; /* configuration register; unused */
long cr; /* control register */
long sr; /* status register */
long va; /* address */
long bcr; /* count */
long _junk0[251]; /* pad up to 0x400 */
long devreg[MBAUNITS][32];
long map[NMAP];
};
#define CRINIT 0x1 /* cr -- init adapter */
#define MRV 0x80000000 /* map register valid bit */
#define CHUNK 8 /* write this many sectors at once */
#define SECSIZE 512 /* size of a sector */
/*
* disk registers
*/
struct hpdevice {
int hpcs1; /* control and status register 1 */
int hpds; /* drive status */
int hper1; /* error register 1 */
int hpmr; /* maintenance */
int hpas; /* attention summary */
int hpda; /* desired address register */
int hpdt; /* drive type */
int hpla; /* look ahead */
int hpsn; /* serial number */
int hpof; /* offset register */
int hpdc; /* desired cylinder address register */
int hpcc; /* current cylinder */
/* on an rp drive, mr2 is called er2 and er2 is called er3 */
/* we use rm terminology here */
int hpmr2; /* maintenance register 2 */
int hper2; /* error register 2 */
int hpec1; /* burst error bit position */
int hpec2; /* burst error bit pattern */
};
/*
* hpcs1
*/
#define HP_GO 0000001
#define HP_DCLR 010 /* drive clear */
#define HP_PRESET 020 /* read-in preset */
#define HP_WCOM 060 /* write */
/*
* hpof
*/
#define HPOF_FMT22 0010000 /* 16 bit format */
/*
* hpds
*/
#define HPDS_ERR 040000 /* error summary */
static hpxtype;
static struct hpdevice *hpxdev;
static struct mbaregs *hpxmba;
extern struct hptype hptype[];
static hpxwrite(), hpxinit();
hpdump(unit, low, size)
int unit;
daddr_t low, size;
{
register long p;
register int i;
register long *map;
extern int physmem;
if (size > physmem)
size = physmem;
size -= CHUNK-1;
if (hpxinit(unit))
return (1);
map = hpxmba->map;
for (p = 0; p < size; p += CHUNK) {
for (i = 0; i < CHUNK; i++)
map[i] = MRV|(p+i);
if (hpxwrite(low+p))
return (1);
}
return (0);
}
/*
* clear the controller and reset it
* hereafter, upcs2 has the unit number we want (we assume)
*/
static
hpxinit(unit)
int unit;
{
register struct hpdevice *rp;
register int i;
if ((i = MBANO(unit)) >= MAXMBA)
return (1);
hpxmba = (struct mbaregs *)mbxaddr[i];
if ((i = DRVNO(unit)) >= MBAUNITS)
return (1);
hpxdev = rp = (struct hpdevice *)hpxmba->devreg[i];
hpxmba->cr = CRINIT;
if ((hpxtype = hputype(rp)) < 0) {
printf("hpdump: can't init\n");
return (1);
}
rp->hpcs1 = HP_DCLR|HP_GO;
rp->hpcs1 = HP_PRESET|HP_GO;
rp->hpof = HPOF_FMT22;
return (0);
}
static
hpxwrite(bno)
register long bno;
{
register struct hpdevice *rp;
register struct mbaregs *mp;
register struct hptype *sp;
register int ts; /* track and sector */
rp = hpxdev;
mp = hpxmba;
sp = &hptype[hpxtype];
ts = bno % sp->nsect;
bno /= sp->nsect;
ts |= (bno%sp->ntrak)<<8;
bno /= sp->ntrak;
rp->hpdc = bno;
rp->hpda = ts;
mp->bcr = -(CHUNK*SECSIZE);
mp->va = 0;
rp->hpcs1 = HP_WCOM|HP_GO;
while ((mp->sr & MBSR_DTCMP) == 0)
;
if (mp->sr & MBSR_EBITS || rp->hpds & HPDS_ERR)
return (1);
return (0);
}