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