V10/lsys/md/staruddump.c
/*
* code to take a crash dump
* on a disk attached to a UDA50 on a 780
* your choice of a couple of unibus adapters,
* a couple of common uda addresses
* (wretched nonstandard alice)
*/
#include "sys/param.h"
#include "sys/mscp.h"
/*
* hardware parameters
*/
#define PHYS(x) ((long)(x)&~KSTART)
/*
* `unit' number is really unit, controller, unibus adapter
* one hopes that controller and adapter will usually be 0
*/
#define UUNIT(d) ((d)&0xff)
#define UCTL(d) (((d)>>8)&0xf)
#define UUBA(d) (((d)>>12)&0xf)
#define MAXUBA 2
static struct {
long reg; /* addr 0 in unibus space */
long adp; /* adapter registers */
} udxuba[MAXUBA] = {
{0x20100000, 0x20006000}, /* first unibus */
{0x20140000, 0x20008000}, /* second unibus */
};
#define UBMAP (0x800/4) /* offset to map regs */
#define CNFGR 0
#define UACR 1
#define ADINIT 01 /* UACR - adapter init */
#define UBIC 0x10000 /* CNFGR - init complete */
#define MAXUDA 2
static long udxaddr[MAXUDA] = {
0772150, 0772160
};
#define MRV 0x80000000 /* map register valid bit */
#define CHUNK 8 /* write this many sectors at once */
struct device {
short udip;
short udsa;
};
/*
* bits in udsa
*/
#define ERR 0100000
#define STEP4 040000
#define STEP3 020000
#define STEP2 010000
#define STEP1 04000
#define GO 01 /* step4 ok */
/*
* bits in ring pointers
*/
#define DPOWN 0x80000000 /* port owns descriptor */
struct udcmd {
short uc_len; /* length of message */
char uc_tc; /* type, credits */
char uc_cid; /* connection id */
struct mscmd uc_p;
};
struct udrsp {
short ur_len; /* length of message */
char ur_tc; /* type, credits */
char ur_cid; /* connection id */
struct msend ur_p;
};
static struct udx {
short ud__r0; /* reserved (ugh) */
char ud__r1;
char ud_bdp; /* path to purge */
short ud_cmdint; /* flag for command interrupt */
short ud_rspint; /* flag for response interrupt */
long ud_rsp; /* response pointer ring */
long ud_cmd; /* command pointer ring */
struct udcmd ud_cp; /* the only command packet */
struct udrsp ud_rp; /* the only response packet */
} udx;
static long udxbase;
static udxinit(), udxsend();
/*
* struct udx (above) is mapped into pages 0 and 1 of unibus space
* the memory we want to transfer goes into page 2 and above
*/
uddump(unit, low, size)
int unit;
daddr_t low, size;
{
register struct udx *up;
register long p;
register int i;
register long *ubmap;
register struct device *udaddr;
extern int physmem;
if (size > physmem)
size = physmem;
if ((i = UUBA(unit)) >= MAXUBA)
return (1);
ubmap = (long *)udxuba[i].adp;
ubmap[UACR] = ADINIT;
while ((ubmap[CNFGR] & UBIC) == 0)
;
ubmap += UBMAP;
if (UCTL(unit) >= MAXUDA)
return (1);
udaddr = (struct device *)(udxuba[i].reg + udxaddr[UCTL(unit)]);
unit = UUNIT(unit);
if (udxinit(udaddr, ubmap))
return (1);
up = (struct udx *)PHYS(&udx);
up->ud_cp.uc_p.m_unit = unit;
up->ud_cp.uc_p.m_opcd = OPONL;
if (udxsend(udaddr))
return (1);
up->ud_cp.uc_p.m_opcd = OPWR;
up->ud_cp.uc_p.m_bcnt = NBPG*CHUNK;
*(long *)&up->ud_cp.uc_p.m_buff = (2*NBPG);
for (p = 0; p < size; p += CHUNK) {
for (i = 0; i < CHUNK; i++)
ubmap[i+2] = MRV|(p+i);
up->ud_cp.uc_p.m_lbn = low + p;
if (udxsend(udaddr))
return (1);
}
return (0);
}
static
udxinit(rp, map)
register struct device *rp;
register long *map;
{
register struct udx *up;
up = (struct udx *)PHYS(&udx);
map[0] = ((long)up/NBPG)|MRV;
map[1] = (((long)up/NBPG)+1)|MRV;
udxbase = (long)up & ~PGOFSET;
up->ud_cmd = 0;
up->ud_rsp = 0;
rp->udip = 0; /* reset */
while ((rp->udsa & (ERR|STEP1)) == 0)
;
if (rp->udsa & ERR)
goto bad;
rp->udsa = ERR; /* no vector, no IE, ring size 1, 1 */
while ((rp->udsa & (ERR|STEP2)) == 0)
;
if (rp->udsa & ERR)
goto bad;
rp->udsa = ((long)&up->ud_rsp - udxbase); /* low order part */
while ((rp->udsa & (ERR|STEP3)) == 0)
;
if (rp->udsa & ERR)
goto bad;
rp->udsa = 0; /* high order part */
while ((rp->udsa & (ERR|STEP4)) == 0)
;
if (rp->udsa & ERR)
goto bad;
rp->udsa = GO;
return (0);
bad:
printf("sa %o\n", rp->udsa & 0xffff);
return (1);
}
static
udxsend(rp)
struct device *rp;
{
register struct udx *up;
register int x;
static int ref;
up = (struct udx *)PHYS(&udx);
up->ud_cp.uc_p.m_crf = ++ref;
up->ud_cp.uc_len = sizeof(struct mscmd);
up->ud_rp.ur_len = sizeof(struct msend);
up->ud_rsp = ((long)&up->ud_rp.ur_p - udxbase)|DPOWN;
up->ud_cmd = ((long)&up->ud_cp.uc_p - udxbase)|DPOWN;
x = rp->udip;
for (;;) {
while (up->ud_rsp & DPOWN)
;
if (up->ud_rp.ur_p.m_crf == ref)
break;
up->ud_rsp |= DPOWN;
}
if ((up->ud_rp.ur_p.m_sts & STMSK) != STSUC) {
printf("ud err %o opc %o\n", up->ud_rp.ur_p.m_sts,
up->ud_cp.uc_p.m_opcd);
return (1);
}
return (0);
}