|
|
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.