SysIII/usr/src/cmd/rp6fmt.c

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

#include <stdio.h>
#include <sys/types.h>
#define RP06_0
#include <sys/io.h>
#define RP6CYL 815	/* no. RP06 cylinders/pack */
#define RP6TRK 19	/* no. tracks/cyl */
#define RP6SEC 22	/* no. sectors/track */
#define RP6ST (RP6SEC*RP6TRK)	/* no. sectors/cyl */
#define MAXSEC (RP6CYL*RP6TRK*RP6SEC)	/* sectors/pack */
#define RPHEAD 8	/* no. sector header bytes supplied by user */
#define M_BASE 0x20010000	/* phys addr MBA 0 */
#define MBAinit 01	/* MBA init bit */
#define MB_ERR 0x3080	/* expected error bits in MBA status reg */
#define RP_GO 1		/* go bit */
#define RP_OFF 014	/* head offset */
#define RP_RTC 016	/* Return to Centerline */
#define RP_RED 070	/* Read */
#define RP_RHD 072	/* RP06 read sector header and date */
#define RP_WHD 062	/* RP06 write sector header and data */
#define RP_WCH 052	/* Write Check Header and Data */
#define RP_DC 010	/* drive clear */
#define RP_FMT 0x1000	/* format bit for offset reg */
#define RP_RIP 0x10	/* Read-in Preset RP06 */
#define RP_DRY 0x80	/* drive ready, status reg */
#define RP_ERR 0x4000	/* composite error, status reg */
#define RP_MOL 0x1000	/* medium-online bit in status reg */
#define RP_WRL 0x800	/* write lock status */
#define RP_ECH 0x40	/* ECC Hard Error */
#define RP_DCK 0x8000	/* ECC */
#define RP_HCRC 0x100	/* header crc err */
#define RP_HCE 0x80	/* header compare err */
#define RP_FER 0x10	/* format err */
#define RP_PAR 0x8	/* parity err */
#define RP_HCI 0x400	/* Header Compare Inhibit, offset reg */
#define RP_ECI 0x800	/* ECC Inhibit, offset reg	*/
#define M_WCKU 0x400	/* Write Check Upper error status - MBA */
#define M_WCKL 0x200	/* Write Check Lower error status - MBA */
#define BLKSIZ 512
#define BUFSZ ((RPHEAD + BLKSIZ) * RP6SEC)
#define MAXUNI 8	/* max. no. units on MBA */
#define MAXMBA 4	/* no. MBA's on system */
#define MAXERR 50
#define PTRN1 0xeb6d	/* DEC defined */
#define PTRN2 0xb6db	/* worst case pattern */
#define OBOFF (((int)obuf) & 0x1ff)
#define IBOFF (((int)ibuf) & 0x1ff)
#define IBMAP0 (128 << 9)
int Report = 0;
union MBREGS {
	struct MBAR {
		int M_csr,	 M_cr,	 M_sr,
		M_var, 	M_bc;
	}Mbar;
		struct {char fill1[0x400];
		struct RPR {
			int	RP_cr, RP_ds, RP_er1, RP_mr;
			int	RP_as, RP_da, RP_dt, RP_la;
			int	RP_sn, RP_off, RP_cyl, RP_cc;
			int	RP_err2, RP_err3, RP_Epos, RP_Epat;
			int	fill2[16];
		} RPreg[8];
	}Unit;
	struct MAP {long fill3[0x200], M_map[256];}Map;
} *Mptr;
struct sect {
	short s_cyl[1];
	char  s_sec;
	char  s_trk;
	short s_kw1, s_kw2;
	short s_data[256];
}; 
int track, cylndr, secnum, mnum, dunit, ecount, daterr, wcerr;
char wcrflg;
char *ibuf, *obuf;	/* buffer pointers */
short fmtflg;
int Offset[]	/* Centerline offsets */
	= {0, 0x08, 0x88, 0x10, 0x90, 0x18, 0x98, -1
}; 
struct EL {
	int e_typ, e_cyl, e_trk, e_err;
} errlst[MAXERR];
struct RPR *RPptr,Test;
extern char *malloc();
extern char *errtyp();
	/*
	* Stand-alone program to format RP06 disk.
	* User specifies disk unit.
	*/
