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