xref: /csrg-svn/sys/vax/stand/format.c (revision 11367)
1*11367Ssam /*	format.c	4.1	83/03/01	*/
2*11367Ssam 
3*11367Ssam /*
4*11367Ssam  * Standalone program to do media checking
5*11367Ssam  * and record bad block information on any
6*11367Ssam  * disk with the appropriate driver.
7*11367Ssam  */
8*11367Ssam #include "../h/param.h"
9*11367Ssam #include "../h/fs.h"
10*11367Ssam #include "../h/inode.h"
11*11367Ssam #include "../h/dkbad.h"
12*11367Ssam #include "../h/vmmac.h"
13*11367Ssam 
14*11367Ssam #include "saio.h"
15*11367Ssam #include "savax.h"
16*11367Ssam 
17*11367Ssam #define MAXBADDESC	126		/* size of bad block table */
18*11367Ssam #define CHUNK		48		/* max # of sectors/io operation */
19*11367Ssam #define SECTSIZ		512		/* standard sector size */
20*11367Ssam #define HDRSIZ		4		/* number of bytes in sector header */
21*11367Ssam 
22*11367Ssam #define SSERR		0
23*11367Ssam #define BSERR		1
24*11367Ssam 
25*11367Ssam #define SSDEV		((ioctl(iob[fd-3], SAIOSSDEV, (char *)0) == 0))
26*11367Ssam 
27*11367Ssam struct sector {
28*11367Ssam 	u_short	header1;
29*11367Ssam 	u_short header2;
30*11367Ssam 	char	buf[SECTSIZ];
31*11367Ssam };
32*11367Ssam 
33*11367Ssam struct	dkbad dkbad;		/* bad sector table */
34*11367Ssam struct	dkbad sstab;		/* skip sector table */
35*11367Ssam 
36*11367Ssam #define	NERRORS		6
37*11367Ssam char	*errornames[NERRORS] = {
38*11367Ssam #define	FE_WCE		0
39*11367Ssam 	"Write check",
40*11367Ssam #define	FE_BSE		1
41*11367Ssam 	"Bad sector",
42*11367Ssam #define	FE_ECC		2
43*11367Ssam 	"ECC",
44*11367Ssam #define	FE_HARD		3
45*11367Ssam 	"Other hard",
46*11367Ssam #define	FE_TOTAL	4
47*11367Ssam 	"Total",
48*11367Ssam #define	FE_SSE		5
49*11367Ssam 	"Skip sector",
50*11367Ssam };
51*11367Ssam 
52*11367Ssam int	errors[NERRORS];	/* histogram of errors */
53*11367Ssam 
54*11367Ssam char	*malloc();
55*11367Ssam char	*prompt();
56*11367Ssam extern	int end;
57*11367Ssam 
58*11367Ssam main()
59*11367Ssam {
60*11367Ssam 	register int sector, sn;
61*11367Ssam 	int pattern, lastsector, tracksize;
62*11367Ssam 	int unit, fd, resid, i, trk, cyl, debug;
63*11367Ssam 	struct st st;
64*11367Ssam 	struct sector *bp, *cbp;
65*11367Ssam 	char *cp;
66*11367Ssam 
67*11367Ssam 	printf("Disk format/check utility\n\n");
68*11367Ssam 
69*11367Ssam again:
70*11367Ssam 	cp = prompt("Enable debugging (1=bse, 2=ecc, 3=bse+ecc)? ");
71*11367Ssam 	debug = atoi(cp);
72*11367Ssam 	if (debug < 0)
73*11367Ssam 		debug = 0;
74*11367Ssam 	for (i = 0; i < NERRORS; i++)
75*11367Ssam 		errors[i] = 0;
76*11367Ssam 	fd = getdevice();
77*11367Ssam 	ioctl(fd, SAIODEVDATA, &st);
78*11367Ssam 	printf("Device data: #cylinders=%d, #tracks=%d, #sectors=%d\n",
79*11367Ssam 	  st.ncyl, st.ntrak, st.nsect);
80*11367Ssam 	printf("Available test patterns are:\n");
81*11367Ssam 	printf("\t0 - (f00f) RH750 worst case\n");
82*11367Ssam 	printf("\t1 - (ec6d) media worst case\n");
83*11367Ssam 	printf("\t2 - (a5a5) alternate 1's & 0's\n");
84*11367Ssam 	cp = prompt("Pattern (0, 1, 2, other to restart)? ");
85*11367Ssam 	pattern = atoi(cp);
86*11367Ssam 	if (pattern < 0 || pattern > 2)
87*11367Ssam 		goto again;
88*11367Ssam 	printf("Start formatting...make sure the drive is online\n");
89*11367Ssam 	ioctl(fd, SAIONOBAD, (char *)0);
90*11367Ssam 	ioctl(fd, SAIOECCLIM, (char *)0);
91*11367Ssam 	ioctl(fd, SAIODEBUG, (char *)debug);
92*11367Ssam 	if (SSDEV) {
93*11367Ssam 		ioctl(fd, SAIOSSI, (char *)0);	/* set skip sector inhibit */
94*11367Ssam 		st.nsect++;
95*11367Ssam 		st.nspc += st.ntrak;
96*11367Ssam 	}
97*11367Ssam 	tracksize = sizeof (struct sector) * st.nsect;
98*11367Ssam 	bp = (struct sector *)malloc(tracksize);
99*11367Ssam 	bufinit(bp, tracksize, pattern);
100*11367Ssam 	/*
101*11367Ssam 	 * Begin check, for each track,
102*11367Ssam 	 *
103*11367Ssam 	 * 1) Write header and test pattern.
104*11367Ssam 	 * 2) Write check header and data.
105*11367Ssam 	 */
106*11367Ssam 	lastsector = st.nspc * st.ncyl;
107*11367Ssam 	for (sector = 0; sector < lastsector; sector += st.nsect) {
108*11367Ssam 		cyl = sector / st.nspc;
109*11367Ssam 		trk = (sector % st.nspc) / st.nsect;
110*11367Ssam 		for (i = 0; i < st.nsect; i++) {
111*11367Ssam 			bp[i].header1 =
112*11367Ssam 				(u_short) cyl | HDR1_FMT22 | HDR1_OKSCT;
113*11367Ssam 			bp[i].header2 = ((u_short)trk << 8) + i;
114*11367Ssam 		}
115*11367Ssam 		if (sector && (sector % (st.nspc * 10)) == 0)
116*11367Ssam 			printf("sector %d\n", sector);
117*11367Ssam 		/*
118*11367Ssam 		 * Try and write the headers and data patterns into
119*11367Ssam 		 * each sector in the track.  Continue until such
120*11367Ssam 		 * we're done, or until there's less than a sector's
121*11367Ssam 		 * worth of data to transfer.
122*11367Ssam 		 *
123*11367Ssam 		 * The lseek call is necessary because of
124*11367Ssam 		 * the odd sector size (516 bytes)
125*11367Ssam 		 */
126*11367Ssam 		for (resid = tracksize, cbp = bp, sn = sector;;) {
127*11367Ssam 			int cc;
128*11367Ssam 
129*11367Ssam 			lseek(fd, sn * SECTSIZ, 0);
130*11367Ssam 			ioctl(fd, SAIOHDR, (char *)0);
131*11367Ssam 			cc = write(fd, cbp, resid);
132*11367Ssam 			if (cc == resid)
133*11367Ssam 				break;
134*11367Ssam 			/*
135*11367Ssam 			 * Don't record errors during write,
136*11367Ssam 			 * all errors will be found during
137*11367Ssam 			 * writecheck performed below.
138*11367Ssam 			 */
139*11367Ssam 			sn = iob[fd - 3].i_errblk;
140*11367Ssam 			cbp += sn - sector;
141*11367Ssam 			resid -= (sn - sector) * sizeof (struct sector);
142*11367Ssam 			if (resid < sizeof (struct sector))
143*11367Ssam 				break;
144*11367Ssam 		}
145*11367Ssam 		/*
146*11367Ssam 		 * Write check headers and test patterns.
147*11367Ssam 		 * Retry remainder of track on error until
148*11367Ssam 		 * we're done, or until there's less than a
149*11367Ssam 		 * sector to verify.
150*11367Ssam 		 */
151*11367Ssam 		for (resid = tracksize, cbp = bp, sn = sector;;) {
152*11367Ssam 			int cc;
153*11367Ssam 
154*11367Ssam 			lseek(fd, sn * SECTSIZ, 0);
155*11367Ssam 			ioctl(fd, SAIOHCHECK, (char *)0);
156*11367Ssam 			cc = read(fd, cbp, resid);
157*11367Ssam 			if (cc == resid)
158*11367Ssam 				break;
159*11367Ssam 			sn = iob[fd-3].i_errblk;
160*11367Ssam 			printf("sector %d, write check error\n", sn);
161*11367Ssam 			recorderror(fd, sn, &st);
162*11367Ssam 			/* advance past bad sector */
163*11367Ssam 			sn++;
164*11367Ssam 			cbp += sn - sector;
165*11367Ssam 			resid -= (sn - sector) * sizeof (struct sector);
166*11367Ssam 			if (resid < sizeof (struct sector))
167*11367Ssam 				break;
168*11367Ssam 		}
169*11367Ssam 	}
170*11367Ssam 	/*
171*11367Ssam 	 * Checking finished.
172*11367Ssam 	 */
173*11367Ssam 	if (errors[FE_TOTAL] || errors[FE_SSE]) {
174*11367Ssam 		printf("Errors:\n");
175*11367Ssam 		for (i = 0; i < NERRORS; i++)
176*11367Ssam 			printf("%s: %d\n", errornames[i], errors[i]);
177*11367Ssam 		printf("Total of %d hard errors found\n",
178*11367Ssam 			errors[FE_TOTAL] + errors[FE_SSE]);
179*11367Ssam 		/* change the headers of all the bad sectors */
180*11367Ssam 		writebb(fd, errors[FE_SSE], &sstab, &st, SSERR);
181*11367Ssam 		writebb(fd, errors[FE_TOTAL], &dkbad, &st, BSERR);
182*11367Ssam 	}
183*11367Ssam 	while (errors[FE_TOTAL] < MAXBADDESC) {
184*11367Ssam 		int i = errors[FE_TOTAL]++;
185*11367Ssam 
186*11367Ssam 		dkbad.bt_bad[i].bt_cyl = -1;
187*11367Ssam 		dkbad.bt_bad[i].bt_trksec = -1;
188*11367Ssam 	}
189*11367Ssam 	printf("\nWriting bad sector table at sector #%d\n",
190*11367Ssam 		st.ncyl * st.nspc - st.nsect);
191*11367Ssam 	/* place on disk */
192*11367Ssam 	for (i = 0; i < 10; i += 2) {
193*11367Ssam 		lseek(fd, SECTSIZ * (st.ncyl * st.nspc - st.nsect + i), 0);
194*11367Ssam 		write(fd, &dkbad, sizeof (dkbad));
195*11367Ssam 	}
196*11367Ssam 	printf("Done\n");
197*11367Ssam 	ioctl(fd,SAIONOSSI,(char *)0);
198*11367Ssam 	close(fd);
199*11367Ssam #ifndef JUSTEXIT
200*11367Ssam 	goto again;
201*11367Ssam #endif
202*11367Ssam }
203*11367Ssam 
204*11367Ssam static struct pat {
205*11367Ssam 	long	pt[2];
206*11367Ssam } pat[3] = {
207*11367Ssam 	{ 0xf00ff00f, 0xf00ff00f }, 	/* worst case for RH750 */
208*11367Ssam 	{ 0xec6dec6d, 0xec6dec6d },	/* worst case for media */
209*11367Ssam 	{ 0xa5a5a5a5, 0xa5a5a5a5 }
210*11367Ssam };
211*11367Ssam 
212*11367Ssam struct xsect {
213*11367Ssam 	u_short	hd1;
214*11367Ssam 	u_short	hd2;
215*11367Ssam 	struct	pat buf[64];
216*11367Ssam };
217*11367Ssam 
218*11367Ssam /*
219*11367Ssam  * Initialize the buffer with the requested pattern.
220*11367Ssam  */
221*11367Ssam bufinit(bufptr, size, pattern)
222*11367Ssam 	register struct xsect bufptr[];
223*11367Ssam 	int size, pattern;
224*11367Ssam {
225*11367Ssam 	register struct pat *pptr;
226*11367Ssam 
227*11367Ssam 	int i, j;
228*11367Ssam 
229*11367Ssam 	size /= sizeof (struct sector);
230*11367Ssam 	pptr = &pat[pattern];
231*11367Ssam 	for (i = 0; i < size; i++)
232*11367Ssam 		for (j = 0; j < 64; j++)
233*11367Ssam 			bufptr[i].buf[j] = *pptr;
234*11367Ssam }
235*11367Ssam 
236*11367Ssam /*
237*11367Ssam  * Write out the bad blocks.
238*11367Ssam  */
239*11367Ssam writebb(fd, nsects, dbad, st, sw)
240*11367Ssam 	int nsects, fd;
241*11367Ssam 	struct dkbad *dbad;
242*11367Ssam 	register struct st *st;
243*11367Ssam {
244*11367Ssam 	struct sector bb_buf; /* buffer for one sector plus 4 byte header */
245*11367Ssam 	register int i;
246*11367Ssam 	int bn, j;
247*11367Ssam 	struct bt_bad *btp;
248*11367Ssam 
249*11367Ssam 	for (i = 0; i < nsects; i++) {
250*11367Ssam 		btp = &dbad->bt_bad[i];
251*11367Ssam 		if (sw == BSERR) {
252*11367Ssam 			bb_buf.header1 = HDR1_FMT22|btp->bt_cyl;
253*11367Ssam 			if (SSDEV)
254*11367Ssam 				bb_buf.header1 |= HDR1_SSF;
255*11367Ssam 		} else
256*11367Ssam 			bb_buf.header1 =
257*11367Ssam 			       btp->bt_cyl | HDR1_FMT22 | HDR1_SSF | HDR1_OKSCT;
258*11367Ssam 		bb_buf.header2 = btp->bt_trksec;
259*11367Ssam 		bn = st->nspc * btp->bt_cyl +
260*11367Ssam 		     st->nsect * (btp->bt_trksec >> 8) +
261*11367Ssam 		     (btp->bt_trksec & 0x1f);
262*11367Ssam 		lseek(fd, bn * SECTSIZ, 0);
263*11367Ssam 		ioctl(fd, SAIOHDR, (char *)0);
264*11367Ssam 		write(fd, &bb_buf, sizeof (bb_buf));
265*11367Ssam 		if (!SSDEV)
266*11367Ssam 			continue;
267*11367Ssam 		/*
268*11367Ssam 		 * If skip sector, mark all remaining
269*11367Ssam 		 * sectors on the track.
270*11367Ssam 		 */
271*11367Ssam 		for (j = (btp->bt_trksec & 0x1f) + 1; j < st->nsect; j++) {
272*11367Ssam 			bb_buf.header1 = j | HDR1_FMT22 | HDR1_SSF;
273*11367Ssam 			ioctl(fd, SAIOHDR, (char *)0);
274*11367Ssam 			write(fd, &bb_buf, sizeof (bb_buf));
275*11367Ssam 		}
276*11367Ssam 	}
277*11367Ssam }
278*11367Ssam 
279*11367Ssam /*
280*11367Ssam  * Record an error, and if there's room, put
281*11367Ssam  * it in the appropriate bad sector table.
282*11367Ssam  */
283*11367Ssam recorderror(fd, bn, st)
284*11367Ssam 	int fd, bn;
285*11367Ssam 	register struct st *st;
286*11367Ssam {
287*11367Ssam 	int cn, tn, sn, strk;
288*11367Ssam 
289*11367Ssam 	if (errors[FE_TOTAL] >= MAXBADDESC) {
290*11367Ssam 		printf("Too many bad sectors\n");
291*11367Ssam 		return;
292*11367Ssam 	}
293*11367Ssam 	if (errors[FE_SSE] >= MAXBADDESC) {
294*11367Ssam 		printf("Too many skip sector errors\n");
295*11367Ssam 		return;
296*11367Ssam 	}
297*11367Ssam 	if (errno <= ECMD || errno > EHER)
298*11367Ssam 		return;
299*11367Ssam 	errors[errno]++;
300*11367Ssam 	cn = bn / st->nspc;
301*11367Ssam 	sn = bn % st->nspc;
302*11367Ssam 	tn = sn / st->nsect;
303*11367Ssam 	sn %= st->nsect;
304*11367Ssam 	if (SSDEV) {		/* if drive has skip sector capability */
305*11367Ssam 		int ss = errors[FE_SSE]++;
306*11367Ssam 
307*11367Ssam 		if (ss)
308*11367Ssam 			strk = sstab.bt_bad[ss - 1].bt_trksec >> 8;
309*11367Ssam 		else
310*11367Ssam 			strk = -1;
311*11367Ssam 		if (tn != strk) {	  /* only one skip sector/track */
312*11367Ssam 			sstab.bt_bad[ss].bt_cyl = cn;
313*11367Ssam 			sstab.bt_bad[ss].bt_trksec = (tn<<8) + sn;
314*11367Ssam 			return;
315*11367Ssam 		}
316*11367Ssam 		cn = -cn;
317*11367Ssam 	}
318*11367Ssam 	/* record the bad sector address and continue */
319*11367Ssam 	dkbad.bt_bad[errors[FE_TOTAL]++].bt_cyl = cn;
320*11367Ssam 	dkbad.bt_bad[errors[FE_TOTAL]++].bt_trksec = (tn << 8) + sn;
321*11367Ssam }
322*11367Ssam 
323*11367Ssam /*
324*11367Ssam  * Allocate memory on a page-aligned address.
325*11367Ssam  * Round allocated chunk to a page multiple to
326*11367Ssam  * ease next request.
327*11367Ssam  */
328*11367Ssam char *
329*11367Ssam malloc(size)
330*11367Ssam 	int size;
331*11367Ssam {
332*11367Ssam 	char *result;
333*11367Ssam 	static caddr_t last = 0;
334*11367Ssam 
335*11367Ssam 	if (last == 0)
336*11367Ssam 		last = (caddr_t)(((int)&end + 511) & ~0x1ff);
337*11367Ssam 	size = (size + 511) & ~0x1ff;
338*11367Ssam 	result = (char *)last;
339*11367Ssam 	last += size;
340*11367Ssam 	return (result);
341*11367Ssam }
342*11367Ssam 
343*11367Ssam /*
344*11367Ssam  * Prompt and verify a device name from the user.
345*11367Ssam  */
346*11367Ssam getdevice()
347*11367Ssam {
348*11367Ssam 	register char *cp;
349*11367Ssam 	register struct devsw *dp;
350*11367Ssam 	int fd;
351*11367Ssam 
352*11367Ssam top:
353*11367Ssam 	cp = prompt("Device to format? ");
354*11367Ssam 	if ((fd = open(cp, 2)) < 0) {
355*11367Ssam 		printf("Known devices are: ");
356*11367Ssam 		for (dp = devsw; dp->dv_name; dp++)
357*11367Ssam 			printf("%s ",dp->dv_name);
358*11367Ssam 		printf("\n");
359*11367Ssam 		goto top;
360*11367Ssam 	}
361*11367Ssam 	printf("Formatting drive %d on %c%c%d ",
362*11367Ssam 		iob[fd - 3].i_unit % 8, cp[0], cp[1], iob[fd - 3].i_unit / 8);
363*11367Ssam 	printf("will destroy everything on the disk, ");
364*11367Ssam 	cp = prompt("verify (yes/no)? ");
365*11367Ssam 	while (*cp != 'y' && *cp != 'n')
366*11367Ssam 		cp = prompt("Huh, yes or no? ");
367*11367Ssam 	if (*cp == 'y')
368*11367Ssam 		return (fd);
369*11367Ssam 	goto top;
370*11367Ssam }
371*11367Ssam 
372*11367Ssam char *
373*11367Ssam prompt(msg)
374*11367Ssam 	char *msg;
375*11367Ssam {
376*11367Ssam 	static char buf[132];
377*11367Ssam 
378*11367Ssam 	printf("%s", msg);
379*11367Ssam 	gets(buf);
380*11367Ssam 	return (buf);
381*11367Ssam }
382