main() 
{
	int i, j;
	char c;
	printf("rp6fmt: Format RP06 Disk\n");
#ifndef TEST
	if(ckcomp()) return;
#endif
	obuf = malloc(BUFSZ);
	ibuf = malloc(BUFSZ);
	dunit = 0;
	mnum = 0;
#ifndef TEST
	obinit(mnum);	/* setup map registers and output buffer */
#endif
	ungetc('v',stdin);	/* print vocabulary */
	while((c = getc(stdin)) != 'q'){
		switch ( c ) {
	case 'm':
		if ((getnum(&mnum)) == 0 || mnum < 0 || mnum >= MAXMBA){
			printf("need MBA # between 0 and %d\n",
				MAXMBA - 1);
			tossin(1);
			mnum = 0;	/* reset to default */
		}
		obinit(mnum);
		break;
	case 'd':
		if ((getnum(&dunit)) == 0 || dunit <= 0 || dunit >= MAXUNI){
			printf("need unit # between 1 and %d\n",MAXUNI - 1);
			tossin(1);
			dunit = 0;	/* reset */
		}
		break;
	case 'f':
		if (dunit == 0){
			printf("\nmust give a unit #\n");
			break;
		}
		printf("\n *** THE PACK ON DRIVE %d-%d",
			mnum,dunit);
		printf(" WILL BE OVER-WRITTEN DURING FORMATTING ***\n");
		tossin(0);
		printf("\nDO YOU WISH TO CONTINUE? (y or n) ");
		if ((c = getc(stdin)) != 'y'){
			printf("*** FORMAT CANCELLED ***");
			if(c == '\n') ungetc(c,stdin);
			break;
		}
		tossin(1);
		fmtflg++;
		if (pkinit()) {
			printf("init error\n");
			break;
		}
	
		RPptr->RP_off = RP_FMT | RP_ECI; /* format and ECC inhibit */
		printf("\n\n *** FORMATTING PACK ***\n\n");
		ecnt0();
		for (cylndr = 0; cylndr < RP6CYL; cylndr++) {
			for (track = 0; track < RP6TRK; track++) {
				if (format(OBOFF,BUFSZ,0)) break;
				if (wcheck(OBOFF,BUFSZ,0)) break;
				trkinc();
			}
			cylinc();
			trkclr();
			if(Report && ((cylndr % 50) == 0))
				printf("\n---cyl  %d---\n",cylndr);
		}
	
		esum();
		if(Report) edump();
		printf("\n\n*** FORMAT COMPLETE *** \n\n");
		printf("\n\n");
	case 'c':
		if (dunit == 0){
			printf("\nmust give a unit #\n");
			break;
		}
		printf("\n*** checking pack on drive %d-%d ***\n",mnum,dunit);
		tossin(1);
		ecnt0();
		fmtflg = 0;
		if(pkinit()) {
			printf("init error\n");
			break;
		}
		RPptr->RP_off = RPptr->RP_off | RP_FMT;
		for (cylndr = 0; cylndr < RP6CYL; cylndr++) {
			for (track = 0; track < RP6TRK; track++) {
				if (dread(IBOFF,BLKSIZ * RP6SEC,0)) break;
				trkinc();
			}
			cylinc();
			trkclr();
			if(Report && ((cylndr % 50) == 0))
				printf("\n---cyl  %d---\n",cylndr);
		}
		esum();
		if(Report) edump();
		printf("\n\n*** CHECK COMPLETE *** \n\n");
		break;
	case 'b':
		if(getnum(&i) == 0) {
			printf(" no bits set\n");
			tossin(1);
			break;
		}
		prbits(i);
		break;
	case 'X':
		whoa (Report);
		break;
	case 'R':
	case 'T':
		if(getnum(&Report) == 0) {
			printf("\ninvalid Report level; ");
			Report = 0;
		}
		printf("\nReport level = %d\n",Report);
		break;
	case 'v':
		printf("\nCommands:\n\tm n - MBA number, ");
		printf("0<=n<=%d (defalts to 0)",MAXMBA - 1);
		printf("\n\td n - Drive number, ");
		printf("1<=n<=%d (must pick one)",MAXUNI - 1);
		printf("\n\tf   - format pack");
		printf("\n\tc   - check pack format");
		printf("\n\tRn  - set Report level to n");
		printf("\n\tbn  - report bits set in n");
		printf("\n\tX   - to execute the report trap ");
		printf("\n\tq   - quit");
		printf("\n\tv   - print vocabulary");
	case '\n':
		printf("\n? ");
	case ' ':
		break;
	case 'Z':
		RPptr = &Test;
		ecount = 0;
		printf("\n number of errors ? ");
		getnum(&j);
		for(i = 0; i < j; i++) {
			RPptr->RP_cyl = 10 * i;
			RPptr->RP_da = (i + (256 * i)) & 0x1f1f;
			if(logerr(i%10 + 1,0x12345)) break;
		}
		esum();
		edump();
		break;
	default:
		ungetc(c,stdin);
		printf("\n dont know how to '");
		while((c = getc(stdin)) != '\n') printf("%c",c);
		printf("'.\n? ");
		}
	}
}
getnum(num)
int *num;
{
	char c;
	while((c =getc(stdin)) == ' ' || c == '\n');
	ungetc(c,stdin);
	if ((c = getc(stdin)) != '0') {
		ungetc(c,stdin);
		if (scanf("%d",num) == 0) return(0);
		return(1);
	}
	if ((c = getc(stdin)) != 'x') {
		ungetc(c,stdin);	/* may be a number, may not. */
		ungetc('0',stdin); /* leading 0 be only # */
		if (scanf("%o",num) == 0) return(0);
	}
	else {
		if (scanf("%x",num) == 0) return(0);
	}
	return(1);
}
tossin(n)
int n;
{
	while(getc(stdin) != '\n');
	if (n) ungetc('\n',stdin);
	return;
}
	/*
	*	reset error counters
	*/
