xref: /csrg-svn/sys/vax/stand/format.c (revision 12175)
1*12175Shelge /*	format.c	4.4	83/05/03	*/
211367Ssam 
311367Ssam /*
411367Ssam  * Standalone program to do media checking
511367Ssam  * and record bad block information on any
611367Ssam  * disk with the appropriate driver.
711367Ssam  */
811367Ssam #include "../h/param.h"
911367Ssam #include "../h/fs.h"
1011367Ssam #include "../h/inode.h"
1111367Ssam #include "../h/dkbad.h"
1211367Ssam #include "../h/vmmac.h"
1311367Ssam 
1411367Ssam #include "saio.h"
1511367Ssam #include "savax.h"
1611367Ssam 
1711367Ssam #define MAXBADDESC	126		/* size of bad block table */
1811367Ssam #define CHUNK		48		/* max # of sectors/io operation */
1911367Ssam #define SECTSIZ		512		/* standard sector size */
2011367Ssam #define HDRSIZ		4		/* number of bytes in sector header */
2111367Ssam 
2211367Ssam #define SSERR		0
2311367Ssam #define BSERR		1
2411367Ssam 
2511367Ssam #define SSDEV		((ioctl(iob[fd-3], SAIOSSDEV, (char *)0) == 0))
2611367Ssam 
2711367Ssam struct sector {
2811367Ssam 	u_short	header1;
2911367Ssam 	u_short header2;
3011367Ssam 	char	buf[SECTSIZ];
3111367Ssam };
3211367Ssam 
3311367Ssam struct	dkbad dkbad;		/* bad sector table */
3411367Ssam struct	dkbad sstab;		/* skip sector table */
3511367Ssam 
3611367Ssam #define	NERRORS		6
3711371Ssam static char *
3811371Ssam errornames[NERRORS] = {
3911367Ssam #define	FE_WCE		0
4011367Ssam 	"Write check",
4111367Ssam #define	FE_BSE		1
4211367Ssam 	"Bad sector",
4311367Ssam #define	FE_ECC		2
4411367Ssam 	"ECC",
4511367Ssam #define	FE_HARD		3
4611367Ssam 	"Other hard",
4711367Ssam #define	FE_TOTAL	4
4811367Ssam 	"Total",
4911367Ssam #define	FE_SSE		5
5011367Ssam 	"Skip sector",
5111367Ssam };
5211367Ssam 
5311367Ssam int	errors[NERRORS];	/* histogram of errors */
5411371Ssam int	pattern;
5511367Ssam 
5611367Ssam char	*malloc();
5711367Ssam char	*prompt();
5811367Ssam extern	int end;
5911367Ssam 
6011367Ssam main()
6111367Ssam {
6211367Ssam 	register int sector, sn;
6311371Ssam 	int lastsector, tracksize;
6411367Ssam 	int unit, fd, resid, i, trk, cyl, debug;
6511367Ssam 	struct st st;
6611367Ssam 	struct sector *bp, *cbp;
6711367Ssam 	char *cp;
6811367Ssam 
6911367Ssam 	printf("Disk format/check utility\n\n");
7011367Ssam 
7111367Ssam again:
7211367Ssam 	cp = prompt("Enable debugging (1=bse, 2=ecc, 3=bse+ecc)? ");
7311367Ssam 	debug = atoi(cp);
7411367Ssam 	if (debug < 0)
7511367Ssam 		debug = 0;
7611367Ssam 	for (i = 0; i < NERRORS; i++)
7711367Ssam 		errors[i] = 0;
7811367Ssam 	fd = getdevice();
7911367Ssam 	ioctl(fd, SAIODEVDATA, &st);
8011367Ssam 	printf("Device data: #cylinders=%d, #tracks=%d, #sectors=%d\n",
8111367Ssam 	  st.ncyl, st.ntrak, st.nsect);
8211371Ssam 	if (getpattern())
8311367Ssam 		goto again;
8411367Ssam 	printf("Start formatting...make sure the drive is online\n");
8511367Ssam 	ioctl(fd, SAIONOBAD, (char *)0);
8611367Ssam 	ioctl(fd, SAIOECCLIM, (char *)0);
8711367Ssam 	ioctl(fd, SAIODEBUG, (char *)debug);
8811367Ssam 	if (SSDEV) {
8911367Ssam 		ioctl(fd, SAIOSSI, (char *)0);	/* set skip sector inhibit */
9011367Ssam 		st.nsect++;
9111367Ssam 		st.nspc += st.ntrak;
9211367Ssam 	}
9311367Ssam 	tracksize = sizeof (struct sector) * st.nsect;
9411367Ssam 	bp = (struct sector *)malloc(tracksize);
9511371Ssam 	bufinit(bp, tracksize);
9611367Ssam 	/*
9711367Ssam 	 * Begin check, for each track,
9811367Ssam 	 *
9911367Ssam 	 * 1) Write header and test pattern.
10011367Ssam 	 * 2) Write check header and data.
10111367Ssam 	 */
10211367Ssam 	lastsector = st.nspc * st.ncyl;
10311367Ssam 	for (sector = 0; sector < lastsector; sector += st.nsect) {
10411367Ssam 		cyl = sector / st.nspc;
10511367Ssam 		trk = (sector % st.nspc) / st.nsect;
10611367Ssam 		for (i = 0; i < st.nsect; i++) {
10711367Ssam 			bp[i].header1 =
10811367Ssam 				(u_short) cyl | HDR1_FMT22 | HDR1_OKSCT;
10911367Ssam 			bp[i].header2 = ((u_short)trk << 8) + i;
11011367Ssam 		}
11111367Ssam 		if (sector && (sector % (st.nspc * 10)) == 0)
112*12175Shelge 			printf("cylinder %d\n", cyl);
11311367Ssam 		/*
11411367Ssam 		 * Try and write the headers and data patterns into
11511367Ssam 		 * each sector in the track.  Continue until such
11611367Ssam 		 * we're done, or until there's less than a sector's
11711367Ssam 		 * worth of data to transfer.
11811367Ssam 		 *
11911367Ssam 		 * The lseek call is necessary because of
12011367Ssam 		 * the odd sector size (516 bytes)
12111367Ssam 		 */
12211367Ssam 		for (resid = tracksize, cbp = bp, sn = sector;;) {
12311367Ssam 			int cc;
12411367Ssam 
12511367Ssam 			lseek(fd, sn * SECTSIZ, 0);
12611367Ssam 			ioctl(fd, SAIOHDR, (char *)0);
12711367Ssam 			cc = write(fd, cbp, resid);
12811367Ssam 			if (cc == resid)
12911367Ssam 				break;
13011367Ssam 			/*
13111367Ssam 			 * Don't record errors during write,
13211367Ssam 			 * all errors will be found during
13311367Ssam 			 * writecheck performed below.
13411367Ssam 			 */
13511367Ssam 			sn = iob[fd - 3].i_errblk;
13611367Ssam 			cbp += sn - sector;
13711367Ssam 			resid -= (sn - sector) * sizeof (struct sector);
13811367Ssam 			if (resid < sizeof (struct sector))
13911367Ssam 				break;
14011367Ssam 		}
14111367Ssam 		/*
14211367Ssam 		 * Write check headers and test patterns.
14311367Ssam 		 * Retry remainder of track on error until
14411367Ssam 		 * we're done, or until there's less than a
14511367Ssam 		 * sector to verify.
14611367Ssam 		 */
14711367Ssam 		for (resid = tracksize, cbp = bp, sn = sector;;) {
14811367Ssam 			int cc;
14911367Ssam 
15011367Ssam 			lseek(fd, sn * SECTSIZ, 0);
15111367Ssam 			ioctl(fd, SAIOHCHECK, (char *)0);
15211367Ssam 			cc = read(fd, cbp, resid);
15311367Ssam 			if (cc == resid)
15411367Ssam 				break;
15511367Ssam 			sn = iob[fd-3].i_errblk;
15611367Ssam 			printf("sector %d, write check error\n", sn);
15711367Ssam 			recorderror(fd, sn, &st);
15811367Ssam 			/* advance past bad sector */
15911367Ssam 			sn++;
16011367Ssam 			cbp += sn - sector;
16111367Ssam 			resid -= (sn - sector) * sizeof (struct sector);
16211367Ssam 			if (resid < sizeof (struct sector))
16311367Ssam 				break;
16411367Ssam 		}
16511367Ssam 	}
16611367Ssam 	/*
16711367Ssam 	 * Checking finished.
16811367Ssam 	 */
16911367Ssam 	if (errors[FE_TOTAL] || errors[FE_SSE]) {
17011367Ssam 		printf("Errors:\n");
17111367Ssam 		for (i = 0; i < NERRORS; i++)
17211367Ssam 			printf("%s: %d\n", errornames[i], errors[i]);
17311367Ssam 		printf("Total of %d hard errors found\n",
17411367Ssam 			errors[FE_TOTAL] + errors[FE_SSE]);
17511367Ssam 		/* change the headers of all the bad sectors */
17611367Ssam 		writebb(fd, errors[FE_SSE], &sstab, &st, SSERR);
17711367Ssam 		writebb(fd, errors[FE_TOTAL], &dkbad, &st, BSERR);
17811367Ssam 	}
17911367Ssam 	while (errors[FE_TOTAL] < MAXBADDESC) {
18011367Ssam 		int i = errors[FE_TOTAL]++;
18111367Ssam 
18211367Ssam 		dkbad.bt_bad[i].bt_cyl = -1;
18311367Ssam 		dkbad.bt_bad[i].bt_trksec = -1;
18411367Ssam 	}
18511367Ssam 	printf("\nWriting bad sector table at sector #%d\n",
18611367Ssam 		st.ncyl * st.nspc - st.nsect);
18711367Ssam 	/* place on disk */
18811367Ssam 	for (i = 0; i < 10; i += 2) {
18911367Ssam 		lseek(fd, SECTSIZ * (st.ncyl * st.nspc - st.nsect + i), 0);
19011367Ssam 		write(fd, &dkbad, sizeof (dkbad));
19111367Ssam 	}
19211367Ssam 	printf("Done\n");
19311367Ssam 	ioctl(fd,SAIONOSSI,(char *)0);
19411367Ssam 	close(fd);
19511367Ssam #ifndef JUSTEXIT
19611367Ssam 	goto again;
19711367Ssam #endif
19811367Ssam }
19911367Ssam 
20011367Ssam /*
20111367Ssam  * Write out the bad blocks.
20211367Ssam  */
20311367Ssam writebb(fd, nsects, dbad, st, sw)
20411367Ssam 	int nsects, fd;
20511367Ssam 	struct dkbad *dbad;
20611367Ssam 	register struct st *st;
20711367Ssam {
20811367Ssam 	struct sector bb_buf; /* buffer for one sector plus 4 byte header */
20911367Ssam 	register int i;
21011367Ssam 	int bn, j;
21111367Ssam 	struct bt_bad *btp;
21211367Ssam 
21311367Ssam 	for (i = 0; i < nsects; i++) {
21411367Ssam 		btp = &dbad->bt_bad[i];
21511367Ssam 		if (sw == BSERR) {
21611367Ssam 			bb_buf.header1 = HDR1_FMT22|btp->bt_cyl;
21711367Ssam 			if (SSDEV)
21811367Ssam 				bb_buf.header1 |= HDR1_SSF;
21911367Ssam 		} else
22011367Ssam 			bb_buf.header1 =
22111367Ssam 			       btp->bt_cyl | HDR1_FMT22 | HDR1_SSF | HDR1_OKSCT;
22211367Ssam 		bb_buf.header2 = btp->bt_trksec;
22311367Ssam 		bn = st->nspc * btp->bt_cyl +
22411367Ssam 		     st->nsect * (btp->bt_trksec >> 8) +
22511367Ssam 		     (btp->bt_trksec & 0x1f);
22611367Ssam 		lseek(fd, bn * SECTSIZ, 0);
22711367Ssam 		ioctl(fd, SAIOHDR, (char *)0);
22811367Ssam 		write(fd, &bb_buf, sizeof (bb_buf));
22911367Ssam 		if (!SSDEV)
23011367Ssam 			continue;
23111367Ssam 		/*
23211367Ssam 		 * If skip sector, mark all remaining
23311367Ssam 		 * sectors on the track.
23411367Ssam 		 */
23511367Ssam 		for (j = (btp->bt_trksec & 0x1f) + 1; j < st->nsect; j++) {
23611367Ssam 			bb_buf.header1 = j | HDR1_FMT22 | HDR1_SSF;
23711367Ssam 			ioctl(fd, SAIOHDR, (char *)0);
23811367Ssam 			write(fd, &bb_buf, sizeof (bb_buf));
23911367Ssam 		}
24011367Ssam 	}
24111367Ssam }
24211367Ssam 
24311367Ssam /*
24411367Ssam  * Record an error, and if there's room, put
24511367Ssam  * it in the appropriate bad sector table.
24611367Ssam  */
24711367Ssam recorderror(fd, bn, st)
24811367Ssam 	int fd, bn;
24911367Ssam 	register struct st *st;
25011367Ssam {
25111367Ssam 	int cn, tn, sn, strk;
25211367Ssam 
25311367Ssam 	if (errors[FE_TOTAL] >= MAXBADDESC) {
25411367Ssam 		printf("Too many bad sectors\n");
25511367Ssam 		return;
25611367Ssam 	}
25711367Ssam 	if (errors[FE_SSE] >= MAXBADDESC) {
25811367Ssam 		printf("Too many skip sector errors\n");
25911367Ssam 		return;
26011367Ssam 	}
26111367Ssam 	if (errno <= ECMD || errno > EHER)
26211367Ssam 		return;
26311367Ssam 	errors[errno]++;
26411367Ssam 	cn = bn / st->nspc;
26511367Ssam 	sn = bn % st->nspc;
26611367Ssam 	tn = sn / st->nsect;
26711367Ssam 	sn %= st->nsect;
26811367Ssam 	if (SSDEV) {		/* if drive has skip sector capability */
26911367Ssam 		int ss = errors[FE_SSE]++;
27011367Ssam 
27111367Ssam 		if (ss)
27211367Ssam 			strk = sstab.bt_bad[ss - 1].bt_trksec >> 8;
27311367Ssam 		else
27411367Ssam 			strk = -1;
27511367Ssam 		if (tn != strk) {	  /* only one skip sector/track */
27611367Ssam 			sstab.bt_bad[ss].bt_cyl = cn;
27711367Ssam 			sstab.bt_bad[ss].bt_trksec = (tn<<8) + sn;
27811367Ssam 			return;
27911367Ssam 		}
28011367Ssam 		cn = -cn;
28111367Ssam 	}
28211367Ssam 	/* record the bad sector address and continue */
28311367Ssam 	dkbad.bt_bad[errors[FE_TOTAL]++].bt_cyl = cn;
28411367Ssam 	dkbad.bt_bad[errors[FE_TOTAL]++].bt_trksec = (tn << 8) + sn;
28511367Ssam }
28611367Ssam 
28711367Ssam /*
28811367Ssam  * Allocate memory on a page-aligned address.
28911367Ssam  * Round allocated chunk to a page multiple to
29011367Ssam  * ease next request.
29111367Ssam  */
29211367Ssam char *
29311367Ssam malloc(size)
29411367Ssam 	int size;
29511367Ssam {
29611367Ssam 	char *result;
29711367Ssam 	static caddr_t last = 0;
29811367Ssam 
29911367Ssam 	if (last == 0)
30011367Ssam 		last = (caddr_t)(((int)&end + 511) & ~0x1ff);
30111367Ssam 	size = (size + 511) & ~0x1ff;
30211367Ssam 	result = (char *)last;
30311367Ssam 	last += size;
30411367Ssam 	return (result);
30511367Ssam }
30611367Ssam 
30711367Ssam /*
30811367Ssam  * Prompt and verify a device name from the user.
30911367Ssam  */
31011367Ssam getdevice()
31111367Ssam {
31211367Ssam 	register char *cp;
31311367Ssam 	register struct devsw *dp;
31411367Ssam 	int fd;
31511367Ssam 
31611367Ssam top:
31711367Ssam 	cp = prompt("Device to format? ");
31811367Ssam 	if ((fd = open(cp, 2)) < 0) {
31911367Ssam 		printf("Known devices are: ");
32011367Ssam 		for (dp = devsw; dp->dv_name; dp++)
32111367Ssam 			printf("%s ",dp->dv_name);
32211367Ssam 		printf("\n");
32311367Ssam 		goto top;
32411367Ssam 	}
32511367Ssam 	printf("Formatting drive %d on %c%c%d ",
32611367Ssam 		iob[fd - 3].i_unit % 8, cp[0], cp[1], iob[fd - 3].i_unit / 8);
32711367Ssam 	cp = prompt("verify (yes/no)? ");
32811367Ssam 	while (*cp != 'y' && *cp != 'n')
32911367Ssam 		cp = prompt("Huh, yes or no? ");
33011367Ssam 	if (*cp == 'y')
33111367Ssam 		return (fd);
33211367Ssam 	goto top;
33311367Ssam }
33411367Ssam 
33511371Ssam static struct pattern {
33611371Ssam 	long	pa_value;
33711371Ssam 	char	*pa_name;
33811371Ssam } pat[] = {
33911371Ssam 	{ 0xf00ff00f, 	"RH750 worst case" },
34011371Ssam 	{ 0xec6dec6d,	"media worst case" },
34111371Ssam 	{ 0xa5a5a5a5,	"alternate 1's and 0's" },
34211371Ssam 	{ 0, 0 },
34311371Ssam };
34411371Ssam 
34511371Ssam getpattern()
34611371Ssam {
34711371Ssam 	register struct pattern *p;
34811371Ssam 	int npatterns;
34911371Ssam 	char *cp;
35011371Ssam 
35111371Ssam 	printf("Available test patterns are:\n");
35211371Ssam 	for (p = pat; p->pa_value; p++)
35311371Ssam 		printf("\t%d - (%x) %s\n", (p - pat) + 1,
35411371Ssam 		  p->pa_value & 0xffff, p->pa_name);
35511371Ssam 	npatterns = p - pat;
35611371Ssam 	cp = prompt("Pattern (one of the above, other to restart)? ");
35711371Ssam 	pattern = atoi(cp) - 1;
35811371Ssam 	return (pattern < 0 || pattern >= npatterns);
35911371Ssam }
36011371Ssam 
36111371Ssam struct xsect {
36211371Ssam 	u_short	hd1;
36311371Ssam 	u_short	hd2;
36411371Ssam 	long	buf[128];
36511371Ssam };
36611371Ssam 
36711371Ssam /*
36811371Ssam  * Initialize the buffer with the requested pattern.
36911371Ssam  */
37011371Ssam bufinit(bp, size)
37111371Ssam 	register struct xsect *bp;
37211371Ssam 	int size;
37311371Ssam {
37411371Ssam 	register struct pattern *pptr;
37511371Ssam 	register long *pp, *last;
37611371Ssam 	register struct xsect *lastbuf;
37711371Ssam 
37811371Ssam 	size /= sizeof (struct sector);
37911371Ssam 	lastbuf = bp + size;
38011371Ssam 	pptr = &pat[pattern];
38111371Ssam 	while (bp < lastbuf) {
38211371Ssam 		last = &bp->buf[128];
38311371Ssam 		for (pp = bp->buf; pp < last; pp++)
38411371Ssam 			*pp = pptr->pa_value;
38511371Ssam 		bp++;
38611371Ssam 	}
38711371Ssam }
38811371Ssam 
38911367Ssam char *
39011367Ssam prompt(msg)
39111367Ssam 	char *msg;
39211367Ssam {
39311367Ssam 	static char buf[132];
39411367Ssam 
39511367Ssam 	printf("%s", msg);
39611367Ssam 	gets(buf);
39711367Ssam 	return (buf);
39811367Ssam }
399