#include "../h/local.h"

#ifdef  SCCS_ID
static char SCCS_ID [] = "@(#)prf.c    	3.2	 01:50:16 - 81/12/10 ";
#endif  SCCS_ID

#include "../h/param.h"
#include "../h/systm.h"
#include "../h/seg.h"
#include "../h/buf.h"
#include "../h/conf.h"
#ifdef  UCB_FSNAM
#include "../h/mount.h"
#include "../h/filsys.h"
#endif  UCB_FSNAM

/*
 * In case console is off,
 * panicstr contains argument to last
 * call to panic.
 */

char	*panicstr;

/*
 * Scaled down version of C Library printf.
 * Only %s %u %d (==%u) %o %x %D %O are recognized.
 * Used to print diagnostic information
 * directly on console tty.
 * Since it is not interrupt driven,
 * all system activities are pretty much
 * suspended.
 * Printf should not be used for chit-chat.
 */
/* VARARGS 1 */
printf(fmt, x1)
register char *fmt;
unsigned x1;
{
	register c;
	register unsigned int *adx;
	char *s;

	adx = &x1;
loop:
	while((c = *fmt++) != '%') {
		if(c == '\0')
			return;
		putchar(c);
	}
	c = *fmt++;
	if(c == 'd' || c == 'u' || c == 'o' || c == 'x')
		printn((long)*adx, c=='o'? 8: (c=='x'? 16:10));
	else if(c == 's') {
		s = (char *)*adx;
		while(c = *s++)
			putchar(c);
#ifdef UCB_DEVERR
	} else if (c == 'D' || c == 'O') {
		printn(*(long *)adx, c=='D'?10:8);
#else  UCB_DEVERR
	} else if (c == 'D') {
		printn(*(long *)adx, 10);
#endif UCB_DEVERR
		adx += (sizeof(long) / sizeof(int)) - 1;
	}
#ifdef  UCB_DEVERR
	/*
	 * Additional format: %b for decoding error registers.
	 * Usage is:
	 *      printf("reg=%b\n", regval, "<base><arg>*");
	 * Where <base> is the output base expressed as a control character,
	 * e.g. \10 gives octal; \20 gives hex.  Each arg is a sequence of
	 * characters, the first of which gives the bit number to be inspected
	 * (origin 1), and the next characters (up to a control character, i.e.
	 * a character <=16), give the name of the register.  Thus
	 *      printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE");
	 * would produce output:
	 *      reg=3<BITTWO,BITONE>
	 */
	else if (c == 'b') {
		unsigned b;
		int i, any;

		b = *adx++;
		s = (char *)*adx;
		printn((long)b, *s++);
		any = 0;
		if (b) {
			putchar('<');
			while (i = *s++) {
				if (b & (1 << (i-1))) {
					if (any)
						putchar(',');
					any = 1;
					for (; (c = *s) > 16; s++)
						putchar(c);
				} else
					for (; *s > 16; s++)
						;
			}
			putchar('>');
		}
	}
#endif  UCB_DEVERR
	adx++;
	goto loop;
}

/*
 * Print an unsigned integer in base b.
 */
printn(n, b)
long n;
{
	register long a;

	if (n<0) {	/* shouldn't happen */
		putchar('-');
		n = -n;
	}
	if(a = n/b)
		printn(a, b);
	putchar("0123456789ABCDEF"[(int)(n%b)]);
}

/*
 * Panic is called on unresolvable
 * fatal errors.
 * It syncs, prints "panic: mesg" and
 * then loops.
 */
panic(s)
char *s;
{
#ifdef  CGL_AUTOB
	int i, j;
#endif  CGL_AUTOB

	panicstr = s;
#ifdef  CGL_AUTOB
	printf("\007\007\007\007\n\nSYSTEM FAULT\n\n");
	printf("panic: %s\n", s);
	spl0();
	printf("syncing disks...");
	for (i=j=0; i<15; i++)
		while(--j);     /* wait for sync to finish */
	printf("done\n");
	autoboot(1);
#else   UCB_AUTOB
	update();
	printf("panic: %s\n", s);
	for(;;)
		idle();
#endif  UCB_AUTOB
}

#ifdef  CGL_AUTOB
#define HPCS1 ((physadr)0176700) /* csr of boot disk */
#define LOC2 ((physadr)02)
#define JMPI 0137       /* jmp (pc)+ */

autoboot(flag)
{
	int reboot(), reboot1();

	if (CSW->r[0] == SNGLU) /* magic csr setting for manual intervention */
		for(;;)
			idle();
	spl7();
	while ((HPCS1->r[0] & 0200) == 0);      /* wait for xfer to finish */
	LOC2->r[0] = JMPI;
	if (flag)
		LOC2->r[1] = (int)reboot;       /* dump memory first */
	else
		LOC2->r[1] = (int)reboot1;      /* no memory dump */
	reset();        /* (in l.s) */
	/* NOTREACHED */
}
#endif  UCB_AUTOB

/*
 * prdev prints a warning message of the
 * form "mesg on dev x/y".
 * x and y are the major and minor parts of
 * the device argument.
 */
prdev(str, dev)
char *str;
dev_t dev;
{
#ifdef  UCB_FSNAM
	register struct mount *mp;
	register struct filsys *fp;

	for (mp = &mount[0]; mp < mountNMOUNT; mp++)
		if (mp->m_bufp!=NULL && mp->m_dev==dev) {
#ifdef  UCB_MOUNT
			fp = mp->m_caddr;
#else   UCB_MOUNT
			fp = mp->m_bufp->b_un.b_filsys;
#endif  UCB_MOUNT
			printf("%s on %s (%u/%u)\n", str, fp->s_fsmnt,
				major(dev), minor(dev));
			return;
		}
#endif  UCB_FSNAM
	printf("%s on dev %u/%u\n", str, major(dev), minor(dev));
}

/*
 * deverr prints a diagnostic from
 * a device driver.
 * It prints the device, block number,
 * and an octal word (usually some error
 * status register) passed as argument.
 */
deverror(bp, o1, o2)
register struct buf *bp;
{

	prdev("err", bp->b_dev);
#ifdef DEC
	printf("bn=%D er=%o,%o\n", bp->b_blkno, o1, o2);
#else
	printf("bn=%D er=%x ad=%x\n", bp->b_blkno, o1, o2);
#endif
}
