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