V10/sys/md/mchkstar.c

Compare this file to the similar file:
Show the results in this format:

/*
 * routines that deal closely with
 * machine checks and the like
 * VAX-11/780 version
 */

#include "sys/param.h"
#include "sys/systm.h"
#include "sys/psl.h"
#include "sys/mtpr.h"
#include "sys/user.h"

/*
 * SBI-related registers
 */

#define	SBIFS	48		/* SBI fault and status */
#define	SBIMT	51		/* SBI and cache maint */
#define	SBIER	52		/* SBI error */
#define	SBITA	53		/* SBI timeout address */

#define	FSNEF	0x2000000	/* nested error flag in fault status */
#define	FSIE	0x40000		/* interrupt enable for sbi faults */

#define	ERCLR	0x70c0		/* latches in error register: */
				/* ib timeout, ib rds, cp timeout, rds, crd */

#define	TAMODE	0xc0000000	/* mode of failure for wtmo, 3 == user */
#define	TAPROT	0x20000000	/* protection checked reference; off -> pt */

struct mframe {
	long count;
	long type;
	long ces;
	long upc;
	long vaddr;
	long dr;
	long tb0;
	long tb1;
	long paddr;
	long par;
	long sbi;
	long pc;
	long psl;
};

#define	NMCK	16		/* number of possible type codes */
static char *macher[NMCK] = {
	"read timeout",
	"control store parity",
	"trans buffer parity",
	"cache parity",
	"-",
	"read data substitute",
	"microcode lost",
	"-",
	"-",
	"-",
	"ib trans buffer parity",
	"-",
	"ib read data substitute",
	"ib read timeout",
	"-",
	"ib cache parity",
};

int mchkcnt[NMCK];	/* number of mchecks of each type */
int mchktime[NMCK];	/* time of last mcheck */

/*
 * table of resumable instructions
 * a table of bits, indexed by opcode
 * this is taken straight from vms;
 * don't ask me to justify choices
 */

static char mrestab[256/8] = {
	0x3b,	/* rei ldpctx svpctx */
	0x3c,	/* insque remque cvtps cvtsp */
	0xff,
	0xff,
	0x0,	/* packed decimal stuff */
	0xff,
	0xff,
	0xfe,	/* editpc */
	0xff,
	0xff,
	0x2f,	/* emodf cvtfd adawi */
	0x0,	/* more interlocked instructions */
	0x0,	/* double precision floating point */
	0x0f,	/* more double stuff */
	0x4a,	/* more double/quad */
	0xc1,	/* .. */
	0xff,
	0xff,
	0xff,
	0xff,
	0xff,
	0xff,
	0xff,
	0xf3,	/* pushr popr */
	0xff,
	0xff,
	0xff,
	0xf4,	/* adwc sbwc mfpr */
	0x3f,	/* bbssi bbcci */
	0xff,
	0xff,
	0x0,	/* ashp cvtlp callg calls xfc reserved */
};

/*
 * bits in machine check type code
 */

#define	TYPE	0xf		/* the real type code */
#define	IB	0x8		/* set if detected by instruction prefetch */
#define	ABORT	0xf0		/* this was an abort */
#define	TIMEOUT	0x100		/* timeout pending */

/*
 * types
 */

#define	CPTIMEOUT	0	/* read timeout */
#define	CSPAR		1	/* control store parity */
#define	TBUFPAR		2	/* translation buffer parity */
#define	CACHEPAR	3	/* cache parity */
#define	RDSUBST		5	/* read data substitute */
#define	IBROMCHK	6	/* confused microcode */
#define	IBTBUF		10	/* ib-detected translation buffer parity */
#define	IBRDSUB		12	/* ib-detected read substitute */
#define	IBTIMEOUT	13	/* ib-detected read timeout */
#define	IBCACHE		15	/* ib-detected cache parity */

/*
 * bits in cache error register
 */

#define	G0OK	0x3f8		/* `ok' bits for group 0 */

/*
 * bits in sbi maint register
 */

#define	G1REPL	0x2000		/* force replace in group 1 */
#define	G0REPL	0x4000		/* force replace in group 0 */
#define	G1MISS	0x8000		/* force miss in group 1 */
#define	G0MISS	0x10000		/* force miss in group 0 */
#define	SBIINV	0x200000	/* enable sbi invalidate */

#define	CACHEOFF	(G0REPL|G1MISS|G0MISS|SBIINV)

static int mchkkill;	/* number of times we've recovered by killing */
static int mchklock;	/* reentrancy lock */
static int mchkcache = SBIINV;	/* current state of cache disable bits */