ecnt0()
{
	ecount = daterr = wcerr = 0;
}
 
	/*
	* Initialize MBA (disk) .
	* Set up MBA map register to map a 
	* output buffer uses 1st 128 map reg's -
	* input buffer uses last 128 map reg's 
	*/
obinit(mnum)
int mnum;
{
	register int page, *mp0, i;
	Mptr =(union MBREGS *)(M_BASE + (mnum*0x2000));
	page = (int)((int)obuf>>9) & 0x1fffff;
	mp0 = Mptr->Map.M_map;
	for (i = 0; i < 128; i++)
		(*mp0++) = 0x80000000 | page++;
 
	page = (int)((int)ibuf>>9) & 0x1fffff;
	for (i = 0; i<128; i++ )
		(*mp0++) = 0x80000000 | page++;
	return;
}
	/*
	* Pack initialization.
	* transfer of 'BUFSZ' bytes.
	*/
pkinit() 
{
	int stat, i, j;
	register struct sect *secp;
	Mptr->Mbar.M_cr = MBAinit;	/* MBA init */
	RPptr = &Mptr->Unit.RPreg[dunit];
	if (((stat = (RPptr->RP_ds)) & RP_MOL) == 0) {
		printf("unit OFF-LINE\n");
		return(-1);
	}
	if(fmtflg){
		if(stat & RP_WRL){
			printf("unit WRITE-PROTECTED\n");
			return(1);
		}
		/*
		*  initialize output buffer with sector header and data:
		* 	4 sector header words:
		* 		cylinder
		* 		track/sector
		* 		key word 1
		* 		key word 2
		* 	256 data words
		*/
		for (secp = (struct sect *)obuf,i = 0;i<RP6SEC;i++,secp++) {
			secp->s_cyl[0] = RP_FMT;
			secp->s_kw1 = secp->s_kw2 = 0;
			secp->s_sec = i;	
			secp->s_trk = 0;	
			for (j = 0; j < 256;){
				secp->s_data[j++] = PTRN1;
				secp->s_data[j++] = PTRN2;
			}
		}
	}
	RPptr->RP_cr = RP_RIP | RP_GO; /* drive preset - sets vv */
	dwait(RPptr);
	ecount = daterr = wcerr = 0;
	return(0);
}
	/*
	* write 'nb' bytes worth of sector and data info
	* from buffer whose map/offset is 'baddr' to disk.
	*/
format(baddr,nb,s)
int baddr, nb, s;
{
	register int i;
	register struct RPR *R;
	register struct MBAR *M;
	R = RPptr;
	M = Mptr;
	R->RP_cr = RP_DC | RP_GO;
	dwait(R);
	setadr(baddr,nb,s);
	R->RP_cr = RP_WHD | RP_GO; /* write sector header and data */
	dwait(R);	
	if (i = derror(R)) {
		cursec(nb,s);
		logerr(3,i);
		if (wcrflg) return(1);	/* stop if 'wrt check' rec. */
		if (ecount > MAXERR) return(-1);
	}
	if (i = mbaerr(M)) {
		cursec(nb,s);
		if((wcrflg == 0) || logerr(1,i)) return(-1);
	}
	return(0);	
}
	/*
	* With ECC enabled,
	* read 'nb' bytes into buffer pointed to
	* by map 'baddr' - start at sector 's'.
	*/
