Ultrix-3.1/sys/sys/errlog.c

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


/**********************************************************************
 *   Copyright (c) Digital Equipment Corporation 1984, 1985, 1986.    *
 *   All Rights Reserved. 					      *
 *   Reference "/usr/src/COPYRIGHT" for applicable restrictions.      *
 **********************************************************************/

/*
 * SCCSID: @(#)errlog.c	3.0	5/5/86
 */
/*
 * ULTRIX-11 kernel error log functions
 * Fred Canter 5/11/83
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/tmscp.h>	/* must preceed errlog.h (EL_MAXSZ) */
#include <sys/errlog.h>
#include <sys/buf.h>
#include <sys/reg.h>
#include <sys/seg.h>
#include <sys/dir.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/uba.h>

/*
 * Block I/O device error log buffer structure.
 */

struct	elbuf
{
	struct	elrhdr	bd_hdr;
	struct	el_bdh	e_bdh;
	int	e_dreg[];
};

/*
 * (fmtbde) - Format a block I/O device error log record.
 *
 * bp	= I/O buffer pointer
 * ebuf	= pointer to driver error log buffer
 * csr	= device CSR address
 * nreg	= number of device registers
 * dbr	= `data buffer' register offset
 *
 * The contents of the `data buffer' register are not
 * logged, because reading this type of register with
 * no data in the SILO causes a DATA LATE error.
*/

fmtbde(bp, ebuf, csr, nreg, dbr)
register struct buf *bp;
physadr	csr;
{
	register struct elbuf *ebp;
/*	register caddr_t dp; 	OHMS: caused System V C compiler error */
	register physadr dp;
	int i;

	ebp = ebuf;
	dp = csr;
	ebp->bd_hdr.e_time = time;	/* time stamp */
	ebp->e_bdh.bd_dev = bp->b_dev;	/* data from buffer header */
	ebp->e_bdh.bd_flags = bp->b_flags;
	ebp->e_bdh.bd_bcount = bp->b_bcount;
	if(bp->b_flags&B_MAP) {
		struct {
			short ubm_lo;
			short ubm_hi;
		} *ubmp = UBMAP;
		i = (((unsigned)bp->b_un.b_addr >> 13) & 7) 
			| (((unsigned)bp->b_xmem << 3) & 030);
		ebp->e_bdh.bd_addr = ubmp[i].ubm_lo;	/* real physical addr */
		ebp->e_bdh.bd_xmem = ubmp[i].ubm_hi;	/* from UB map reg */
	} else {
		ebp->e_bdh.bd_addr = bp->b_un.b_addr;
		ebp->e_bdh.bd_xmem = bp->b_xmem & 077;
	}
	ebp->e_bdh.bd_blkno = bp->b_blkno;
	ebp->e_bdh.bd_errcnt = 0;	/* driver loads retry counter later */
	ebp->e_bdh.bd_act = el_bdact;	/* block device activity */
	ebp->e_bdh.bd_csr = csr;	/* device CSR address */
	ebp->e_bdh.bd_nreg = nreg;	/* # of device registers */
	ebp->e_bdh.bd_mcact = ra_mcact;	/* MSCP cntlr activity */
	for(i=0; i<nreg; i++) {		/* log device registers */
		if(dbr && (i == dbr))		/* except for data buffer */
			ebp->e_dreg[i] = 0;
		else
			ebp->e_dreg[i] = dp->r[i];
	}
}

/*
 * (logerr) - Add a header & copy record to error log buffer.
 *
 * et	= type of error log record
 * ebuf	= pointer to driver error log buffer
 * sz	= size of driver's error log buffer in bytes
 *
 */

int	el_bact;	/* 0 = buffer empty, else # of records in buffer */
char	*el_bpi = &el_buf;
char	*el_bpo = &el_buf;

logerr(et, ebuf, sz)
struct elbuf *ebuf;
{
	register struct elbuf *debp, *kebp;
	register int *b;
	extern int el_buf[];
	int	hs, pri;
	int	*p;
	mapinfo	map;
	int	nelip;