/*
 * sbi fault
 * yell and hope for the best
 */

sbifault()
{
	register int fs, er;

	fs = mfpr(SBIFS);
	er = mfpr(SBIER);
	machreset();
	printf("sbi fault: fs %x er %x\n", fs, er);
}

/*
 * SBI write timeout
 * no recovery;
 * panic if kernel or if updating page table
 * else just signal
 */

machwtmo()
{
	register int fs, er, ta;

	fs = mfpr(SBIFS);
	er = mfpr(SBIER);
	ta = mfpr(SBITA);
	machreset();
	printf("sbi write timeout: fs %x er %x ta %x\n", fs, er, ta);
	if ((ta & (TAMODE | TAPROT)) != (TAMODE | TAPROT))
		panic("wtmo");
	runrun++;
	aston();
	psignal(u.u_procp, SIGBUS);
}

/*
 * clear latches in sbi error registers
 */

machreset()
{
	mtpr(SBIFS, (mfpr(SBIFS) &~ FSNEF)|FSIE);
	mtpr(SBIER, mfpr(SBIER) | ERCLR);
}

/*
 * Machine check.
 * If possible, recover and return;
 * if not but in user mode, send a signal;
 * if not and in kernel mode, panic.
 */

machinecheck(ps, f)
long ps;
struct mframe *f;
{
	int ok;

	ok = mckrec(f);
	machreset();
	printf("\nMachine check, type %x\n", f->type);
	if ((f->type & ABORT) == 0)
		printf("%s fault\n", macher[f->type & TYPE]);
	else
		printf("%s abort\n", macher[f->type & TYPE]);
	printf("pc %x psl %x\n", f->pc, f->psl);
	printf("v/p addr %x/%x\n", f->vaddr, f->paddr<<2);
	printf("ces %x sbi %x\n", f->ces, f->sbi);
	if (ok)
		return;
	if (USERMODE(ps)) {
		/*
		 * code stolen from setrun
		 */
		runrun++;
		aston();
		psignal(u.u_procp, SIGBUS);
		return;
	}
	panic("mchk");
}

/*
 * here to look at machine check type
 * and arrange for recovery if possible
 * cache is still turned off when we start
 * return nonzero if we recovered
 */

int
mckrec(f)
register struct mframe *f;
{
	register int x;

	mchkcnt[f->type & TYPE]++;
	switch (f->type & TYPE) {
	case TBUFPAR:		/* trans buffer parity */
	case IBTBUF:
		mtpr(TBIA, 0);	/* clear the buffer */
		mtpr(SBIMT, mchkcache);
		break;

	case IBROMCHK:		/* unexpected microcode confusion */
	case CSPAR:		/* control store parity */
		mtpr(SBIMT, mchkcache);
		return (0);	/* can never recover */

	case CACHEPAR:		/* cache parity error */
	case IBCACHE:
		/*
		 * force bad stuff to be replaced
		 * in both cache groups
		 */
		x = *(char *)f->vaddr;
		mtpr(SBIMT, CACHEOFF);
		x = 0;		/* defeat optimizer */
		x = *(char *)f->vaddr;
		if ((f->par & G0OK) != G0OK) {
			printf("group 0 off\n");
			mchkcache |= G0MISS | G0REPL;
			mchkcache &=~ G1REPL;	/* don't replace both groups */
		}
		else {
			printf("group 1 off\n");
			mchkcache |= G1MISS | G1REPL;
			mchkcache &=~ G0REPL;
		}
		mtpr(SBIMT, mchkcache);
		break;

	case CPTIMEOUT:
	case IBTIMEOUT:
		mtpr(SBIMT, mchkcache);
		break;

	case RDSUBST:		/* read data substitute == hard mem err */
	case IBRDSUB:
		mtpr(SBIMT, mchkcache);
		memerr();
		return (0);

	default:
		mtpr(SBIMT, mchkcache);
		panic("weird mcheck");
	}
	/*
	 * if we get here, it's potentially recoverable
	 * may recover if:
	 * haven't had one in the last second
	 * not an abort or timeout
	 * detected by lookahead, or resumable instruction
	 */
	if (mchktime[f->type & TYPE] == time)
		return (0);
	mchktime[f->type & TYPE] = time;
	if (f->type & (ABORT | TIMEOUT))
		return (0);
	if (f->type & IB)
		return (1);
	x = *(char *)f->pc & 0377;
	if (mrestab[x >> 3] & (1 << (x & 07)))
		return (1);
	return (0);
}