1*17426Skarels /* format.c 6.4 84/11/27 */ 211367Ssam 315051Skarels 411367Ssam /* 511367Ssam * Standalone program to do media checking 611367Ssam * and record bad block information on any 715009Skarels * disk with the appropriate driver and RM03-style headers. 811367Ssam */ 911367Ssam #include "../h/param.h" 1011367Ssam #include "../h/fs.h" 1111367Ssam #include "../h/inode.h" 1211367Ssam #include "../h/dkbad.h" 1311367Ssam #include "../h/vmmac.h" 1411367Ssam 1511367Ssam #include "saio.h" 1611367Ssam #include "savax.h" 1711367Ssam 1811367Ssam #define MAXBADDESC 126 /* size of bad block table */ 1911367Ssam #define CHUNK 48 /* max # of sectors/io operation */ 2011367Ssam #define SECTSIZ 512 /* standard sector size */ 2111367Ssam #define HDRSIZ 4 /* number of bytes in sector header */ 2211367Ssam 2311367Ssam #define SSERR 0 2411367Ssam #define BSERR 1 2511367Ssam 2611367Ssam #define SSDEV ((ioctl(iob[fd-3], SAIOSSDEV, (char *)0) == 0)) 2711367Ssam 2811367Ssam struct sector { 2911367Ssam u_short header1; 3011367Ssam u_short header2; 3111367Ssam char buf[SECTSIZ]; 3211367Ssam }; 3311367Ssam 3411367Ssam struct dkbad dkbad; /* bad sector table */ 3511367Ssam struct dkbad sstab; /* skip sector table */ 3611367Ssam 3711367Ssam #define NERRORS 6 3811371Ssam static char * 3911371Ssam errornames[NERRORS] = { 4015009Skarels #define FE_BSE 0 4115009Skarels "Bad sector", 4215009Skarels #define FE_WCE 1 4311367Ssam "Write check", 4411367Ssam #define FE_ECC 2 4511367Ssam "ECC", 4611367Ssam #define FE_HARD 3 4711367Ssam "Other hard", 4811367Ssam #define FE_TOTAL 4 4911367Ssam "Total", 5011367Ssam #define FE_SSE 5 5111367Ssam "Skip sector", 5211367Ssam }; 5311367Ssam 5411367Ssam int errors[NERRORS]; /* histogram of errors */ 5511371Ssam int pattern; 5611367Ssam 5715051Skarels /* 5815051Skarels * Purdue/EE severe burnin patterns. 5915051Skarels */ 6015051Skarels unsigned short ppat[] = { 61*17426Skarels 0xf00f, 0xec6d, 0031463,0070707,0133333,0155555,0161616,0143434, 6215051Skarels 0107070,0016161,0034343,0044444,0022222,0111111,0125252, 052525, 6315051Skarels 0125252,0125252,0125252,0125252,0125252,0125252,0125252,0125252, 6415051Skarels #ifndef SHORTPASS 6515051Skarels 0125252,0125252,0125252,0125252,0125252,0125252,0125252,0125252, 6615051Skarels 052525, 052525, 052525, 052525, 052525, 052525, 052525, 052525, 6715051Skarels #endif 6815051Skarels 052525, 052525, 052525, 052525, 052525, 052525, 052525, 052525 6915051Skarels }; 7015051Skarels 7115051Skarels #define NPT (sizeof (ppat) / sizeof (short)) 72*17426Skarels int maxpass, npat; /* subscript to ppat[] */ 7315051Skarels int severe; /* nz if running "severe" burnin */ 7415051Skarels int nbads; /* subscript for bads */ 7515051Skarels long bads[MAXBADDESC]; /* Bad blocks accumulated */ 7615051Skarels 7711367Ssam char *malloc(); 7815051Skarels int qcompar(); 7911367Ssam char *prompt(); 8011367Ssam extern int end; 8111367Ssam 8211367Ssam main() 8311367Ssam { 8411367Ssam register int sector, sn; 8515051Skarels int lastsector, tracksize, rtracksize; 8611367Ssam int unit, fd, resid, i, trk, cyl, debug; 8711367Ssam struct st st; 8811367Ssam struct sector *bp, *cbp; 8915051Skarels char *rbp, *rcbp; 90*17426Skarels int pass; 9111367Ssam char *cp; 9211367Ssam 9311367Ssam printf("Disk format/check utility\n\n"); 9411367Ssam 9511367Ssam again: 9615051Skarels nbads = 0; 9715051Skarels cp = prompt("Enable debugging (0=none, 1=bse, 2=ecc, 3=bse+ecc)? "); 9811367Ssam debug = atoi(cp); 9911367Ssam if (debug < 0) 10011367Ssam debug = 0; 10111367Ssam for (i = 0; i < NERRORS; i++) 10211367Ssam errors[i] = 0; 10311367Ssam fd = getdevice(); 10411367Ssam ioctl(fd, SAIODEVDATA, &st); 10511367Ssam printf("Device data: #cylinders=%d, #tracks=%d, #sectors=%d\n", 10611367Ssam st.ncyl, st.ntrak, st.nsect); 10711371Ssam if (getpattern()) 10811367Ssam goto again; 10911367Ssam printf("Start formatting...make sure the drive is online\n"); 11015051Skarels if (severe) 11115051Skarels ioctl(fd, SAIOSEVRE, (char *) 0); 11211367Ssam ioctl(fd, SAIONOBAD, (char *)0); 11311367Ssam ioctl(fd, SAIOECCLIM, (char *)0); 11411367Ssam ioctl(fd, SAIODEBUG, (char *)debug); 11511367Ssam if (SSDEV) { 11615051Skarels if (severe) { 11715051Skarels printf("Severe burnin doesn't work with RM80 yet\n"); 11815051Skarels exit(1); 11915051Skarels } 12011367Ssam ioctl(fd, SAIOSSI, (char *)0); /* set skip sector inhibit */ 12111367Ssam st.nsect++; 12211367Ssam st.nspc += st.ntrak; 12311367Ssam } 12411367Ssam tracksize = sizeof (struct sector) * st.nsect; 12515051Skarels rtracksize = SECTSIZ * st.nsect; 12611367Ssam bp = (struct sector *)malloc(tracksize); 12715051Skarels rbp = malloc(rtracksize); 128*17426Skarels pass = 0; 129*17426Skarels npat = 0; 130*17426Skarels more: 131*17426Skarels for (; pass < maxpass; pass++) { 13215051Skarels if (severe) 13315051Skarels printf("Begin pass %d\n", pass); 13415051Skarels bufinit(bp, tracksize); 13515051Skarels if (severe) 13615051Skarels npat++; 13711367Ssam /* 13815051Skarels * Begin check, for each track, 13911367Ssam * 14015051Skarels * 1) Write header and test pattern. 14115051Skarels * 2) Read data. Hardware checks header and data ECC. 142*17426Skarels * Read data (esp on Eagles) is much faster than write check. 14311367Ssam */ 14415051Skarels lastsector = st.nspc * st.ncyl; 14515051Skarels for (sector = 0; sector < lastsector; sector += st.nsect) { 14615051Skarels cyl = sector / st.nspc; 14715051Skarels trk = (sector % st.nspc) / st.nsect; 14815051Skarels for (i = 0; i < st.nsect; i++) { 14915051Skarels bp[i].header1 = 15015051Skarels (u_short) cyl | HDR1_FMT22 | HDR1_OKSCT; 15115051Skarels bp[i].header2 = ((u_short)trk << 8) + i; 15215051Skarels } 15315051Skarels if (sector && (sector % (st.nspc * 100)) == 0) 15415051Skarels printf("cylinder %d\n", cyl); 15515051Skarels /* 15615051Skarels * Try and write the headers and data patterns into 15715051Skarels * each sector in the track. Continue until such 15815051Skarels * we're done, or until there's less than a sector's 15915051Skarels * worth of data to transfer. 16015051Skarels * 16115051Skarels * The lseek call is necessary because of 16215051Skarels * the odd sector size (516 bytes) 16315051Skarels */ 16415051Skarels for (resid = tracksize, cbp = bp, sn = sector;;) { 16515051Skarels int cc; 16611367Ssam 16715051Skarels lseek(fd, sn * SECTSIZ, 0); 16815051Skarels ioctl(fd, SAIOHDR, (char *)0); 16915051Skarels cc = write(fd, cbp, resid); 17015051Skarels if (cc == resid) 17115051Skarels break; 17215051Skarels /* 17315051Skarels * Don't record errors during write, 17415051Skarels * all errors will be found during 17515051Skarels * writecheck performed below. 17615051Skarels */ 17715051Skarels sn = iob[fd - 3].i_errblk; 17815051Skarels cbp += sn - sector; 17915051Skarels resid -= (sn - sector) * sizeof (struct sector); 18015051Skarels if (resid < sizeof (struct sector)) 18115051Skarels break; 18215051Skarels } 18311367Ssam /* 18415051Skarels * Read test patterns. 18515051Skarels * Retry remainder of track on error until 18615051Skarels * we're done, or until there's less than a 18715051Skarels * sector to verify. 18811367Ssam */ 18915051Skarels for (resid = rtracksize, rcbp = rbp, sn = sector;;) { 19015051Skarels int cc; 19111367Ssam 19215051Skarels lseek(fd, sn * SECTSIZ, 0); 19315051Skarels cc = read(fd, rcbp, resid); 19415051Skarels if (cc == resid) 19515051Skarels break; 19615051Skarels sn = iob[fd-3].i_errblk; 19715051Skarels printf("sector %d, read error\n", sn); 19815051Skarels if (recorderror(fd, sn, &st) < 0 && pass > 0) 19915051Skarels goto out; 20015051Skarels /* advance past bad sector */ 20115051Skarels sn++; 20215051Skarels rcbp += sn - sector; 20315051Skarels resid -= ((sn - sector) * SECTSIZ); 20415051Skarels if (resid < SECTSIZ) 20515051Skarels break; 20615051Skarels } 20711367Ssam } 20811367Ssam } 20911367Ssam /* 21011367Ssam * Checking finished. 21111367Ssam */ 21215051Skarels out: 213*17426Skarels if (errors[FE_TOTAL] || errors[FE_SSE]) { 214*17426Skarels printf("Errors:\n"); 215*17426Skarels for (i = 0; i < NERRORS; i++) 216*17426Skarels printf("%s: %d\n", errornames[i], errors[i]); 217*17426Skarels printf("Total of %d hard errors found\n", 218*17426Skarels errors[FE_TOTAL] + errors[FE_SSE]); 219*17426Skarels } 220*17426Skarels if (severe && maxpass < NPT) { 221*17426Skarels cp = prompt("More passes? (0 or number) "); 222*17426Skarels maxpass = atoi(cp); 223*17426Skarels if (maxpass > 0) { 224*17426Skarels maxpass += pass; 225*17426Skarels goto more; 226*17426Skarels } 227*17426Skarels } 22815051Skarels if (severe && nbads) { 22915051Skarels /* 23015051Skarels * Sort bads and insert in bad block table. 23115051Skarels */ 23215051Skarels qsort(bads, nbads, sizeof (long), qcompar); 23315051Skarels severe = 0; 234*17426Skarels errno = 0; 235*17426Skarels for (i = 0; i < nbads; i++) 23615051Skarels recorderror(fd, bads[i], &st); 23715051Skarels severe++; 23815051Skarels } 23911367Ssam if (errors[FE_TOTAL] || errors[FE_SSE]) { 24011367Ssam /* change the headers of all the bad sectors */ 24111367Ssam writebb(fd, errors[FE_SSE], &sstab, &st, SSERR); 24211367Ssam writebb(fd, errors[FE_TOTAL], &dkbad, &st, BSERR); 24311367Ssam } 24411367Ssam while (errors[FE_TOTAL] < MAXBADDESC) { 24511367Ssam int i = errors[FE_TOTAL]++; 24611367Ssam 24711367Ssam dkbad.bt_bad[i].bt_cyl = -1; 24811367Ssam dkbad.bt_bad[i].bt_trksec = -1; 24911367Ssam } 25011367Ssam printf("\nWriting bad sector table at sector #%d\n", 25111367Ssam st.ncyl * st.nspc - st.nsect); 25211367Ssam /* place on disk */ 25311367Ssam for (i = 0; i < 10; i += 2) { 25411367Ssam lseek(fd, SECTSIZ * (st.ncyl * st.nspc - st.nsect + i), 0); 25511367Ssam write(fd, &dkbad, sizeof (dkbad)); 25611367Ssam } 25711367Ssam printf("Done\n"); 25811367Ssam ioctl(fd,SAIONOSSI,(char *)0); 25911367Ssam close(fd); 26011367Ssam #ifndef JUSTEXIT 26111367Ssam goto again; 26211367Ssam #endif 26311367Ssam } 26411367Ssam 26515051Skarels qcompar(l1, l2) 26615051Skarels register long *l1, *l2; 26715051Skarels { 26815051Skarels if (*l1 < *l2) 26915051Skarels return(-1); 27015051Skarels if (*l1 == *l2) 27115051Skarels return(0); 27215051Skarels return(1); 27315051Skarels } 27415051Skarels 27511367Ssam /* 27611367Ssam * Write out the bad blocks. 27711367Ssam */ 27811367Ssam writebb(fd, nsects, dbad, st, sw) 27911367Ssam int nsects, fd; 28011367Ssam struct dkbad *dbad; 28111367Ssam register struct st *st; 28211367Ssam { 28311367Ssam struct sector bb_buf; /* buffer for one sector plus 4 byte header */ 28411367Ssam register int i; 28511367Ssam int bn, j; 28611367Ssam struct bt_bad *btp; 28711367Ssam 28811367Ssam for (i = 0; i < nsects; i++) { 28911367Ssam btp = &dbad->bt_bad[i]; 29011367Ssam if (sw == BSERR) { 29111367Ssam bb_buf.header1 = HDR1_FMT22|btp->bt_cyl; 29211367Ssam if (SSDEV) 29311367Ssam bb_buf.header1 |= HDR1_SSF; 29411367Ssam } else 29511367Ssam bb_buf.header1 = 29611367Ssam btp->bt_cyl | HDR1_FMT22 | HDR1_SSF | HDR1_OKSCT; 29711367Ssam bb_buf.header2 = btp->bt_trksec; 29811367Ssam bn = st->nspc * btp->bt_cyl + 29911367Ssam st->nsect * (btp->bt_trksec >> 8) + 30015009Skarels (btp->bt_trksec & 0xff); 30111367Ssam lseek(fd, bn * SECTSIZ, 0); 30211367Ssam ioctl(fd, SAIOHDR, (char *)0); 30311367Ssam write(fd, &bb_buf, sizeof (bb_buf)); 30411367Ssam if (!SSDEV) 30511367Ssam continue; 30611367Ssam /* 30711367Ssam * If skip sector, mark all remaining 30811367Ssam * sectors on the track. 30911367Ssam */ 31015009Skarels for (j = (btp->bt_trksec & 0xff) + 1; j < st->nsect; j++) { 31111367Ssam bb_buf.header1 = j | HDR1_FMT22 | HDR1_SSF; 31211367Ssam ioctl(fd, SAIOHDR, (char *)0); 31311367Ssam write(fd, &bb_buf, sizeof (bb_buf)); 31411367Ssam } 31511367Ssam } 31611367Ssam } 31711367Ssam 31811367Ssam /* 31911367Ssam * Record an error, and if there's room, put 32011367Ssam * it in the appropriate bad sector table. 32115051Skarels * 32215051Skarels * If severe burnin store block in a list after making sure 32315051Skarels * we have not already found it on a prev pass. 32411367Ssam */ 32511367Ssam recorderror(fd, bn, st) 32611367Ssam int fd, bn; 32711367Ssam register struct st *st; 32811367Ssam { 32911367Ssam int cn, tn, sn, strk; 33015051Skarels register i; 33111367Ssam 33215051Skarels 33315051Skarels if (severe) { 33415051Skarels for (i = 0; i < nbads; i++) 33515051Skarels if (bads[i] == bn) 33615051Skarels return(0); /* bn already flagged */ 33715051Skarels if (nbads >= MAXBADDESC) { 33815051Skarels printf("Bad sector table full, burnin terminating\n"); 33915051Skarels return(-1); 34015051Skarels } 34115051Skarels bads[nbads++] = bn; 342*17426Skarels if (errno < EBSE || errno > EHER) 343*17426Skarels return(0); 344*17426Skarels errno -= EBSE; 345*17426Skarels errors[errno]++; 34615051Skarels return(0); 34715051Skarels } 348*17426Skarels if (errno >= EBSE && errno <= EHER) { 349*17426Skarels if (errors[FE_TOTAL] >= MAXBADDESC) { 350*17426Skarels printf("Too many bad sectors\n"); 351*17426Skarels return(-1); 352*17426Skarels } 353*17426Skarels if (errors[FE_SSE] >= MAXBADDESC) { 354*17426Skarels printf("Too many skip sector errors\n"); 355*17426Skarels return(-1); 356*17426Skarels } 357*17426Skarels errno -= EBSE; 358*17426Skarels errors[errno]++; 35911367Ssam } 36011367Ssam cn = bn / st->nspc; 36111367Ssam sn = bn % st->nspc; 36211367Ssam tn = sn / st->nsect; 36311367Ssam sn %= st->nsect; 36411367Ssam if (SSDEV) { /* if drive has skip sector capability */ 36511367Ssam int ss = errors[FE_SSE]++; 36611367Ssam 36711367Ssam if (ss) 36811367Ssam strk = sstab.bt_bad[ss - 1].bt_trksec >> 8; 36911367Ssam else 37011367Ssam strk = -1; 37111367Ssam if (tn != strk) { /* only one skip sector/track */ 37211367Ssam sstab.bt_bad[ss].bt_cyl = cn; 37311367Ssam sstab.bt_bad[ss].bt_trksec = (tn<<8) + sn; 37411367Ssam return; 37511367Ssam } 37611367Ssam cn = -cn; 37711367Ssam } 37811367Ssam /* record the bad sector address and continue */ 37915009Skarels dkbad.bt_bad[errors[FE_TOTAL]].bt_cyl = cn; 38011367Ssam dkbad.bt_bad[errors[FE_TOTAL]++].bt_trksec = (tn << 8) + sn; 38115051Skarels return(0); 38211367Ssam } 38311367Ssam 38411367Ssam /* 38511367Ssam * Allocate memory on a page-aligned address. 38611367Ssam * Round allocated chunk to a page multiple to 38711367Ssam * ease next request. 38811367Ssam */ 38911367Ssam char * 39011367Ssam malloc(size) 39111367Ssam int size; 39211367Ssam { 39311367Ssam char *result; 39411367Ssam static caddr_t last = 0; 39511367Ssam 39611367Ssam if (last == 0) 39711367Ssam last = (caddr_t)(((int)&end + 511) & ~0x1ff); 39811367Ssam size = (size + 511) & ~0x1ff; 39911367Ssam result = (char *)last; 40011367Ssam last += size; 40111367Ssam return (result); 40211367Ssam } 40311367Ssam 40411367Ssam /* 40511367Ssam * Prompt and verify a device name from the user. 40611367Ssam */ 40711367Ssam getdevice() 40811367Ssam { 40911367Ssam register char *cp; 41011367Ssam register struct devsw *dp; 41111367Ssam int fd; 41211367Ssam 41311367Ssam top: 41411367Ssam cp = prompt("Device to format? "); 41511367Ssam if ((fd = open(cp, 2)) < 0) { 41611367Ssam printf("Known devices are: "); 41711367Ssam for (dp = devsw; dp->dv_name; dp++) 41811367Ssam printf("%s ",dp->dv_name); 41911367Ssam printf("\n"); 42011367Ssam goto top; 42111367Ssam } 42215051Skarels printf("Formatting drive %c%c%d on adaptor %d: ", 42315051Skarels cp[0], cp[1], iob[fd - 3].i_unit % 8, iob[fd - 3].i_unit / 8); 42411367Ssam cp = prompt("verify (yes/no)? "); 42511367Ssam while (*cp != 'y' && *cp != 'n') 42611367Ssam cp = prompt("Huh, yes or no? "); 42711367Ssam if (*cp == 'y') 42811367Ssam return (fd); 42911367Ssam goto top; 43011367Ssam } 43111367Ssam 43211371Ssam static struct pattern { 43311371Ssam long pa_value; 43411371Ssam char *pa_name; 43511371Ssam } pat[] = { 43611371Ssam { 0xf00ff00f, "RH750 worst case" }, 43711371Ssam { 0xec6dec6d, "media worst case" }, 43811371Ssam { 0xa5a5a5a5, "alternate 1's and 0's" }, 439*17426Skarels { 0xFFFFFFFF, "Severe burnin (up to 48 passes)" }, 44011371Ssam { 0, 0 }, 44111371Ssam }; 44211371Ssam 44311371Ssam getpattern() 44411371Ssam { 44511371Ssam register struct pattern *p; 44611371Ssam int npatterns; 44711371Ssam char *cp; 44811371Ssam 44911371Ssam printf("Available test patterns are:\n"); 45011371Ssam for (p = pat; p->pa_value; p++) 45111371Ssam printf("\t%d - (%x) %s\n", (p - pat) + 1, 45211371Ssam p->pa_value & 0xffff, p->pa_name); 45311371Ssam npatterns = p - pat; 45411371Ssam cp = prompt("Pattern (one of the above, other to restart)? "); 45511371Ssam pattern = atoi(cp) - 1; 456*17426Skarels if (pattern < 0 || pattern >= npatterns) 457*17426Skarels return(1); 45815051Skarels severe = 0; 459*17426Skarels maxpass = 1; 460*17426Skarels if (pat[pattern].pa_value == -1) { 46115051Skarels severe = 1; 462*17426Skarels cp = prompt("How many passes (up to 48)? "); 463*17426Skarels maxpass = atoi(cp); 464*17426Skarels if (maxpass > NPT) 465*17426Skarels maxpass = NPT; 466*17426Skarels } 467*17426Skarels return (0); 46811371Ssam } 46911371Ssam 47011371Ssam struct xsect { 47111371Ssam u_short hd1; 47211371Ssam u_short hd2; 47311371Ssam long buf[128]; 47411371Ssam }; 47511371Ssam 47611371Ssam /* 47711371Ssam * Initialize the buffer with the requested pattern. 47811371Ssam */ 47911371Ssam bufinit(bp, size) 48011371Ssam register struct xsect *bp; 48111371Ssam int size; 48211371Ssam { 48311371Ssam register struct pattern *pptr; 48411371Ssam register long *pp, *last; 48511371Ssam register struct xsect *lastbuf; 48615051Skarels int patt; 48711371Ssam 48811371Ssam size /= sizeof (struct sector); 48911371Ssam lastbuf = bp + size; 49015051Skarels if (severe) { 49115051Skarels patt = ppat[npat] | ((long)ppat[npat] << 16); 49215051Skarels printf("Write pattern 0x%x\n", patt&0xffff); 49315051Skarels } else { 49415051Skarels pptr = &pat[pattern]; 49515051Skarels patt = pptr->pa_value; 49615051Skarels } 49711371Ssam while (bp < lastbuf) { 49811371Ssam last = &bp->buf[128]; 49911371Ssam for (pp = bp->buf; pp < last; pp++) 50015051Skarels *pp = patt; 50111371Ssam bp++; 50211371Ssam } 50311371Ssam } 50411371Ssam 50511367Ssam char * 50611367Ssam prompt(msg) 50711367Ssam char *msg; 50811367Ssam { 50911367Ssam static char buf[132]; 51011367Ssam 51111367Ssam printf("%s", msg); 51211367Ssam gets(buf); 51311367Ssam return (buf); 51411367Ssam } 515