	if(!el_on && (et != E_SU))
		return(0);	/* error logging disabled */
	if(el_on && (et == E_SU))
		return(0);	/* no startup if error logging already on */
	kebp = el_bpi;		/* kernel error log buffer pointer */
	debp = ebuf;		/* deivce error log buffer pointer */
	hs = sizeof(struct elrhdr);	/* size of record header */
	if(et == E_BD) {		/* block device error, */
		hs = 2;			/* time stamp already in buffer */
		sz -= 2;		/* if error on error log device, */
					/* don't try to log it, instead */
					/* print a message and disable logging */
/* the if statement was using wrong offsets:
		if((debp->e_bdh.b_dev == el_dev)
		 && (debp->e_bdh.b_blkno >= el_sb)
		 && (debp->e_bdh.b_blkno < (el_sb + el_nb))) {
***/
		if((debp->e_bdh.bd_dev == el_dev)
		 && (debp->e_bdh.bd_blkno >= el_sb)
		 && (debp->e_bdh.bd_blkno < (el_sb + el_nb))) {
			printf("\nlogerr: ERROR LOG DEVICE\n");
			el_on = 0;	/* disable error logging */
			return(0);
		}
	}
	/*
	 * Copy the error log record to the kernel buffer.
	 * If the buffer is full, return zero to cause the
	 * `missed error' message to be printed on the console.
	 * The kernel error log buffer is a circular buffer
	 * and is managed by the el_bpi & el_bpo pointers.
	 * If the input and output pointers are equal,
	 * then the buffer is empty.
	 */

	pri = spl7();	/* don't want to be interrupted */
	nelip = el_bpi + hs + sz;
	savemap(map);
	if(el_bact && (el_bpi == el_bpo))
		goto bad;
	if((el_bpi < el_bpo) && (nelip > el_bpo))
		goto bad;
	if(nelip > &el_buf[elbsiz]) {
		kebp->bd_hdr.e_type = 0;	/* mark end of buffer */
		kebp = &el_buf;		/* set pointer to start of buffer */
		el_bpi = &el_buf;
		if((el_bpi + hs + sz) > el_bpo) {
	bad:
			restormap(map);
			splx(pri);
			printf("\nlogerr: MISSED ERROR\n");
			return(0);
		}
	}
	el_bact++;				/* fill in record header */
	kebp->bd_hdr.e_type = et;		/* error record type */
	kebp->bd_hdr.e_size = (hs + sz);	/* total record size in bytes */
	if(et != E_BD)		/* time stamp, except for block device errors */
		kebp->bd_hdr.e_time = time;
	p = el_bpi+sizeof(struct elrhdr);	/* pointer to record body */
	b = debp;				/* pointer to driver buffer */
	if(et == E_BD) {	/* block device buffer has dummy header */
		b++;		/* skip over it (2 bytes) */
		p -= 2;		/* BD buf has time stamp in it */
	}
	sz /= 2;
	while(sz--)
		*p++ = *b++;	/* copy record body to kernel buffer */
	el_bpi = p;			/* now points to start of next record */
	if(et == E_SU)
		el_on = 1;		/* if startup record, enable logging */
	if(et == E_SD)
		el_on = 0;		/* if shutdown, disable logging */
	restormap(map);
	splx(pri);
	wakeup((caddr_t)&el_buf);	/* wakeup error copy process */
	return(1);
}

/*
 * errlog() - error logging control and status system call.
 * 
 *
 * func	= function code (see errlog.h)
 * bufp	= user buffer pointer, for argument return
 */

char	ra_ctid[];	/* RA controller type ID, see ra.c */

