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