xref: /csrg-svn/sys/vax/stand/format.c (revision 33553)
123251Smckusick /*
229297Smckusick  * Copyright (c) 1980, 1986 Regents of the University of California.
323251Smckusick  * All rights reserved.  The Berkeley software License Agreement
423251Smckusick  * specifies the terms and conditions for redistribution.
523251Smckusick  */
611367Ssam 
723251Smckusick #ifndef lint
823251Smckusick char copyright[] =
929297Smckusick "@(#) Copyright (c) 1980, 1986 Regents of the University of California.\n\
1023251Smckusick  All rights reserved.\n";
1123251Smckusick #endif not lint
1215051Skarels 
1323251Smckusick #ifndef lint
14*33553Skarels static char sccsid[] = "@(#)format.c	7.2 (Berkeley) 02/24/88";
1523251Smckusick #endif not lint
1623251Smckusick 
1725212Skarels 
1811367Ssam /*
1911367Ssam  * Standalone program to do media checking
2011367Ssam  * and record bad block information on any
2115009Skarels  * disk with the appropriate driver and RM03-style headers.
2225212Skarels  * TODO:
2325212Skarels  *	add new bad sectors to bad-sector table when formatting by track
2425212Skarels  *		(rearranging replacements ala bad144 -a)
2525212Skarels  *	multi-pass format for disks with skip-sector capability
2611367Ssam  */
27*33553Skarels #include "param.h"
28*33553Skarels #include "fs.h"
29*33553Skarels #include "inode.h"
30*33553Skarels #include "dkbad.h"
31*33553Skarels #include "vmmac.h"
3211367Ssam 
3311367Ssam #include "saio.h"
3411367Ssam #include "savax.h"
3511367Ssam 
3611367Ssam #define MAXBADDESC	126		/* size of bad block table */
3711367Ssam #define CHUNK		48		/* max # of sectors/io operation */
3811367Ssam #define SECTSIZ		512		/* standard sector size */
3911367Ssam #define HDRSIZ		4		/* number of bytes in sector header */
4011367Ssam 
4111367Ssam #define SSERR		0
4211367Ssam #define BSERR		1
4311367Ssam 
4425438Skarels #define SSDEV(fd)	(ioctl((fd), SAIOSSDEV, (char *)0) == 0)
4525438Skarels #define MAXECCBITS	3
4611367Ssam 
4711367Ssam struct sector {
4811367Ssam 	u_short	header1;
4911367Ssam 	u_short header2;
5011367Ssam 	char	buf[SECTSIZ];
5111367Ssam };
5211367Ssam 
5311367Ssam struct	dkbad dkbad;		/* bad sector table */
5425438Skarels struct	dkbad oldbad;		/* old bad sector table */
5511367Ssam struct	dkbad sstab;		/* skip sector table */
5611367Ssam 
5711367Ssam #define	NERRORS		6
5811371Ssam static char *
5911371Ssam errornames[NERRORS] = {
6015009Skarels #define	FE_BSE		0
6115009Skarels 	"Bad sector",
6215009Skarels #define	FE_WCE		1
6311367Ssam 	"Write check",
6411367Ssam #define	FE_ECC		2
6525438Skarels 	"Hard ECC",
6611367Ssam #define	FE_HARD		3
6711367Ssam 	"Other hard",
6811367Ssam #define	FE_TOTAL	4
6925438Skarels 	"Marked bad",
7011367Ssam #define	FE_SSE		5
7125438Skarels 	"Skipped",
7211367Ssam };
7311367Ssam 
7411367Ssam int	errors[NERRORS];	/* histogram of errors */
7511371Ssam int	pattern;
7625438Skarels int	maxeccbits;
7711367Ssam 
7815051Skarels /*
7915051Skarels  * Purdue/EE severe burnin patterns.
8015051Skarels  */
8115051Skarels unsigned short ppat[] = {
8217426Skarels 0xf00f, 0xec6d, 0031463,0070707,0133333,0155555,0161616,0143434,
8315051Skarels 0107070,0016161,0034343,0044444,0022222,0111111,0125252, 052525,
8415051Skarels 0125252,0125252,0125252,0125252,0125252,0125252,0125252,0125252,
8515051Skarels #ifndef	SHORTPASS
8615051Skarels 0125252,0125252,0125252,0125252,0125252,0125252,0125252,0125252,
8715051Skarels  052525, 052525, 052525, 052525, 052525, 052525, 052525, 052525,
8815051Skarels #endif
8915051Skarels  052525, 052525, 052525, 052525, 052525, 052525, 052525, 052525
9015051Skarels  };
9115051Skarels 
9215051Skarels #define	NPT	(sizeof (ppat) / sizeof (short))
9317426Skarels int	maxpass, npat;	/* subscript to ppat[] */
9415051Skarels int	severe;		/* nz if running "severe" burnin */
9525438Skarels int	ssdev;			/* device supports skip sectors */
9625212Skarels int	startcyl, endcyl, starttrack, endtrack;
9725438Skarels int	nbads;			/* subscript for bads */
9825438Skarels daddr_t	bads[2*MAXBADDESC]; 	/* Bad blocks accumulated */
9915051Skarels 
10011367Ssam char	*malloc();
10115051Skarels int	qcompar();
10211367Ssam char	*prompt();
10325212Skarels daddr_t	badsn();
10411367Ssam extern	int end;
10511367Ssam 
10611367Ssam main()
10711367Ssam {
10811367Ssam 	register int sector, sn;
10915051Skarels 	int lastsector, tracksize, rtracksize;
11011367Ssam 	int unit, fd, resid, i, trk, cyl, debug;
11111367Ssam 	struct st st;
11211367Ssam 	struct sector *bp, *cbp;
11315051Skarels 	char *rbp, *rcbp;
11417426Skarels 	int pass;
11511367Ssam 	char *cp;
11611367Ssam 
11711367Ssam 	printf("Disk format/check utility\n\n");
11811367Ssam 
11911367Ssam again:
12015051Skarels 	nbads = 0;
12115051Skarels 	cp = prompt("Enable debugging (0=none, 1=bse, 2=ecc, 3=bse+ecc)? ");
12211367Ssam 	debug = atoi(cp);
12311367Ssam 	if (debug < 0)
12411367Ssam 		debug = 0;
12511367Ssam 	for (i = 0; i < NERRORS; i++)
12611367Ssam 		errors[i] = 0;
12711367Ssam 	fd = getdevice();
12811367Ssam 	ioctl(fd, SAIODEVDATA, &st);
12911367Ssam 	printf("Device data: #cylinders=%d, #tracks=%d, #sectors=%d\n",
13011367Ssam 	  st.ncyl, st.ntrak, st.nsect);
13125438Skarels 	ssdev = SSDEV(fd);
13225438Skarels 	if (ssdev) {
13325438Skarels 		ioctl(fd, SAIOSSI, (char *)0);	/* set skip sector inhibit */
13425438Skarels 		st.nsect++;
13525438Skarels 		st.nspc += st.ntrak;
13625438Skarels 		printf("(not counting skip-sector replacement)\n");
13725438Skarels 	}
13825212Skarels 	getrange(&st);
13911371Ssam 	if (getpattern())
14011367Ssam 		goto again;
14111367Ssam 	printf("Start formatting...make sure the drive is online\n");
14211367Ssam 	ioctl(fd, SAIONOBAD, (char *)0);
14325438Skarels 	ioctl(fd, SAIORETRIES, (char *)0);
14425438Skarels 	ioctl(fd, SAIOECCLIM, (char *)maxeccbits);
14511367Ssam 	ioctl(fd, SAIODEBUG, (char *)debug);
14611367Ssam 	tracksize = sizeof (struct sector) * st.nsect;
14715051Skarels 	rtracksize = SECTSIZ * st.nsect;
14811367Ssam 	bp = (struct sector *)malloc(tracksize);
14915051Skarels 	rbp = malloc(rtracksize);
15017426Skarels 	pass = 0;
15117426Skarels 	npat = 0;
15217426Skarels more:
15317426Skarels 	for (; pass < maxpass; pass++) {
15415051Skarels 		if (severe)
15515051Skarels 			printf("Begin pass %d\n", pass);
15615051Skarels 		bufinit(bp, tracksize);
15715051Skarels 		if (severe)
15815051Skarels 			npat++;
15911367Ssam 		/*
16015051Skarels 		 * Begin check, for each track,
16111367Ssam 		 *
16215051Skarels 		 * 1) Write header and test pattern.
16315051Skarels 		 * 2) Read data.  Hardware checks header and data ECC.
16417426Skarels 		 *    Read data (esp on Eagles) is much faster than write check.
16511367Ssam 		 */
16625212Skarels 		sector = ((startcyl * st.ntrak) + starttrack) * st.nsect;
16725212Skarels 		lastsector = ((endcyl * st.ntrak) + endtrack) * st.nsect
16825212Skarels 			+ st.nsect;
16925212Skarels 		for ( ; sector < lastsector; sector += st.nsect) {
17015051Skarels 			cyl = sector / st.nspc;
17115051Skarels 			trk = (sector % st.nspc) / st.nsect;
17215051Skarels 			for (i = 0; i < st.nsect; i++) {
17315051Skarels 				bp[i].header1 =
17415051Skarels 					(u_short) cyl | HDR1_FMT22 | HDR1_OKSCT;
17515051Skarels 				bp[i].header2 = ((u_short)trk << 8) + i;
17615051Skarels 			}
17715051Skarels 			if (sector && (sector % (st.nspc * 100)) == 0)
17815051Skarels 				printf("cylinder %d\n", cyl);
17915051Skarels 			/*
18015051Skarels 			 * Try and write the headers and data patterns into
18115051Skarels 			 * each sector in the track.  Continue until such
18215051Skarels 			 * we're done, or until there's less than a sector's
18315051Skarels 			 * worth of data to transfer.
18415051Skarels 			 *
18515051Skarels 			 * The lseek call is necessary because of
18615051Skarels 			 * the odd sector size (516 bytes)
18715051Skarels 			 */
18815051Skarels 			for (resid = tracksize, cbp = bp, sn = sector;;) {
18915051Skarels 				int cc;
19011367Ssam 
191*33553Skarels 				lseek(fd, sn * SECTSIZ, L_SET);
19215051Skarels 				ioctl(fd, SAIOHDR, (char *)0);
19315051Skarels 				cc = write(fd, cbp, resid);
19415051Skarels 				if (cc == resid)
19515051Skarels 					break;
19615051Skarels 				/*
19715051Skarels 				 * Don't record errors during write,
19815051Skarels 				 * all errors will be found during
19925438Skarels 				 * check performed below.
20015051Skarels 				 */
20115051Skarels 				sn = iob[fd - 3].i_errblk;
20215051Skarels 				cbp += sn - sector;
20315051Skarels 				resid -= (sn - sector) * sizeof (struct sector);
20415051Skarels 				if (resid < sizeof (struct sector))
20515051Skarels 					break;
20615051Skarels 			}
20711367Ssam 			/*
20815051Skarels 			 * Read test patterns.
20915051Skarels 			 * Retry remainder of track on error until
21015051Skarels 			 * we're done, or until there's less than a
21115051Skarels 			 * sector to verify.
21211367Ssam 			 */
21315051Skarels 			for (resid = rtracksize, rcbp = rbp, sn = sector;;) {
21425438Skarels 				int cc, rsn;
21511367Ssam 
216*33553Skarels 				lseek(fd, sn * SECTSIZ, L_SET);
21715051Skarels 				cc = read(fd, rcbp, resid);
21815051Skarels 				if (cc == resid)
21915051Skarels 					break;
22015051Skarels 				sn = iob[fd-3].i_errblk;
22125438Skarels 				if (ssdev) {
22225438Skarels 					rsn = sn - (sn / st.nsect);
22325438Skarels 					printf("data ");
22425438Skarels 				} else
22525438Skarels 					rsn = sn;
22625438Skarels 				printf("sector %d, read error\n\n", rsn);
22715051Skarels 				if (recorderror(fd, sn, &st) < 0 && pass > 0)
22815051Skarels 					goto out;
22915051Skarels 				/* advance past bad sector */
23015051Skarels 				sn++;
23125438Skarels 				resid = rtracksize - ((sn - sector) * SECTSIZ);
23225438Skarels 				rcbp = rbp + ((sn - sector) * SECTSIZ);
23315051Skarels 				if (resid < SECTSIZ)
23415051Skarels 					break;
23515051Skarels 			}
23611367Ssam 		}
23711367Ssam 	}
23811367Ssam 	/*
23911367Ssam 	 * Checking finished.
24011367Ssam 	 */
24115051Skarels out:
24217426Skarels 	if (severe && maxpass < NPT) {
24317426Skarels 		cp = prompt("More passes? (0 or number) ");
24417426Skarels 		maxpass = atoi(cp);
24517426Skarels 		if (maxpass > 0) {
24617426Skarels 			maxpass += pass;
24717426Skarels 			goto more;
24817426Skarels 		}
24917426Skarels 	}
25015051Skarels 	if (severe && nbads) {
25115051Skarels 		/*
25215051Skarels 		 * Sort bads and insert in bad block table.
25315051Skarels 		 */
25425438Skarels 		qsort(bads, nbads, sizeof (daddr_t), qcompar);
25515051Skarels 		severe = 0;
25617426Skarels 		errno = 0;
25717426Skarels 		for (i = 0; i < nbads; i++)
25815051Skarels 			recorderror(fd, bads[i], &st);
25915051Skarels 		severe++;
26015051Skarels 	}
26111367Ssam 	if (errors[FE_TOTAL] || errors[FE_SSE]) {
26211367Ssam 		/* change the headers of all the bad sectors */
26311367Ssam 		writebb(fd, errors[FE_SSE], &sstab, &st, SSERR);
26411367Ssam 		writebb(fd, errors[FE_TOTAL], &dkbad, &st, BSERR);
26511367Ssam 	}
26625438Skarels 	if (errors[FE_TOTAL] || errors[FE_SSE]) {
26725438Skarels 		printf("Errors:\n");
26825438Skarels 		for (i = 0; i < NERRORS; i++)
26925438Skarels 			printf("%s: %d\n", errornames[i], errors[i]);
27025438Skarels 		printf("Total of %d hard errors revectored\n",
27125438Skarels 			errors[FE_TOTAL] + errors[FE_SSE]);
27225438Skarels 	}
27325212Skarels 	if (endcyl == st.ncyl - 1 &&
27425212Skarels 	    (startcyl < st.ncyl - 1 || starttrack == 0)) {
27525212Skarels 		while (errors[FE_TOTAL] < MAXBADDESC) {
27625212Skarels 			int i = errors[FE_TOTAL]++;
27711367Ssam 
27825212Skarels 			dkbad.bt_bad[i].bt_cyl = -1;
27925212Skarels 			dkbad.bt_bad[i].bt_trksec = -1;
28025212Skarels 		}
28125212Skarels 		printf("\nWriting bad sector table at sector #%d\n",
28225212Skarels 			st.ncyl * st.nspc - st.nsect);
28325212Skarels 		/* place on disk */
28425212Skarels 		for (i = 0; i < 10 && i < st.nsect; i += 2) {
285*33553Skarels 			lseek(fd, SECTSIZ * (st.ncyl * st.nspc - st.nsect + i), L_SET);
28625212Skarels 			write(fd, &dkbad, sizeof (dkbad));
28725212Skarels 		}
28825212Skarels 	} else if (errors[FE_TOTAL]) {
28925212Skarels 		struct bt_bad *bt;
29025212Skarels 
29125212Skarels 		printf("New bad sectors (not added to table):\n");
29225212Skarels 		bt = dkbad.bt_bad;
29325212Skarels 		for (i = 0; i < errors[FE_TOTAL]; i++) {
29425438Skarels 			printf("bn %d (cn=%d, tn=%d, sn=%d)\n", badsn(bt, &st),
29525212Skarels 			    bt->bt_cyl, bt->bt_trksec>>8, bt->bt_trksec&0xff);
29625212Skarels 			bt++;
29725212Skarels 		}
29811367Ssam 	}
29911367Ssam 	printf("Done\n");
30011367Ssam 	ioctl(fd,SAIONOSSI,(char *)0);
30111367Ssam 	close(fd);
30211367Ssam #ifndef JUSTEXIT
30311367Ssam 	goto again;
30411367Ssam #endif
30511367Ssam }
30611367Ssam 
30715051Skarels qcompar(l1, l2)
30825438Skarels register daddr_t *l1, *l2;
30915051Skarels {
31015051Skarels 	if (*l1 < *l2)
31115051Skarels 		return(-1);
31215051Skarels 	if (*l1 == *l2)
31315051Skarels 		return(0);
31415051Skarels 	return(1);
31515051Skarels }
31615051Skarels 
31725212Skarels daddr_t
31825212Skarels badsn(bt, st)
31925212Skarels 	register struct bt_bad *bt;
32025212Skarels 	register struct st *st;
32125212Skarels {
32225438Skarels 
32325438Skarels 	if (ssdev)
32425438Skarels 	    return ((bt->bt_cyl * st->ntrak + (bt->bt_trksec>>8)) *
32525438Skarels 		(st->nsect - 1) + (bt->bt_trksec&0xff)) - 1;
32625438Skarels 	else
32725438Skarels 	    return ((bt->bt_cyl*st->ntrak + (bt->bt_trksec>>8)) * st->nsect
32825212Skarels 		+ (bt->bt_trksec&0xff));
32925212Skarels }
33025212Skarels 
33111367Ssam /*
33225212Skarels  * Mark the bad/skipped sectors.
33325438Skarels  * Bad sectors on skip-sector devices are assumed to be skipped also,
33425438Skarels  * and must be done after the (earlier) first skipped sector.
33511367Ssam  */
33611367Ssam writebb(fd, nsects, dbad, st, sw)
33711367Ssam 	int nsects, fd;
33811367Ssam 	struct dkbad *dbad;
33911367Ssam 	register struct st *st;
34011367Ssam {
34111367Ssam 	struct sector bb_buf; /* buffer for one sector plus 4 byte header */
34211367Ssam 	register int i;
34311367Ssam 	int bn, j;
34411367Ssam 	struct bt_bad *btp;
34511367Ssam 
34611367Ssam 	for (i = 0; i < nsects; i++) {
34711367Ssam 		btp = &dbad->bt_bad[i];
34811367Ssam 		if (sw == BSERR) {
34911367Ssam 			bb_buf.header1 = HDR1_FMT22|btp->bt_cyl;
35025438Skarels 			if (ssdev)
35111367Ssam 				bb_buf.header1 |= HDR1_SSF;
35211367Ssam 		} else
35311367Ssam 			bb_buf.header1 =
35411367Ssam 			       btp->bt_cyl | HDR1_FMT22 | HDR1_SSF | HDR1_OKSCT;
35511367Ssam 		bb_buf.header2 = btp->bt_trksec;
35611367Ssam 		bn = st->nspc * btp->bt_cyl +
35711367Ssam 		     st->nsect * (btp->bt_trksec >> 8) +
35815009Skarels 		     (btp->bt_trksec & 0xff);
359*33553Skarels 		lseek(fd, bn * SECTSIZ, L_SET);
36011367Ssam 		ioctl(fd, SAIOHDR, (char *)0);
36111367Ssam 		write(fd, &bb_buf, sizeof (bb_buf));
36211367Ssam 		/*
36311367Ssam 		 * If skip sector, mark all remaining
36411367Ssam 		 * sectors on the track.
36511367Ssam 		 */
36625438Skarels 		if (sw == SSERR) {
36725438Skarels 			for (j = (btp->bt_trksec & 0xff) + 1, bn++;
36825438Skarels 			    j < st->nsect; j++, bn++) {
36925438Skarels 				bb_buf.header2 = j | (btp->bt_trksec & 0xff00);
370*33553Skarels 				lseek(fd, bn * SECTSIZ, L_SET);
37125438Skarels 				ioctl(fd, SAIOHDR, (char *)0);
37225438Skarels 				write(fd, &bb_buf, sizeof (bb_buf));
37325438Skarels 			}
37411367Ssam 		}
37511367Ssam 	}
37611367Ssam }
37711367Ssam 
37811367Ssam /*
37911367Ssam  * Record an error, and if there's room, put
38011367Ssam  * it in the appropriate bad sector table.
38115051Skarels  *
38215051Skarels  * If severe burnin store block in a list after making sure
38315051Skarels  * we have not already found it on a prev pass.
38411367Ssam  */
38511367Ssam recorderror(fd, bn, st)
38611367Ssam 	int fd, bn;
38711367Ssam 	register struct st *st;
38811367Ssam {
38925212Skarels 	int cn, tn, sn;
39015051Skarels 	register i;
39111367Ssam 
39215051Skarels 
39315051Skarels 	if (severe) {
39415051Skarels 		for (i = 0; i < nbads; i++)
39515051Skarels 			if (bads[i] == bn)
39615051Skarels 				return(0);	/* bn already flagged */
39725438Skarels 		if (nbads >= (ssdev ? 2 * MAXBADDESC : MAXBADDESC)) {
39825212Skarels 			printf("Bad sector table full, format terminating\n");
39915051Skarels 			return(-1);
40015051Skarels 		}
40115051Skarels 		bads[nbads++] = bn;
40217426Skarels 		if (errno < EBSE || errno > EHER)
40317426Skarels 			return(0);
40417426Skarels 		errno -= EBSE;
40517426Skarels 		errors[errno]++;
40615051Skarels 		return(0);
40715051Skarels 	}
40817426Skarels 	if (errno >= EBSE && errno <= EHER) {
40917426Skarels 		errno -= EBSE;
41017426Skarels 		errors[errno]++;
41111367Ssam 	}
41211367Ssam 	cn = bn / st->nspc;
41311367Ssam 	sn = bn % st->nspc;
41411367Ssam 	tn = sn / st->nsect;
41511367Ssam 	sn %= st->nsect;
41625438Skarels 	if (ssdev) {		/* if drive has skip sector capability */
41725212Skarels 		int ss = errors[FE_SSE];
41811367Ssam 
41925212Skarels 		if (errors[FE_SSE] >= MAXBADDESC) {
42025212Skarels 			/* this is bogus, we don't maintain skip sector table */
42125212Skarels 			printf("Too many skip sector errors\n");
42225212Skarels 			return(-1);
42325212Skarels 		}
42425212Skarels 		  /* only one skip sector/track */
42525212Skarels 		if (ss == 0 ||
42625212Skarels 		    tn != (sstab.bt_bad[ss - 1].bt_trksec >> 8) ||
42725212Skarels 		    cn != sstab.bt_bad[ss - 1].bt_cyl) {
42825438Skarels 			/*
42925438Skarels 			 * Don't bother with skipping the extra sector
43025438Skarels 			 * at the end of the track.
43125438Skarels 			 */
43225438Skarels 			if (sn == st->nsect - 1)
43325438Skarels 				return(0);
43411367Ssam 			sstab.bt_bad[ss].bt_cyl = cn;
43511367Ssam 			sstab.bt_bad[ss].bt_trksec = (tn<<8) + sn;
43625212Skarels 			errors[FE_SSE]++;
43725212Skarels 			return(0);
43811367Ssam 		}
43911367Ssam 	}
44025212Skarels 	if (errors[FE_TOTAL] >= MAXBADDESC) {
44125212Skarels 		printf("Too many bad sectors\n");
44225212Skarels 		return(-1);
44325212Skarels 	}
44411367Ssam 	/* record the bad sector address and continue */
44515009Skarels 	dkbad.bt_bad[errors[FE_TOTAL]].bt_cyl = cn;
44611367Ssam 	dkbad.bt_bad[errors[FE_TOTAL]++].bt_trksec = (tn << 8) + sn;
44715051Skarels 	return(0);
44811367Ssam }
44911367Ssam 
45011367Ssam /*
45111367Ssam  * Allocate memory on a page-aligned address.
45211367Ssam  * Round allocated chunk to a page multiple to
45311367Ssam  * ease next request.
45411367Ssam  */
45511367Ssam char *
45611367Ssam malloc(size)
45711367Ssam 	int size;
45811367Ssam {
45911367Ssam 	char *result;
46011367Ssam 	static caddr_t last = 0;
46111367Ssam 
46211367Ssam 	if (last == 0)
46311367Ssam 		last = (caddr_t)(((int)&end + 511) & ~0x1ff);
46411367Ssam 	size = (size + 511) & ~0x1ff;
46511367Ssam 	result = (char *)last;
46611367Ssam 	last += size;
46711367Ssam 	return (result);
46811367Ssam }
46911367Ssam 
47011367Ssam /*
47111367Ssam  * Prompt and verify a device name from the user.
47211367Ssam  */
47311367Ssam getdevice()
47411367Ssam {
47511367Ssam 	register char *cp;
47611367Ssam 	int fd;
47711367Ssam 
47811367Ssam top:
479*33553Skarels 	do {
480*33553Skarels 		cp = prompt("Device to format? ");
481*33553Skarels 	} while ((fd = open(cp, 2)) < 0);
48215051Skarels 	printf("Formatting drive %c%c%d on adaptor %d: ",
48315051Skarels 		cp[0], cp[1], iob[fd - 3].i_unit % 8, iob[fd - 3].i_unit / 8);
48411367Ssam 	cp = prompt("verify (yes/no)? ");
48511367Ssam 	while (*cp != 'y' && *cp != 'n')
48611367Ssam 		cp = prompt("Huh, yes or no? ");
48711367Ssam 	if (*cp == 'y')
48811367Ssam 		return (fd);
48911367Ssam 	goto top;
49011367Ssam }
49111367Ssam 
49225212Skarels /*
49325212Skarels  * Find range of tracks to format.
49425212Skarels  */
49525212Skarels getrange(st)
49625212Skarels 	struct st *st;
49725212Skarels {
49825212Skarels 	startcyl = getnum("Starting cylinder", 0, st->ncyl - 1, 0);
49925438Skarels 	starttrack = getnum("Starting track", 0, st->ntrak - 1, 0);
50025212Skarels 	endcyl = getnum("Ending cylinder", 0, st->ncyl - 1, st->ncyl - 1);
50125212Skarels 	endtrack = getnum("Ending track", 0, st->ntrak - 1, st->ntrak - 1);
50225212Skarels }
50325212Skarels 
50425212Skarels getnum(s, low, high, dflt)
50525212Skarels {
50625212Skarels 	char buf[132];
50725212Skarels 	unsigned val;
50825212Skarels 
50925212Skarels 	while (1) {
51025212Skarels 		printf("%s (%d): ", s, dflt);
51125212Skarels 		gets(buf);
51225212Skarels 		if (buf[0] == 0)
51325212Skarels 			return (dflt);
51425212Skarels 		val = atoi(buf);
51525212Skarels 		if (val >= low && val <= high)
51625212Skarels 			return ((int)val);
51725212Skarels 		printf("Value must be in range [%d,%d]\n", low, high);
51825212Skarels 	}
51925212Skarels }
52025212Skarels 
52111371Ssam static struct pattern {
52211371Ssam 	long	pa_value;
52311371Ssam 	char	*pa_name;
52411371Ssam } pat[] = {
52511371Ssam 	{ 0xf00ff00f, 	"RH750 worst case" },
52611371Ssam 	{ 0xec6dec6d,	"media worst case" },
52711371Ssam 	{ 0xa5a5a5a5,	"alternate 1's and 0's" },
52817426Skarels 	{ 0xFFFFFFFF,	"Severe burnin (up to 48 passes)" },
52911371Ssam 	{ 0, 0 },
53011371Ssam };
53111371Ssam 
53211371Ssam getpattern()
53311371Ssam {
53411371Ssam 	register struct pattern *p;
53511371Ssam 	int npatterns;
53611371Ssam 	char *cp;
53711371Ssam 
53811371Ssam 	printf("Available test patterns are:\n");
53911371Ssam 	for (p = pat; p->pa_value; p++)
54011371Ssam 		printf("\t%d - (%x) %s\n", (p - pat) + 1,
54111371Ssam 		  p->pa_value & 0xffff, p->pa_name);
54211371Ssam 	npatterns = p - pat;
54311371Ssam 	cp = prompt("Pattern (one of the above, other to restart)? ");
54411371Ssam 	pattern = atoi(cp) - 1;
54517426Skarels 	if (pattern < 0 || pattern >= npatterns)
54617426Skarels 		return(1);
54715051Skarels 	severe = 0;
54817426Skarels 	maxpass = 1;
54917426Skarels 	if (pat[pattern].pa_value == -1) {
55015051Skarels 		severe = 1;
55117426Skarels 		cp = prompt("How many passes (up to 48)? ");
55217426Skarels 		maxpass = atoi(cp);
55317426Skarels 		if (maxpass > NPT)
55417426Skarels 			maxpass = NPT;
55517426Skarels 	}
55625438Skarels 	maxeccbits = getnum(
55725438Skarels 		"Maximum number of bit errors to allow for soft ECC",
55825438Skarels 		0, 11, MAXECCBITS);
55917426Skarels 	return (0);
56011371Ssam }
56111371Ssam 
56211371Ssam struct xsect {
56311371Ssam 	u_short	hd1;
56411371Ssam 	u_short	hd2;
56511371Ssam 	long	buf[128];
56611371Ssam };
56711371Ssam 
56811371Ssam /*
56911371Ssam  * Initialize the buffer with the requested pattern.
57011371Ssam  */
57111371Ssam bufinit(bp, size)
57211371Ssam 	register struct xsect *bp;
57311371Ssam 	int size;
57411371Ssam {
57511371Ssam 	register struct pattern *pptr;
57611371Ssam 	register long *pp, *last;
57711371Ssam 	register struct xsect *lastbuf;
57815051Skarels 	int patt;
57911371Ssam 
58011371Ssam 	size /= sizeof (struct sector);
58111371Ssam 	lastbuf = bp + size;
58215051Skarels 	if (severe) {
58315051Skarels 		patt = ppat[npat] | ((long)ppat[npat] << 16);
58415051Skarels 		printf("Write pattern 0x%x\n", patt&0xffff);
58515051Skarels 	} else {
58615051Skarels 		pptr = &pat[pattern];
58715051Skarels 		patt = pptr->pa_value;
58815051Skarels 	}
58911371Ssam 	while (bp < lastbuf) {
59011371Ssam 		last = &bp->buf[128];
59111371Ssam 		for (pp = bp->buf; pp < last; pp++)
59215051Skarels 			*pp = patt;
59311371Ssam 		bp++;
59411371Ssam 	}
59511371Ssam }
59611371Ssam 
59711367Ssam char *
59811367Ssam prompt(msg)
59911367Ssam 	char *msg;
60011367Ssam {
60111367Ssam 	static char buf[132];
60211367Ssam 
60311367Ssam 	printf("%s", msg);
60411367Ssam 	gets(buf);
60511367Ssam 	return (buf);
60611367Ssam }
607