V10/sys/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);
}