dread(baddr,nb,s)
int baddr, nb, s;
{
	register int i;
	register struct MBAR *M;
	register struct RPR *R;
	R = RPptr;
	M = Mptr;
	setadr(baddr,nb,s);
rini:
	R->RP_cr = RP_DC | RP_GO;	
	dwait(R);
	dwait(R);
	R->RP_cr = RP_RED | RP_GO;	
	dwait(R);	
	cursec(nb,s);
	if (i = derror(R)) {	
		if (wcrflg) return(-1);
		if (i & (RP_HCE|RP_HCRC|RP_FER|RP_PAR)){
			logerr(14,i);
			return(1);
		}
		if (i & RP_DCK) {	
			daterr++;
			if (i & RP_ECH) {	/* ECC Hard Error */
				if(logerr(5,R->RP_Epat)
					|| wcrflg) return(-1);
			}
			else {		/* ECC recoverable */
				logerr(8,R->RP_Epat & 0xfff);
			}
			if (M->M_bc) {	/* more i-o to complete */
				goto rini;
				/* status reg cleared by Drive Clear */
			}
		}
		else {
			if( i & RP_FER)
				logerr(9,i);
			else
				logerr(4,i);
		}
		if (wcrflg) return(0);
	}
	if (i = mbaerr(M)) {
		return(-1);
	}
	return(0);
}
mbaerr(mba)
register struct MBAR *mba;
{
	register int i;
	if ((i = mba->M_sr) == 0x2000 || i == MB_ERR) return(0); 
	mba->M_sr = (-1);
	return(i);
}
	/*
	* write check 'nb' bytes of sector and data info
	* from buffer whose map reg is 'baddr' - start at sector 's'.
	*/
wcheck(baddr,nb,s)
int baddr, nb, s;
{
	register int i, j;
	register struct RPR *R;
	register struct MBAR *M;
	R = RPptr;
	M = Mptr;
	R->RP_cr = RP_DC | RP_GO;
	dwait(RPptr);
	setadr(baddr,nb,s);
	R->RP_cr = RP_WCH | RP_GO; 
	dwait(RPptr); 
	j = cursec(nb,s);
	if (i = derror(R))  {
		if(R->RP_er1 & RP_DCK) {
			logerr(7,i);
			R->RP_cr = RP_RIP | RP_GO;	/* resets ECC inhibit */
			R->RP_off = R->RP_off | RP_FMT;
			if((j = dread(IBOFF + IBMAP0,RPHEAD + BLKSIZ,j)) == 0)
				logerr(8,R->RP_Epat & 0xfff);
			R->RP_off = R->RP_off | RP_ECI | RP_FMT;
			return(i);
		}
	}
	else if (i = mbaerr(M)) {
		if (i & (M_WCKU | M_WCKL)) { 
			wcerr++;
			if(wcrflg) {
				return(1);
			}
		wckrcv(j);
		}
	}
	if (ecount > MAXERR) return(-1);
	return(0);
}
	/*
	* Try to recover from a 'write check' error during a
	* 'Write Check Header and Data' function.
	* 'RPptr' is ptr to RP register set.
	* 'Mptr' is ptr to MBA reg set.
	* MBA byte count reg has neg. no. bytes remaining - transfer 
	* stops on error, even in middle of a sector.
	* Loop with a 'Write Sector Header and Data' followed by a 
	* 'Read Sector Header and Data' - each loop iteration uses 
	* a different head centerline offset.
	* If all fails, report irrecoverable error and finish off the
	* 'write check data and header' on the rest of the track.
	*/
