xref: /csrg-svn/sys/vax/stand/format.c (revision 25438)
123251Smckusick /*
223251Smckusick  * Copyright (c) 1980 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[] =
923251Smckusick "@(#) Copyright (c) 1980 Regents of the University of California.\n\
1023251Smckusick  All rights reserved.\n";
1123251Smckusick #endif not lint
1215051Skarels 
1323251Smckusick #ifndef lint
14*25438Skarels static char sccsid[] = "@(#)format.c	6.7 (Berkeley) 11/08/85";
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  */
2711367Ssam #include "../h/param.h"
2811367Ssam #include "../h/fs.h"
2911367Ssam #include "../h/inode.h"
3011367Ssam #include "../h/dkbad.h"
3111367Ssam #include "../h/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 
44*25438Skarels #define SSDEV(fd)	(ioctl((fd), SAIOSSDEV, (char *)0) == 0)
45*25438Skarels #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 */
54*25438Skarels 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
65*25438Skarels 	"Hard ECC",
6611367Ssam #define	FE_HARD		3
6711367Ssam 	"Other hard",
6811367Ssam #define	FE_TOTAL	4
69*25438Skarels 	"Marked bad",
7011367Ssam #define	FE_SSE		5
71*25438Skarels 	"Skipped",
7211367Ssam };
7311367Ssam 
7411367Ssam int	errors[NERRORS];	/* histogram of errors */
7511371Ssam int	pattern;
76*25438Skarels 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 */
95*25438Skarels int	ssdev;			/* device supports skip sectors */
9625212Skarels int	startcyl, endcyl, starttrack, endtrack;
97*25438Skarels int	nbads;			/* subscript for bads */
98*25438Skarels 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);
131*25438Skarels 	ssdev = SSDEV(fd);
132*25438Skarels 	if (ssdev) {
133*25438Skarels 		ioctl(fd, SAIOSSI, (char *)0);	/* set skip sector inhibit */
134*25438Skarels 		st.nsect++;
135*25438Skarels 		st.nspc += st.ntrak;
136*25438Skarels 		printf("(not counting skip-sector replacement)\n");
137*25438Skarels 	}
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);
143*25438Skarels 	ioctl(fd, SAIORETRIES, (char *)0);
144*25438Skarels 	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 
19115051Skarels 				lseek(fd, sn * SECTSIZ, 0);
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
199*25438Skarels 				 * 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;;) {
214*25438Skarels 				int cc, rsn;
21511367Ssam 
21615051Skarels 				lseek(fd, sn * SECTSIZ, 0);
21715051Skarels 				cc = read(fd, rcbp, resid);
21815051Skarels 				if (cc == resid)
21915051Skarels 					break;
22015051Skarels 				sn = iob[fd-3].i_errblk;
221*25438Skarels 				if (ssdev) {
222*25438Skarels 					rsn = sn - (sn / st.nsect);
223*25438Skarels 					printf("data ");
224*25438Skarels 				} else
225*25438Skarels 					rsn = sn;
226*25438Skarels 				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++;
231*25438Skarels 				resid = rtracksize - ((sn - sector) * SECTSIZ);
232*25438Skarels 				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 		 */
254*25438Skarels 		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 	}
266*25438Skarels 	if (errors[FE_TOTAL] || errors[FE_SSE]) {
267*25438Skarels 		printf("Errors:\n");
268*25438Skarels 		for (i = 0; i < NERRORS; i++)
269*25438Skarels 			printf("%s: %d\n", errornames[i], errors[i]);
270*25438Skarels 		printf("Total of %d hard errors revectored\n",
271*25438Skarels 			errors[FE_TOTAL] + errors[FE_SSE]);
272*25438Skarels 	}
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) {
28525212Skarels 			lseek(fd, SECTSIZ * (st.ncyl * st.nspc - st.nsect + i), 0);
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++) {
294*25438Skarels 			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)
308*25438Skarels 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 {
322*25438Skarels 
323*25438Skarels 	if (ssdev)
324*25438Skarels 	    return ((bt->bt_cyl * st->ntrak + (bt->bt_trksec>>8)) *
325*25438Skarels 		(st->nsect - 1) + (bt->bt_trksec&0xff)) - 1;
326*25438Skarels 	else
327*25438Skarels 	    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.
333*25438Skarels  * Bad sectors on skip-sector devices are assumed to be skipped also,
334*25438Skarels  * 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;
350*25438Skarels 			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);
35911367Ssam 		lseek(fd, bn * SECTSIZ, 0);
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 		 */
366*25438Skarels 		if (sw == SSERR) {
367*25438Skarels 			for (j = (btp->bt_trksec & 0xff) + 1, bn++;
368*25438Skarels 			    j < st->nsect; j++, bn++) {
369*25438Skarels 				bb_buf.header2 = j | (btp->bt_trksec & 0xff00);
370*25438Skarels 				lseek(fd, bn * SECTSIZ, 0);
371*25438Skarels 				ioctl(fd, SAIOHDR, (char *)0);
372*25438Skarels 				write(fd, &bb_buf, sizeof (bb_buf));
373*25438Skarels 			}
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 */
397*25438Skarels 		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;
416*25438Skarels 	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) {
428*25438Skarels 			/*
429*25438Skarels 			 * Don't bother with skipping the extra sector
430*25438Skarels 			 * at the end of the track.
431*25438Skarels 			 */
432*25438Skarels 			if (sn == st->nsect - 1)
433*25438Skarels 				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 	register struct devsw *dp;
47711367Ssam 	int fd;
47811367Ssam 
47911367Ssam top:
48011367Ssam 	cp = prompt("Device to format? ");
48111367Ssam 	if ((fd = open(cp, 2)) < 0) {
48211367Ssam 		printf("Known devices are: ");
48311367Ssam 		for (dp = devsw; dp->dv_name; dp++)
48411367Ssam 			printf("%s ",dp->dv_name);
48511367Ssam 		printf("\n");
48611367Ssam 		goto top;
48711367Ssam 	}
48815051Skarels 	printf("Formatting drive %c%c%d on adaptor %d: ",
48915051Skarels 		cp[0], cp[1], iob[fd - 3].i_unit % 8, iob[fd - 3].i_unit / 8);
49011367Ssam 	cp = prompt("verify (yes/no)? ");
49111367Ssam 	while (*cp != 'y' && *cp != 'n')
49211367Ssam 		cp = prompt("Huh, yes or no? ");
49311367Ssam 	if (*cp == 'y')
49411367Ssam 		return (fd);
49511367Ssam 	goto top;
49611367Ssam }
49711367Ssam 
49825212Skarels /*
49925212Skarels  * Find range of tracks to format.
50025212Skarels  */
50125212Skarels getrange(st)
50225212Skarels 	struct st *st;
50325212Skarels {
50425212Skarels 	startcyl = getnum("Starting cylinder", 0, st->ncyl - 1, 0);
505*25438Skarels 	starttrack = getnum("Starting track", 0, st->ntrak - 1, 0);
50625212Skarels 	endcyl = getnum("Ending cylinder", 0, st->ncyl - 1, st->ncyl - 1);
50725212Skarels 	endtrack = getnum("Ending track", 0, st->ntrak - 1, st->ntrak - 1);
50825212Skarels }
50925212Skarels 
51025212Skarels getnum(s, low, high, dflt)
51125212Skarels {
51225212Skarels 	char buf[132];
51325212Skarels 	unsigned val;
51425212Skarels 
51525212Skarels 	while (1) {
51625212Skarels 		printf("%s (%d): ", s, dflt);
51725212Skarels 		gets(buf);
51825212Skarels 		if (buf[0] == 0)
51925212Skarels 			return (dflt);
52025212Skarels 		val = atoi(buf);
52125212Skarels 		if (val >= low && val <= high)
52225212Skarels 			return ((int)val);
52325212Skarels 		printf("Value must be in range [%d,%d]\n", low, high);
52425212Skarels 	}
52525212Skarels }
52625212Skarels 
52711371Ssam static struct pattern {
52811371Ssam 	long	pa_value;
52911371Ssam 	char	*pa_name;
53011371Ssam } pat[] = {
53111371Ssam 	{ 0xf00ff00f, 	"RH750 worst case" },
53211371Ssam 	{ 0xec6dec6d,	"media worst case" },
53311371Ssam 	{ 0xa5a5a5a5,	"alternate 1's and 0's" },
53417426Skarels 	{ 0xFFFFFFFF,	"Severe burnin (up to 48 passes)" },
53511371Ssam 	{ 0, 0 },
53611371Ssam };
53711371Ssam 
53811371Ssam getpattern()
53911371Ssam {
54011371Ssam 	register struct pattern *p;
54111371Ssam 	int npatterns;
54211371Ssam 	char *cp;
54311371Ssam 
54411371Ssam 	printf("Available test patterns are:\n");
54511371Ssam 	for (p = pat; p->pa_value; p++)
54611371Ssam 		printf("\t%d - (%x) %s\n", (p - pat) + 1,
54711371Ssam 		  p->pa_value & 0xffff, p->pa_name);
54811371Ssam 	npatterns = p - pat;
54911371Ssam 	cp = prompt("Pattern (one of the above, other to restart)? ");
55011371Ssam 	pattern = atoi(cp) - 1;
55117426Skarels 	if (pattern < 0 || pattern >= npatterns)
55217426Skarels 		return(1);
55315051Skarels 	severe = 0;
55417426Skarels 	maxpass = 1;
55517426Skarels 	if (pat[pattern].pa_value == -1) {
55615051Skarels 		severe = 1;
55717426Skarels 		cp = prompt("How many passes (up to 48)? ");
55817426Skarels 		maxpass = atoi(cp);
55917426Skarels 		if (maxpass > NPT)
56017426Skarels 			maxpass = NPT;
56117426Skarels 	}
562*25438Skarels 	maxeccbits = getnum(
563*25438Skarels 		"Maximum number of bit errors to allow for soft ECC",
564*25438Skarels 		0, 11, MAXECCBITS);
56517426Skarels 	return (0);
56611371Ssam }
56711371Ssam 
56811371Ssam struct xsect {
56911371Ssam 	u_short	hd1;
57011371Ssam 	u_short	hd2;
57111371Ssam 	long	buf[128];
57211371Ssam };
57311371Ssam 
57411371Ssam /*
57511371Ssam  * Initialize the buffer with the requested pattern.
57611371Ssam  */
57711371Ssam bufinit(bp, size)
57811371Ssam 	register struct xsect *bp;
57911371Ssam 	int size;
58011371Ssam {
58111371Ssam 	register struct pattern *pptr;
58211371Ssam 	register long *pp, *last;
58311371Ssam 	register struct xsect *lastbuf;
58415051Skarels 	int patt;
58511371Ssam 
58611371Ssam 	size /= sizeof (struct sector);
58711371Ssam 	lastbuf = bp + size;
58815051Skarels 	if (severe) {
58915051Skarels 		patt = ppat[npat] | ((long)ppat[npat] << 16);
59015051Skarels 		printf("Write pattern 0x%x\n", patt&0xffff);
59115051Skarels 	} else {
59215051Skarels 		pptr = &pat[pattern];
59315051Skarels 		patt = pptr->pa_value;
59415051Skarels 	}
59511371Ssam 	while (bp < lastbuf) {
59611371Ssam 		last = &bp->buf[128];
59711371Ssam 		for (pp = bp->buf; pp < last; pp++)
59815051Skarels 			*pp = patt;
59911371Ssam 		bp++;
60011371Ssam 	}
60111371Ssam }
60211371Ssam 
60311367Ssam char *
60411367Ssam prompt(msg)
60511367Ssam 	char *msg;
60611367Ssam {
60711367Ssam 	static char buf[132];
60811367Ssam 
60911367Ssam 	printf("%s", msg);
61011367Ssam 	gets(buf);
61111367Ssam 	return (buf);
61211367Ssam }
613