|
|
1.1 root 1: /*
2: * Copyright (c) 1980, 1986 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: char copyright[] =
9: "@(#) Copyright (c) 1980, 1986 Regents of the University of California.\n\
10: All rights reserved.\n";
11: #endif not lint
12:
13: #ifndef lint
14: static char sccsid[] = "@(#)format.c 7.1 (Berkeley) 6/5/86";
15: #endif not lint
16:
17:
18: /*
19: * Standalone program to do media checking
20: * and record bad block information on any
21: * disk with the appropriate driver and RM03-style headers.
22: * TODO:
23: * add new bad sectors to bad-sector table when formatting by track
24: * (rearranging replacements ala bad144 -a)
25: * multi-pass format for disks with skip-sector capability
26: */
27: #include "../h/param.h"
28: #include "../h/fs.h"
29: #include "../h/inode.h"
30: #include "../h/dkbad.h"
31: #include "../h/vmmac.h"
32:
33: #include "saio.h"
34: #include "savax.h"
35:
36: #define MAXBADDESC 126 /* size of bad block table */
37: #define CHUNK 48 /* max # of sectors/io operation */
38: #define SECTSIZ 512 /* standard sector size */
39: #define HDRSIZ 4 /* number of bytes in sector header */
40:
41: #define SSERR 0
42: #define BSERR 1
43:
44: #define SSDEV(fd) (ioctl((fd), SAIOSSDEV, (char *)0) == 0)
45: #define MAXECCBITS 3
46:
47: struct sector {
48: u_short header1;
49: u_short header2;
50: char buf[SECTSIZ];
51: };
52:
53: struct dkbad dkbad; /* bad sector table */
54: struct dkbad oldbad; /* old bad sector table */
55: struct dkbad sstab; /* skip sector table */
56:
57: #define NERRORS 6
58: static char *
59: errornames[NERRORS] = {
60: #define FE_BSE 0
61: "Bad sector",
62: #define FE_WCE 1
63: "Write check",
64: #define FE_ECC 2
65: "Hard ECC",
66: #define FE_HARD 3
67: "Other hard",
68: #define FE_TOTAL 4
69: "Marked bad",
70: #define FE_SSE 5
71: "Skipped",
72: };
73:
74: int errors[NERRORS]; /* histogram of errors */
75: int pattern;
76: int maxeccbits;
77:
78: /*
79: * Purdue/EE severe burnin patterns.
80: */
81: unsigned short ppat[] = {
82: 0xf00f, 0xec6d, 0031463,0070707,0133333,0155555,0161616,0143434,
83: 0107070,0016161,0034343,0044444,0022222,0111111,0125252, 052525,
84: 0125252,0125252,0125252,0125252,0125252,0125252,0125252,0125252,
85: #ifndef SHORTPASS
86: 0125252,0125252,0125252,0125252,0125252,0125252,0125252,0125252,
87: 052525, 052525, 052525, 052525, 052525, 052525, 052525, 052525,
88: #endif
89: 052525, 052525, 052525, 052525, 052525, 052525, 052525, 052525
90: };
91:
92: #define NPT (sizeof (ppat) / sizeof (short))
93: int maxpass, npat; /* subscript to ppat[] */
94: int severe; /* nz if running "severe" burnin */
95: int ssdev; /* device supports skip sectors */
96: int startcyl, endcyl, starttrack, endtrack;
97: int nbads; /* subscript for bads */
98: daddr_t bads[2*MAXBADDESC]; /* Bad blocks accumulated */
99:
100: char *malloc();
101: int qcompar();
102: char *prompt();
103: daddr_t badsn();
104: extern int end;
105:
106: main()
107: {
108: register int sector, sn;
109: int lastsector, tracksize, rtracksize;
110: int unit, fd, resid, i, trk, cyl, debug;
111: struct st st;
112: struct sector *bp, *cbp;
113: char *rbp, *rcbp;
114: int pass;
115: char *cp;
116:
117: printf("Disk format/check utility\n\n");
118:
119: again:
120: nbads = 0;
121: cp = prompt("Enable debugging (0=none, 1=bse, 2=ecc, 3=bse+ecc)? ");
122: debug = atoi(cp);
123: if (debug < 0)
124: debug = 0;
125: for (i = 0; i < NERRORS; i++)
126: errors[i] = 0;
127: fd = getdevice();
128: ioctl(fd, SAIODEVDATA, &st);
129: printf("Device data: #cylinders=%d, #tracks=%d, #sectors=%d\n",
130: st.ncyl, st.ntrak, st.nsect);
131: ssdev = SSDEV(fd);
132: if (ssdev) {
133: ioctl(fd, SAIOSSI, (char *)0); /* set skip sector inhibit */
134: st.nsect++;
135: st.nspc += st.ntrak;
136: printf("(not counting skip-sector replacement)\n");
137: }
138: getrange(&st);
139: if (getpattern())
140: goto again;
141: printf("Start formatting...make sure the drive is online\n");
142: ioctl(fd, SAIONOBAD, (char *)0);
143: ioctl(fd, SAIORETRIES, (char *)0);
144: ioctl(fd, SAIOECCLIM, (char *)maxeccbits);
145: ioctl(fd, SAIODEBUG, (char *)debug);
146: tracksize = sizeof (struct sector) * st.nsect;
147: rtracksize = SECTSIZ * st.nsect;
148: bp = (struct sector *)malloc(tracksize);
149: rbp = malloc(rtracksize);
150: pass = 0;
151: npat = 0;
152: more:
153: for (; pass < maxpass; pass++) {
154: if (severe)
155: printf("Begin pass %d\n", pass);
156: bufinit(bp, tracksize);
157: if (severe)
158: npat++;
159: /*
160: * Begin check, for each track,
161: *
162: * 1) Write header and test pattern.
163: * 2) Read data. Hardware checks header and data ECC.
164: * Read data (esp on Eagles) is much faster than write check.
165: */
166: sector = ((startcyl * st.ntrak) + starttrack) * st.nsect;
167: lastsector = ((endcyl * st.ntrak) + endtrack) * st.nsect
168: + st.nsect;
169: for ( ; sector < lastsector; sector += st.nsect) {
170: cyl = sector / st.nspc;
171: trk = (sector % st.nspc) / st.nsect;
172: for (i = 0; i < st.nsect; i++) {
173: bp[i].header1 =
174: (u_short) cyl | HDR1_FMT22 | HDR1_OKSCT;
175: bp[i].header2 = ((u_short)trk << 8) + i;
176: }
177: if (sector && (sector % (st.nspc * 100)) == 0)
178: printf("cylinder %d\n", cyl);
179: /*
180: * Try and write the headers and data patterns into
181: * each sector in the track. Continue until such
182: * we're done, or until there's less than a sector's
183: * worth of data to transfer.
184: *
185: * The lseek call is necessary because of
186: * the odd sector size (516 bytes)
187: */
188: for (resid = tracksize, cbp = bp, sn = sector;;) {
189: int cc;
190:
191: lseek(fd, sn * SECTSIZ, 0);
192: ioctl(fd, SAIOHDR, (char *)0);
193: cc = write(fd, cbp, resid);
194: if (cc == resid)
195: break;
196: /*
197: * Don't record errors during write,
198: * all errors will be found during
199: * check performed below.
200: */
201: sn = iob[fd - 3].i_errblk;
202: cbp += sn - sector;
203: resid -= (sn - sector) * sizeof (struct sector);
204: if (resid < sizeof (struct sector))
205: break;
206: }
207: /*
208: * Read test patterns.
209: * Retry remainder of track on error until
210: * we're done, or until there's less than a
211: * sector to verify.
212: */
213: for (resid = rtracksize, rcbp = rbp, sn = sector;;) {
214: int cc, rsn;
215:
216: lseek(fd, sn * SECTSIZ, 0);
217: cc = read(fd, rcbp, resid);
218: if (cc == resid)
219: break;
220: sn = iob[fd-3].i_errblk;
221: if (ssdev) {
222: rsn = sn - (sn / st.nsect);
223: printf("data ");
224: } else
225: rsn = sn;
226: printf("sector %d, read error\n\n", rsn);
227: if (recorderror(fd, sn, &st) < 0 && pass > 0)
228: goto out;
229: /* advance past bad sector */
230: sn++;
231: resid = rtracksize - ((sn - sector) * SECTSIZ);
232: rcbp = rbp + ((sn - sector) * SECTSIZ);
233: if (resid < SECTSIZ)
234: break;
235: }
236: }
237: }
238: /*
239: * Checking finished.
240: */
241: out:
242: if (severe && maxpass < NPT) {
243: cp = prompt("More passes? (0 or number) ");
244: maxpass = atoi(cp);
245: if (maxpass > 0) {
246: maxpass += pass;
247: goto more;
248: }
249: }
250: if (severe && nbads) {
251: /*
252: * Sort bads and insert in bad block table.
253: */
254: qsort(bads, nbads, sizeof (daddr_t), qcompar);
255: severe = 0;
256: errno = 0;
257: for (i = 0; i < nbads; i++)
258: recorderror(fd, bads[i], &st);
259: severe++;
260: }
261: if (errors[FE_TOTAL] || errors[FE_SSE]) {
262: /* change the headers of all the bad sectors */
263: writebb(fd, errors[FE_SSE], &sstab, &st, SSERR);
264: writebb(fd, errors[FE_TOTAL], &dkbad, &st, BSERR);
265: }
266: if (errors[FE_TOTAL] || errors[FE_SSE]) {
267: printf("Errors:\n");
268: for (i = 0; i < NERRORS; i++)
269: printf("%s: %d\n", errornames[i], errors[i]);
270: printf("Total of %d hard errors revectored\n",
271: errors[FE_TOTAL] + errors[FE_SSE]);
272: }
273: if (endcyl == st.ncyl - 1 &&
274: (startcyl < st.ncyl - 1 || starttrack == 0)) {
275: while (errors[FE_TOTAL] < MAXBADDESC) {
276: int i = errors[FE_TOTAL]++;
277:
278: dkbad.bt_bad[i].bt_cyl = -1;
279: dkbad.bt_bad[i].bt_trksec = -1;
280: }
281: printf("\nWriting bad sector table at sector #%d\n",
282: st.ncyl * st.nspc - st.nsect);
283: /* place on disk */
284: for (i = 0; i < 10 && i < st.nsect; i += 2) {
285: lseek(fd, SECTSIZ * (st.ncyl * st.nspc - st.nsect + i), 0);
286: write(fd, &dkbad, sizeof (dkbad));
287: }
288: } else if (errors[FE_TOTAL]) {
289: struct bt_bad *bt;
290:
291: printf("New bad sectors (not added to table):\n");
292: bt = dkbad.bt_bad;
293: for (i = 0; i < errors[FE_TOTAL]; i++) {
294: printf("bn %d (cn=%d, tn=%d, sn=%d)\n", badsn(bt, &st),
295: bt->bt_cyl, bt->bt_trksec>>8, bt->bt_trksec&0xff);
296: bt++;
297: }
298: }
299: printf("Done\n");
300: ioctl(fd,SAIONOSSI,(char *)0);
301: close(fd);
302: #ifndef JUSTEXIT
303: goto again;
304: #endif
305: }
306:
307: qcompar(l1, l2)
308: register daddr_t *l1, *l2;
309: {
310: if (*l1 < *l2)
311: return(-1);
312: if (*l1 == *l2)
313: return(0);
314: return(1);
315: }
316:
317: daddr_t
318: badsn(bt, st)
319: register struct bt_bad *bt;
320: register struct st *st;
321: {
322:
323: if (ssdev)
324: return ((bt->bt_cyl * st->ntrak + (bt->bt_trksec>>8)) *
325: (st->nsect - 1) + (bt->bt_trksec&0xff)) - 1;
326: else
327: return ((bt->bt_cyl*st->ntrak + (bt->bt_trksec>>8)) * st->nsect
328: + (bt->bt_trksec&0xff));
329: }
330:
331: /*
332: * Mark the bad/skipped sectors.
333: * Bad sectors on skip-sector devices are assumed to be skipped also,
334: * and must be done after the (earlier) first skipped sector.
335: */
336: writebb(fd, nsects, dbad, st, sw)
337: int nsects, fd;
338: struct dkbad *dbad;
339: register struct st *st;
340: {
341: struct sector bb_buf; /* buffer for one sector plus 4 byte header */
342: register int i;
343: int bn, j;
344: struct bt_bad *btp;
345:
346: for (i = 0; i < nsects; i++) {
347: btp = &dbad->bt_bad[i];
348: if (sw == BSERR) {
349: bb_buf.header1 = HDR1_FMT22|btp->bt_cyl;
350: if (ssdev)
351: bb_buf.header1 |= HDR1_SSF;
352: } else
353: bb_buf.header1 =
354: btp->bt_cyl | HDR1_FMT22 | HDR1_SSF | HDR1_OKSCT;
355: bb_buf.header2 = btp->bt_trksec;
356: bn = st->nspc * btp->bt_cyl +
357: st->nsect * (btp->bt_trksec >> 8) +
358: (btp->bt_trksec & 0xff);
359: lseek(fd, bn * SECTSIZ, 0);
360: ioctl(fd, SAIOHDR, (char *)0);
361: write(fd, &bb_buf, sizeof (bb_buf));
362: /*
363: * If skip sector, mark all remaining
364: * sectors on the track.
365: */
366: if (sw == SSERR) {
367: for (j = (btp->bt_trksec & 0xff) + 1, bn++;
368: j < st->nsect; j++, bn++) {
369: bb_buf.header2 = j | (btp->bt_trksec & 0xff00);
370: lseek(fd, bn * SECTSIZ, 0);
371: ioctl(fd, SAIOHDR, (char *)0);
372: write(fd, &bb_buf, sizeof (bb_buf));
373: }
374: }
375: }
376: }
377:
378: /*
379: * Record an error, and if there's room, put
380: * it in the appropriate bad sector table.
381: *
382: * If severe burnin store block in a list after making sure
383: * we have not already found it on a prev pass.
384: */
385: recorderror(fd, bn, st)
386: int fd, bn;
387: register struct st *st;
388: {
389: int cn, tn, sn;
390: register i;
391:
392:
393: if (severe) {
394: for (i = 0; i < nbads; i++)
395: if (bads[i] == bn)
396: return(0); /* bn already flagged */
397: if (nbads >= (ssdev ? 2 * MAXBADDESC : MAXBADDESC)) {
398: printf("Bad sector table full, format terminating\n");
399: return(-1);
400: }
401: bads[nbads++] = bn;
402: if (errno < EBSE || errno > EHER)
403: return(0);
404: errno -= EBSE;
405: errors[errno]++;
406: return(0);
407: }
408: if (errno >= EBSE && errno <= EHER) {
409: errno -= EBSE;
410: errors[errno]++;
411: }
412: cn = bn / st->nspc;
413: sn = bn % st->nspc;
414: tn = sn / st->nsect;
415: sn %= st->nsect;
416: if (ssdev) { /* if drive has skip sector capability */
417: int ss = errors[FE_SSE];
418:
419: if (errors[FE_SSE] >= MAXBADDESC) {
420: /* this is bogus, we don't maintain skip sector table */
421: printf("Too many skip sector errors\n");
422: return(-1);
423: }
424: /* only one skip sector/track */
425: if (ss == 0 ||
426: tn != (sstab.bt_bad[ss - 1].bt_trksec >> 8) ||
427: cn != sstab.bt_bad[ss - 1].bt_cyl) {
428: /*
429: * Don't bother with skipping the extra sector
430: * at the end of the track.
431: */
432: if (sn == st->nsect - 1)
433: return(0);
434: sstab.bt_bad[ss].bt_cyl = cn;
435: sstab.bt_bad[ss].bt_trksec = (tn<<8) + sn;
436: errors[FE_SSE]++;
437: return(0);
438: }
439: }
440: if (errors[FE_TOTAL] >= MAXBADDESC) {
441: printf("Too many bad sectors\n");
442: return(-1);
443: }
444: /* record the bad sector address and continue */
445: dkbad.bt_bad[errors[FE_TOTAL]].bt_cyl = cn;
446: dkbad.bt_bad[errors[FE_TOTAL]++].bt_trksec = (tn << 8) + sn;
447: return(0);
448: }
449:
450: /*
451: * Allocate memory on a page-aligned address.
452: * Round allocated chunk to a page multiple to
453: * ease next request.
454: */
455: char *
456: malloc(size)
457: int size;
458: {
459: char *result;
460: static caddr_t last = 0;
461:
462: if (last == 0)
463: last = (caddr_t)(((int)&end + 511) & ~0x1ff);
464: size = (size + 511) & ~0x1ff;
465: result = (char *)last;
466: last += size;
467: return (result);
468: }
469:
470: /*
471: * Prompt and verify a device name from the user.
472: */
473: getdevice()
474: {
475: register char *cp;
476: register struct devsw *dp;
477: int fd;
478:
479: top:
480: cp = prompt("Device to format? ");
481: if ((fd = open(cp, 2)) < 0) {
482: printf("Known devices are: ");
483: for (dp = devsw; dp->dv_name; dp++)
484: printf("%s ",dp->dv_name);
485: printf("\n");
486: goto top;
487: }
488: printf("Formatting drive %c%c%d on adaptor %d: ",
489: cp[0], cp[1], iob[fd - 3].i_unit % 8, iob[fd - 3].i_unit / 8);
490: cp = prompt("verify (yes/no)? ");
491: while (*cp != 'y' && *cp != 'n')
492: cp = prompt("Huh, yes or no? ");
493: if (*cp == 'y')
494: return (fd);
495: goto top;
496: }
497:
498: /*
499: * Find range of tracks to format.
500: */
501: getrange(st)
502: struct st *st;
503: {
504: startcyl = getnum("Starting cylinder", 0, st->ncyl - 1, 0);
505: starttrack = getnum("Starting track", 0, st->ntrak - 1, 0);
506: endcyl = getnum("Ending cylinder", 0, st->ncyl - 1, st->ncyl - 1);
507: endtrack = getnum("Ending track", 0, st->ntrak - 1, st->ntrak - 1);
508: }
509:
510: getnum(s, low, high, dflt)
511: {
512: char buf[132];
513: unsigned val;
514:
515: while (1) {
516: printf("%s (%d): ", s, dflt);
517: gets(buf);
518: if (buf[0] == 0)
519: return (dflt);
520: val = atoi(buf);
521: if (val >= low && val <= high)
522: return ((int)val);
523: printf("Value must be in range [%d,%d]\n", low, high);
524: }
525: }
526:
527: static struct pattern {
528: long pa_value;
529: char *pa_name;
530: } pat[] = {
531: { 0xf00ff00f, "RH750 worst case" },
532: { 0xec6dec6d, "media worst case" },
533: { 0xa5a5a5a5, "alternate 1's and 0's" },
534: { 0xFFFFFFFF, "Severe burnin (up to 48 passes)" },
535: { 0, 0 },
536: };
537:
538: getpattern()
539: {
540: register struct pattern *p;
541: int npatterns;
542: char *cp;
543:
544: printf("Available test patterns are:\n");
545: for (p = pat; p->pa_value; p++)
546: printf("\t%d - (%x) %s\n", (p - pat) + 1,
547: p->pa_value & 0xffff, p->pa_name);
548: npatterns = p - pat;
549: cp = prompt("Pattern (one of the above, other to restart)? ");
550: pattern = atoi(cp) - 1;
551: if (pattern < 0 || pattern >= npatterns)
552: return(1);
553: severe = 0;
554: maxpass = 1;
555: if (pat[pattern].pa_value == -1) {
556: severe = 1;
557: cp = prompt("How many passes (up to 48)? ");
558: maxpass = atoi(cp);
559: if (maxpass > NPT)
560: maxpass = NPT;
561: }
562: maxeccbits = getnum(
563: "Maximum number of bit errors to allow for soft ECC",
564: 0, 11, MAXECCBITS);
565: return (0);
566: }
567:
568: struct xsect {
569: u_short hd1;
570: u_short hd2;
571: long buf[128];
572: };
573:
574: /*
575: * Initialize the buffer with the requested pattern.
576: */
577: bufinit(bp, size)
578: register struct xsect *bp;
579: int size;
580: {
581: register struct pattern *pptr;
582: register long *pp, *last;
583: register struct xsect *lastbuf;
584: int patt;
585:
586: size /= sizeof (struct sector);
587: lastbuf = bp + size;
588: if (severe) {
589: patt = ppat[npat] | ((long)ppat[npat] << 16);
590: printf("Write pattern 0x%x\n", patt&0xffff);
591: } else {
592: pptr = &pat[pattern];
593: patt = pptr->pa_value;
594: }
595: while (bp < lastbuf) {
596: last = &bp->buf[128];
597: for (pp = bp->buf; pp < last; pp++)
598: *pp = patt;
599: bp++;
600: }
601: }
602:
603: char *
604: prompt(msg)
605: char *msg;
606: {
607: static char buf[132];
608:
609: printf("%s", msg);
610: gets(buf);
611: return (buf);
612: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.