wckrcv(j)
int j;
{
	register int i, k, l, m;
	wcrflg++;
	m = j * (BLKSIZ+RPHEAD);	/* data offset in buffer */
	/* See if a simple reread (3) will fix this problem */
	for(l = 1; l <= 16; l++){
		if(wcheck(m + OBOFF,BLKSIZ + RPHEAD,j)) continue;
		logerr(12,l);
		goto wckfin;
	}
	/*
	* Try to recover using 
	* different centerline offset - 1st offset is 0.
	*/
	for (i = 0; (l = Offset[i]) >= 0; i++) {
		k = RPptr->RP_off & 0xff00;
		RPptr->RP_off = k | l;
		RPptr->RP_cr = RP_DC | RP_GO;
		dwait(RPptr);
		RPptr->RP_cr = RP_OFF | RP_GO;
		dwait(RPptr);
		if (format(m + OBOFF,BLKSIZ + RPHEAD,j)) continue;
		if (rshd(IBMAP0 + IBOFF,BLKSIZ + RPHEAD,j) < 0) continue;
		if (cksec(ibuf,obuf+m)) continue;
		secnum = j;
		logerr(6,(i << 12) | l);
		goto wckfin;
	}
	secnum = j;
	logerr(10,RPptr->RP_da);
wckfin :
	RPptr->RP_cr = RP_RTC | RP_GO; /* return to centerline */
	dwait(RPptr);
	/*
	* Continue write check where
	* the original WCHD left off.
	*/
	if(++j >= RP6SEC)  {
		wcrflg = 0;
		return;
	}
	i = j * (BLKSIZ + RPHEAD);
	if(wcheck(i + OBOFF,(RP6SEC - j) * (BLKSIZ + RPHEAD),j))
				logerr(13,i);
	wcrflg = 0;
	return;
}
	/*
	* read 'nb' bytes into buffer pointed to
	* by map and offset in 'baddr' - start at sector 's'
	*/
rshd(baddr,nb,s)
int baddr, nb, s;
{
	register int i, j;
	register struct MBAR *M;
	register struct RPR *R;
	R = RPptr;
	M = Mptr;
	setadr(baddr,nb,s);
	R->RP_cr = RP_DC | RP_GO; 
	dwait(R);
	R->RP_cr = RP_RHD | RP_GO; /* read sector header and data */
	dwait(R);	/* wait for i/o to finish */
	if (i = derror(R)) {	
		cursec(nb,s);
		if(i & (RP_HCRC|RP_HCE|RP_FER)){
			logerr(14,i);
			return(-1); 
		}
		if(R->RP_er1 & RP_DCK) {
			R->RP_cr = RP_RIP | RP_GO;	/* resets ECC inhibit */
			R->RP_off = R->RP_off | RP_FMT;
			if((j = dread(IBOFF + IBMAP0,RPHEAD + BLKSIZ,s)) == 0)
				logerr(8,R->RP_Epat & 0xfff);
			R->RP_off = R->RP_off | RP_ECI | RP_FMT;
			return(i);
		}
		else logerr(2,i);
		return(i);
	}
	if (i = mbaerr(M)) {
		return(-1);
	}
	return(i);
}
	/* setup data transfer addresses */
setadr(baddr,nb,s)
int baddr, nb, s;
{
	RPptr->RP_cyl = cylndr;	
	RPptr->RP_da = (track<<8) | s;	
	Mptr->Mbar.M_bc = (-nb);
	Mptr->Mbar.M_var = baddr; /* virt addr reg = map no. + byte off */
}
	/*
	* Compare sector header and data info on disk against that
	* which was written from output buffer
	*/
cksec(insec,ousec)
register struct sect *insec, *ousec;
{
	register int j;
	for (j = 0; j < (RPHEAD>>1); j++)
		if (insec->s_cyl[j] != ousec->s_cyl[j])
			return(1);
	for (j = 0; j < 256; j++)
		if (insec->s_data[j] != ousec->s_data[j])
			return(1);
	return(0);
}
	/*
	* wait RP06 disc unit to be ready.
	*/
dwait(rptr)
struct RPR *rptr;
{
	while ((rptr->RP_ds & RP_DRY) == 0);
}
	/*
	* check for RP06 error.
	*/
derror(rptr)
struct RPR *rptr;
{
	if (rptr->RP_ds & RP_ERR) 
		return(rptr->RP_er1 & 0xffff);
	return(0);
}
	/*
	* given sector and count for last transfer, determine
	* the last partial sector transferred.
	*/
cursec(nb,s)
int nb,s;
{
	register int i, j;
	if((i = Mptr->Mbar.M_bc >> 16) == 0){
		secnum = (RPptr->RP_da & 0x1f) -1;
	}
	else {
		j = nb + i;	/* bytes transferred */
		secnum = ((j - 1) /(RPHEAD + BLKSIZ)) + s;
	}
	if(secnum >= RP6SEC) {
		printf("\n*** sector conversion error");
		printf("\n*** M_bc %x, bytes %x, sector %x ***\n",
			i,j,secnum);
		whoa(2);
	}
	if(secnum < 0 ) secnum =  RP6SEC - 1;
	return(secnum);
}
	/*
	* modify track/sector no. in output buffer sector headers.
	*/
