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