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: }