trkinc()
{
	register struct sect *sp;
	register int i;
	for (i = 0, sp = (struct sect *)obuf; i < RP6SEC; i++, sp++)
		sp->s_trk++;
}
cylinc() 
{
	register struct sect *sp;
	register int i;
	for (i = 0, sp = (struct sect *)obuf; i < RP6SEC; i++, sp++)
		sp->s_cyl[0]++;
}
trkclr()
{
	register struct sect *sp;
	register int i;
	for (i = 0, sp = (struct sect *)obuf; i < RP6SEC; i++, sp++)
		sp->s_trk = 0;
}
	/*
	*	check we were assembled standalone for the VAX
	*/
ckcomp()
{
#ifndef vax
	printf("available only on the VAX 11/780\n");
#endif
#ifndef STANDALONE
	printf("available STAND-ALONE only \n");
	return(1);
#endif
#ifndef vax
	return(1);
#endif
	return(0);
}
	/*
	*	log errors in erlist
	*/
logerr(code,stat)
int code, stat;
{
	errlst[ecount].e_typ = code;
	errlst[ecount].e_cyl = RPptr->RP_cyl & 0xffff;
	errlst[ecount].e_trk = RPptr->RP_da;
	errlst[ecount].e_err = stat;
	if(secnum == (RP6SEC -1)){
		errlst[ecount].e_trk += ((-1) << 8);
	}
	prloc();
	printf(":  %s, %8x\n",errtyp(code),stat);
	if(++ecount > (MAXERR - 5)) {
		Report = 9;
		printf("\nerror count is %d of %d MAX\n",
			ecount,MAXERR);
	}
	if(Report != 8) whoa(Report);
	if(ecount >= MAXERR) return(-1);
	return(0);
}
	/*
	*	print bits set in a word
	*/
prbits(wrd)
int wrd;
{
	int j,k;
	printf("\nerror bits : ");
	for(j = 0, k = 1; j <= 31; j++, k <<= 1)
		if(wrd & k) printf("%d, ",j);
	printf("\n\n");
	return;
}
	/*
	*	summarize errors by type and location
	*/