errlog()
{
	register struct a {
		int	func;	/* function code */
		int	bufp;	/* user buffer pointer */
		} *uap;
	register char *ubp;
	register int *kbp;
	int	ebuf[5];
	int pri, i;

	uap = (struct a *)u.u_ap;
	if(!suser())
		return;		/* only super-user can use errlog() */
	switch(uap->func) {
	case EL_OFFNL:	/* disable error logging, don't log shutdown */
		el_on = 0;
		break;
	case EL_OFF:	/* disable error logging & log shutdown */
		logerr(E_SD, &ebuf, 0);
		break;
	case EL_ON:	/* enable error logging & and log a startup */
		ebuf[0] = cputype;
		ebuf[1] = rn_ssr3;	/* release # / M/M SSR 3 */
		ebuf[2] = el_bdcw;	/* block device config word */
		ebuf[3] = el_cdcw;	/* char device config word */
/*
 * Save MSCP cntlr types,
 * see conf/uda.c for ra_ctid[] format.
 */
		for(i=3; i>=0; i--) {
			ebuf[4] <<= 4;
			ebuf[4] |= ((ra_ctid[i] >> 4) & 017);
		}
		logerr(E_SU, &ebuf, sizeof(ebuf));	/* log a startup */
		break;
	case EL_INIT:	/* disable logging & init kernel buffer */
		el_on = 0;
		el_bpi = &el_buf;
		el_bpo = &el_buf;
		el_bact = 0;	/* say error log buffer empty */
		el_init = 1;	/* error log buffer reinit flag */
		break;
	case EL_WAIT:	/* sleep elc process at hi priority */
		el_c_pid = u.u_procp->p_pid;  /* save elc process ID */
					     /* so clock.c will not nice it */
		sleep((caddr_t)&el_buf, PZERO - 20);
		break;
	case EL_REC:	/* move an error log record to caller's buffer */
		ubp = uap->bufp;	/* user's buffer pointer */
		if(el_init) {		/* if error log has been init'ed */
			el_init = 0;	/* tell elc process about it  ! */
			suword((caddr_t)ubp, E_INIT);
			break;
		}
		if(el_bpi == el_bpo)
			suword((caddr_t)ubp, E_EOF);	/* no more records */
		else {
			(caddr_t)kbp = el_bpo;
			if((*kbp & 0377) == E_EOF)  /* end of kernel buffer */
				kbp = &el_buf;
			i = *kbp & 0377;	/* check for bad record */
			if(i < 0 || i > E_BD) {	/* bad error type */
		badrec:
				suword((caddr_t)ubp, E_BADR);
				break;
			}
			i = (*kbp >> 8) & 0377;	/* bad size */
			if((i <= 0) || (i & 1) || (i >EL_MAXSZ))
				goto badrec;
			pri = spl7();
			for(i=(((*kbp >> 8)&0377)/2); i; i--) {
				suword((caddr_t)ubp, *kbp++);
				ubp += 2;
			}
			el_bpo = kbp;
			if(el_bpi == el_bpo)
				el_bact = 0;
			splx(pri);
		}
		break;
	case EL_INFO:	/* pass system error log information to elc & elp */
			/* frees elc & elp form dependence on nlist */
		ubp = uap->bufp;	/* pointer to user's buffer */
		suword((caddr_t)ubp, el_dev);
		ubp += 2;
		suword((caddr_t)ubp, (int)(el_sb >> 16));	/* LONG */
		ubp += 2;
		suword((caddr_t)ubp, (int)el_sb);
		ubp += 2;
		suword((caddr_t)ubp, el_nb);
		ubp += 2;
		suword((caddr_t)ubp, nblkdev);
		break;
	default:	/* invalid function code or not super-user */
		psignal(u.u_procp, SIGSYS);
		break;
	}
}

/*
 * Log a stray device interrupt.
 *
 * A stray interrupt is defined as one that occurs for
 * a configured device through a valid vector address,
 * but is unexpected. In the case of big disks, a stray
 * interrupt is logged when the interrupt service routine
 * is entered and the device is not active and no attention
 * summary bits are set.
 */

logsi(csr)
{
	int	si_ebuf[3];

	si_ebuf[0] = csr;	/* device's CSR address */
	si_ebuf[1] = el_bdact;	/* other block device activity */
	si_ebuf[2] = ra_mcact;	/* MSCP controller activity */
	logerr(E_SI, &si_ebuf, sizeof(si_ebuf));
	printf("\nSI %o\n", si_ebuf[0]);
}

/*
 * Interface from unused vectors to the stray
 * vector logging routine.
 */

sv0(dev)
{
	logsv(dev, 0);
}

sv100(dev)
{
	logsv(dev, 0100);
}

sv200(dev)
{
	logsv(dev, 0200);
}

sv300(dev)
{
	logsv(dev, 0300);
}

sv400(dev)
{
	logsv(dev, 0400);
}

sv500(dev)
{
	logsv(dev, 0500);
}

sv600(dev)
{
	logsv(dev, 0600);
}

sv700(dev)
{
	logsv(dev, 0700);
}

/*
 * Log a stray vector, i.e., a vector thru
 * an unused vector location.
 * The most common of these is thru location zero.
 *
 * base	- base address of a group of 16 vector locations
 * dev	- offset into that group
 */

logsv(dev, base)
{
	int	sv_ebuf[3];

	sv_ebuf[0] = base + ((dev &017) << 2);	/* vector address */
	sv_ebuf[1] = el_bdact;	/* other block device activity */
	sv_ebuf[2] = ra_mcact;	/* MSCP controller activity */
	logerr(E_SV, &sv_ebuf, sizeof(sv_ebuf));
	printf("\nSV %o\n", sv_ebuf[0]);
}