esum()
{
	int n, h, bw, badpk,badecc;
	register int slice;
	register struct EL *elptr;
	int ernum, endcyl, ocyl, otrk, osec;
	int *hitcyl, hittrk[RP6TRK], hitsec[RP6SEC],
		hcyl[8], htrk[8], hsec[8], hard[8], soft[8], xsec[8],
		headr[8], dta[8], read[8], write[8],
		minb[8],maxb[8];
	if(ecount == 0){
		printf("\nNO ERRORS\n");
		return;
	}
	printf("\n Total errors: %d",ecount);
	hitcyl = ibuf; /* scratch space */
	for(n = 0; n < RP6CYL; n++) *(hitcyl + n) = 0;
	for(n = 0; n < RP6TRK; n++) hittrk[n] = 0;
	for(n = 0; n < RP6SEC; n++) hitsec[n] = 0;
	for(n = 0;n < 8; n++){
		hcyl[n] = htrk[n] = hsec[n] = 0;
		hard[n] = soft[n] = xsec[n] = 0;
		headr[n] = dta[n] = read[n] = write[n] = 0;
		minb[n] = 13;	/* 12 is max field width */
		maxb[n] = 0;
	}
	ernum = badecc = badpk = 0;
	elptr = errlst;
	ocyl = otrk = osec = -1;
	for(slice = 0; slice < 8; slice++) {
		if((endcyl = hp_sizes[slice + 1].cyloff) == 0)
			endcyl = RP6CYL;
		while((ernum < ecount) && (elptr->e_cyl < endcyl)) {
			if((n = elptr->e_cyl) < RP6CYL){
				(*(hitcyl + n))++;
				if(n != ocyl){
					hcyl[slice]++;
					ocyl = n;
					otrk = osec = -1;
				}
			}
			else printf("\nbad cylinder data %x\n",
				elptr->e_cyl);
			if((n = (elptr->e_trk >> 8) & 0x1f) < RP6TRK){
				hittrk[n]++;
				if(n != otrk){
					htrk[slice]++;
					otrk = n;
					osec = -1;
				}
			}
			else printf("\nbad track data %x\n",
				elptr->e_trk);
			if((n = (elptr->e_trk & 0x1f)) < RP6SEC){
				(*(hitsec + n))++;
				if(n != osec){
					hsec[slice]++;
					osec = n;
				}
			}
			else printf("\nbad sector data %x\n",
				elptr->e_trk);
			switch (elptr->e_typ) {
			case 2:
			case 6:
				read[slice]++;
				headr[slice]++;
				break;
			case 3:
				write[slice]++;
				headr[slice]++;
				break;
			case 4:
				read[slice]++;
				dta[slice]++;
				break;
			case 5:
				hard[slice]++;
				badpk++;
				break;
			case 7:
				write[slice]++;
				dta[slice]++;
				break;
			case 8:
				soft[slice]++;
				if((bw = brstw(&elptr->e_err)) > maxb[slice])
					maxb[slice] = bw;
				if((bw < minb[slice]) && bw)
					minb[slice] = bw;
				break;
			case 9:
				break;
			case 10:
			case 13:
				hard[slice]++;
				xsec[slice]++;
				break;
			case 12:
				soft[slice]++;
				break;
			}
			ernum++;
			elptr++;
		}
		printf("\nDisk slice %d error summary",slice);
		if(hard[slice]){
			printf("\n\n\t%d\tHard errors",hard[slice]);
		}
		if(soft[slice]){
			printf("\n\t%d\tRecoverable errors",soft[slice]);
			if(!fmtflg)
			printf("\n\t\tmin burst : %d, max burst : %d",
				minb[slice] % 13, maxb[slice]);
			if(maxb[slice] > 8) badecc++;
		}
		if(hcyl[slice]){
			printf("\n\t%d\tBad cylinders",hcyl[slice]);
		}
		if(htrk[slice]){
			printf("\n\t%d\tBad tracks",htrk[slice]);
		}
		if(hsec[slice]){
			printf("\n\t%d\tBad sectors",hsec[slice]);
		}
		if(write[slice]){
			printf("\n\t%d\tWrite errors",write[slice]);
		}
		if(read[slice]){
			printf("\n\t%d\tRead errors",read[slice]);
		}
		if(headr[slice]){
			printf("\n\t%d\tHeader errors",headr[slice]);
		}
		if(dta[slice]){
			printf("\n\t%d\tData errors",dta[slice]);
		}
	
	}
	if(badecc){
		printf("\n\n*** This pack has %d ECC error",badecc);
		if(badecc > 1) printf("s");
		printf(" That FAIL");
		if(badecc < 2) printf("S");
		printf(" new pack requirements ***\n");
		printf("*** If this is a new pack, ");
		printf("return it to the vendor ***\n\n");
	}
	if(badpk && !fmtflg){
		printf("\n\n*** This pack has %d HARD error",badpk);
		if(badpk > 1) printf("s");
		printf(". It is UNUSABLE as a system pack ***\n\n");
		printf("*** This pack must be refurbished ***\n\n");
	}
	printf("\n\nPack summary\n");
	printf("\n\nCylinder hits\n");
	for(n = 0;n < RP6CYL; n++){
		if(endcyl == RP6CYL) break;
		h = *(hitcyl + n);
		if(h){
			printf("\n %d:\t%d hit",n,h);
			if(h > 1) printf("s");
		}
	}
	printf("\n\nTrack hits\n");
	for(n = 0;n < RP6TRK; n++)
		if(hittrk[n]){
			printf("\n %d:\t%d hit",n,hittrk[n]);
			if(hittrk[n] > 1) printf("s");
		}
	printf("\n\nSector hits\n");
	for(n = 0;n < RP6SEC; n++)
		if(hitsec[n]){
			printf("\n %d:\t%d hit",n,hitsec[n]);
			if(hitsec[n] > 1) printf("s");
		}
}
brstw(eptr)
int *eptr;
{
	int i, j, b1, b2;
	b1 = b2 = 0;
	j = *eptr;
	for(i = 1;i < 13; i++){
		if(j % 2) {
			if( b1 == 0) b1 = i;
			b2 = i + 1;
		}
		j = j / 2;
	}
	return(b2 - b1);
}
	/*
	*	dump the error list
	*/
edump()
{
	int i;
	if(ecount == 0)	return;
	printf("\n\nerror file dump");
	printf("\n\nCYL\tTRK\tSECT\t  STATUS\t ERROR TYPE\n");
	for(i = 0; i < ecount; i++)
		printf("\n%3d\t%3d\t%3d\t%8x\t%s",
		errlst[i].e_cyl,
		(errlst[i].e_trk >> 8) & 0x1f,
		errlst[i].e_trk & 0x1f,
		errlst[i].e_err,
		errtyp(errlst[i].e_typ));
	printf("\n");
}
	/*
	*	print cyl-trk-sect address
	*/
prloc()
{
	printf("\ncyl %d, trk %d, sec %d",
		cylndr,track,secnum);
}
	/*
	*	decode error type given the code number
	*/
char *
errtyp(n)
int n;
{
	switch(n) {
	case 1: return("MBA error");
	case 2: return("Read SHD");
	case 3: return("Write SHD");
	case 4: return("Read error");
	case 5: return("ECC; Non-recoverable");
	case 6: return("Write Check; Recoverable with head offset");
	case 7: return("Data check");
	case 8: return("ECC; Recoverable");
	case 9: return("Format error");
	case 10: return("Bad sector");
	case 11: return("Wckrcv sect. compare");
	case 12: return("Write Check; Recoverable by re-read");
	case 13: return("Multiple wrt-cks on track");
	case 14: return("Header Compare error");
	default: return("undefined");
	}
}
	/* debugging trap */
whoa(n)
int n;
{
	int i, j, *mp;
	static int passn = 1;
	char c;
	switch(n){
case 0: return;
case 1:
	printf("\n\nMBA Regs:\
		\n csr  %9x\n cr   %9x\n sr   %9x\
		\n var  %9x\n bc   %9x\n",
		Mptr->Mbar.M_csr,
		Mptr->Mbar.M_cr,
		Mptr->Mbar.M_sr,
		Mptr->Mbar.M_var,
		Mptr->Mbar.M_bc);
	break;
case 2:
	printf("\n\nMBA Regs:\
		\n csr  %9x\n cr   %9x\n sr   %9x\
		\n var  %9x\n bc   %9x\n",
		Mptr->Mbar.M_csr,
		Mptr->Mbar.M_cr,
		Mptr->Mbar.M_sr,
		Mptr->Mbar.M_var,
		Mptr->Mbar.M_bc);
case 3:
	printf("\nDrive Regs:\
		\n cr   %5x\tds   %5x\ter1  %5x\tmr   %5x\
		\n as   %5x\tda   %5x\tdt   %5x\tla   %5x\
		\n sn   %5x\toff  %5x\tcyl  %5x\tcc   %5x\
		\n err2 %5x\terr3 %5x\tepos %5x\tepat %5x\n",
		RPptr->RP_cr & 0xffff,
		RPptr->RP_ds & 0xffff,
		RPptr->RP_er1 & 0xffff,
		RPptr->RP_mr & 0xffff,
		RPptr->RP_as & 0xffff,
		RPptr->RP_da & 0x1f1f,
		RPptr->RP_dt & 0xffff,
		RPptr->RP_la & 0xffff,
		RPptr->RP_sn & 0xffff,
		RPptr->RP_off & 0xffff,
		RPptr->RP_cyl & 0xffff,
		RPptr->RP_cc & 0xffff,
		RPptr->RP_err2 & 0xffff,
		RPptr->RP_err3 & 0xffff,
		RPptr->RP_Epos & 0xffff,
		RPptr->RP_Epat & 0xffff);
		prloc();
		break;
case 8:
	prloc();
	return;
case 9:
	printf("\n***");
	}
	while(c != 'R'){
		if(passn < 2){
			printf("\nType 'c' fo continue,");
			printf("\n     'Rn' to change this trap to level n.");
			printf("\n and '<ctl> p' and 'H' to halt the system..");
			printf("\n\nReport levels:");
			printf("\n 9 - trap, no printout");
			printf("\n 8 - pack address info, NO trap");
			printf("\n 3 - drive registers");
			printf("\n 2 - things above and MBA regs");
			printf("\n 1 - MBA regs only");
			printf("\n 0 - no trap, re-enable with 'Tn' command");
		}
		printf("\nContinue?...");
		passn++;
		tossin(0);
		if((c = getc(stdin)) == 'c') return;
	}
	if(getnum(&Report) == 0) {
		printf("\ninvalid level");
		Report = 0;
	}
	printf("\nReport level %d\n",Report);
	return;
}