1*15051Skarels /* format.c 6.3 83/09/23 */ 211367Ssam 3*15051Skarels 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 57*15051Skarels /* 58*15051Skarels * Purdue/EE severe burnin patterns. 59*15051Skarels */ 60*15051Skarels unsigned short ppat[] = { 61*15051Skarels 0031463,0070707,0133333,0155555,0161616,0143434, 62*15051Skarels 0107070,0016161,0034343,0044444,0022222,0111111,0125252, 052525, 63*15051Skarels 0125252,0125252,0125252,0125252,0125252,0125252,0125252,0125252, 64*15051Skarels #ifndef SHORTPASS 65*15051Skarels 0125252,0125252,0125252,0125252,0125252,0125252,0125252,0125252, 66*15051Skarels 052525, 052525, 052525, 052525, 052525, 052525, 052525, 052525, 67*15051Skarels #endif 68*15051Skarels 052525, 052525, 052525, 052525, 052525, 052525, 052525, 052525 69*15051Skarels }; 70*15051Skarels 71*15051Skarels #define NPT (sizeof (ppat) / sizeof (short)) 72*15051Skarels int npat; /* subscript to ppat[] */ 73*15051Skarels int severe; /* nz if running "severe" burnin */ 74*15051Skarels int nbads; /* subscript for bads */ 75*15051Skarels long bads[MAXBADDESC]; /* Bad blocks accumulated */ 76*15051Skarels 7711367Ssam char *malloc(); 78*15051Skarels int qcompar(); 7911367Ssam char *prompt(); 8011367Ssam extern int end; 8111367Ssam 8211367Ssam main() 8311367Ssam { 8411367Ssam register int sector, sn; 85*15051Skarels int lastsector, tracksize, rtracksize; 8611367Ssam int unit, fd, resid, i, trk, cyl, debug; 8711367Ssam struct st st; 8811367Ssam struct sector *bp, *cbp; 89*15051Skarels char *rbp, *rcbp; 90*15051Skarels int pass, maxpass; 9111367Ssam char *cp; 9211367Ssam 9311367Ssam printf("Disk format/check utility\n\n"); 9411367Ssam 9511367Ssam again: 96*15051Skarels nbads = 0; 97*15051Skarels 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"); 110*15051Skarels if (severe) 111*15051Skarels 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) { 116*15051Skarels if (severe) { 117*15051Skarels printf("Severe burnin doesn't work with RM80 yet\n"); 118*15051Skarels exit(1); 119*15051Skarels } 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; 125*15051Skarels rtracksize = SECTSIZ * st.nsect; 12611367Ssam bp = (struct sector *)malloc(tracksize); 127*15051Skarels rbp = malloc(rtracksize); 128*15051Skarels if (severe) { 129*15051Skarels npat = 0; 130*15051Skarels maxpass = NPT; 131*15051Skarels } else 132*15051Skarels maxpass = 1; 133*15051Skarels for (pass = 0; pass < maxpass; pass++) { 134*15051Skarels if (severe) 135*15051Skarels printf("Begin pass %d\n", pass); 136*15051Skarels bufinit(bp, tracksize); 137*15051Skarels if (severe) 138*15051Skarels npat++; 13911367Ssam /* 140*15051Skarels * Begin check, for each track, 14111367Ssam * 142*15051Skarels * 1) Write header and test pattern. 143*15051Skarels * 2) Read data. Hardware checks header and data ECC. 144*15051Skarels * Read data (esp on Eagles) is much faster when write check. 14511367Ssam */ 146*15051Skarels lastsector = st.nspc * st.ncyl; 147*15051Skarels for (sector = 0; sector < lastsector; sector += st.nsect) { 148*15051Skarels cyl = sector / st.nspc; 149*15051Skarels trk = (sector % st.nspc) / st.nsect; 150*15051Skarels for (i = 0; i < st.nsect; i++) { 151*15051Skarels bp[i].header1 = 152*15051Skarels (u_short) cyl | HDR1_FMT22 | HDR1_OKSCT; 153*15051Skarels bp[i].header2 = ((u_short)trk << 8) + i; 154*15051Skarels } 155*15051Skarels if (sector && (sector % (st.nspc * 100)) == 0) 156*15051Skarels printf("cylinder %d\n", cyl); 157*15051Skarels /* 158*15051Skarels * Try and write the headers and data patterns into 159*15051Skarels * each sector in the track. Continue until such 160*15051Skarels * we're done, or until there's less than a sector's 161*15051Skarels * worth of data to transfer. 162*15051Skarels * 163*15051Skarels * The lseek call is necessary because of 164*15051Skarels * the odd sector size (516 bytes) 165*15051Skarels */ 166*15051Skarels for (resid = tracksize, cbp = bp, sn = sector;;) { 167*15051Skarels int cc; 16811367Ssam 169*15051Skarels lseek(fd, sn * SECTSIZ, 0); 170*15051Skarels ioctl(fd, SAIOHDR, (char *)0); 171*15051Skarels cc = write(fd, cbp, resid); 172*15051Skarels if (cc == resid) 173*15051Skarels break; 174*15051Skarels /* 175*15051Skarels * Don't record errors during write, 176*15051Skarels * all errors will be found during 177*15051Skarels * writecheck performed below. 178*15051Skarels */ 179*15051Skarels sn = iob[fd - 3].i_errblk; 180*15051Skarels cbp += sn - sector; 181*15051Skarels resid -= (sn - sector) * sizeof (struct sector); 182*15051Skarels if (resid < sizeof (struct sector)) 183*15051Skarels break; 184*15051Skarels } 18511367Ssam /* 186*15051Skarels * Read test patterns. 187*15051Skarels * Retry remainder of track on error until 188*15051Skarels * we're done, or until there's less than a 189*15051Skarels * sector to verify. 19011367Ssam */ 191*15051Skarels for (resid = rtracksize, rcbp = rbp, sn = sector;;) { 192*15051Skarels int cc; 19311367Ssam 194*15051Skarels lseek(fd, sn * SECTSIZ, 0); 195*15051Skarels cc = read(fd, rcbp, resid); 196*15051Skarels if (cc == resid) 197*15051Skarels break; 198*15051Skarels sn = iob[fd-3].i_errblk; 199*15051Skarels printf("sector %d, read error\n", sn); 200*15051Skarels if (recorderror(fd, sn, &st) < 0 && pass > 0) 201*15051Skarels goto out; 202*15051Skarels /* advance past bad sector */ 203*15051Skarels sn++; 204*15051Skarels rcbp += sn - sector; 205*15051Skarels resid -= ((sn - sector) * SECTSIZ); 206*15051Skarels if (resid < SECTSIZ) 207*15051Skarels break; 208*15051Skarels } 20911367Ssam } 21011367Ssam } 21111367Ssam /* 21211367Ssam * Checking finished. 21311367Ssam */ 214*15051Skarels out: 215*15051Skarels if (severe && nbads) { 216*15051Skarels /* 217*15051Skarels * Sort bads and insert in bad block table. 218*15051Skarels */ 219*15051Skarels qsort(bads, nbads, sizeof (long), qcompar); 220*15051Skarels severe = 0; 221*15051Skarels for (i = 0; i < nbads; i++) { 222*15051Skarels errno = EECC; /* for now */ 223*15051Skarels recorderror(fd, bads[i], &st); 224*15051Skarels } 225*15051Skarels severe++; 226*15051Skarels } 22711367Ssam if (errors[FE_TOTAL] || errors[FE_SSE]) { 22811367Ssam printf("Errors:\n"); 22911367Ssam for (i = 0; i < NERRORS; i++) 23011367Ssam printf("%s: %d\n", errornames[i], errors[i]); 23111367Ssam printf("Total of %d hard errors found\n", 23211367Ssam errors[FE_TOTAL] + errors[FE_SSE]); 23311367Ssam /* change the headers of all the bad sectors */ 23411367Ssam writebb(fd, errors[FE_SSE], &sstab, &st, SSERR); 23511367Ssam writebb(fd, errors[FE_TOTAL], &dkbad, &st, BSERR); 23611367Ssam } 23711367Ssam while (errors[FE_TOTAL] < MAXBADDESC) { 23811367Ssam int i = errors[FE_TOTAL]++; 23911367Ssam 24011367Ssam dkbad.bt_bad[i].bt_cyl = -1; 24111367Ssam dkbad.bt_bad[i].bt_trksec = -1; 24211367Ssam } 24311367Ssam printf("\nWriting bad sector table at sector #%d\n", 24411367Ssam st.ncyl * st.nspc - st.nsect); 24511367Ssam /* place on disk */ 24611367Ssam for (i = 0; i < 10; i += 2) { 24711367Ssam lseek(fd, SECTSIZ * (st.ncyl * st.nspc - st.nsect + i), 0); 24811367Ssam write(fd, &dkbad, sizeof (dkbad)); 24911367Ssam } 25011367Ssam printf("Done\n"); 25111367Ssam ioctl(fd,SAIONOSSI,(char *)0); 25211367Ssam close(fd); 253*15051Skarels /* 254*15051Skarels if (severe) { 255*15051Skarels asm("halt"); 256*15051Skarels exit(0); 257*15051Skarels } 258*15051Skarels */ 25911367Ssam #ifndef JUSTEXIT 26011367Ssam goto again; 26111367Ssam #endif 26211367Ssam } 26311367Ssam 264*15051Skarels qcompar(l1, l2) 265*15051Skarels register long *l1, *l2; 266*15051Skarels { 267*15051Skarels if (*l1 < *l2) 268*15051Skarels return(-1); 269*15051Skarels if (*l1 == *l2) 270*15051Skarels return(0); 271*15051Skarels return(1); 272*15051Skarels } 273*15051Skarels 27411367Ssam /* 27511367Ssam * Write out the bad blocks. 27611367Ssam */ 27711367Ssam writebb(fd, nsects, dbad, st, sw) 27811367Ssam int nsects, fd; 27911367Ssam struct dkbad *dbad; 28011367Ssam register struct st *st; 28111367Ssam { 28211367Ssam struct sector bb_buf; /* buffer for one sector plus 4 byte header */ 28311367Ssam register int i; 28411367Ssam int bn, j; 28511367Ssam struct bt_bad *btp; 28611367Ssam 28711367Ssam for (i = 0; i < nsects; i++) { 28811367Ssam btp = &dbad->bt_bad[i]; 28911367Ssam if (sw == BSERR) { 29011367Ssam bb_buf.header1 = HDR1_FMT22|btp->bt_cyl; 29111367Ssam if (SSDEV) 29211367Ssam bb_buf.header1 |= HDR1_SSF; 29311367Ssam } else 29411367Ssam bb_buf.header1 = 29511367Ssam btp->bt_cyl | HDR1_FMT22 | HDR1_SSF | HDR1_OKSCT; 29611367Ssam bb_buf.header2 = btp->bt_trksec; 29711367Ssam bn = st->nspc * btp->bt_cyl + 29811367Ssam st->nsect * (btp->bt_trksec >> 8) + 29915009Skarels (btp->bt_trksec & 0xff); 30011367Ssam lseek(fd, bn * SECTSIZ, 0); 30111367Ssam ioctl(fd, SAIOHDR, (char *)0); 30211367Ssam write(fd, &bb_buf, sizeof (bb_buf)); 30311367Ssam if (!SSDEV) 30411367Ssam continue; 30511367Ssam /* 30611367Ssam * If skip sector, mark all remaining 30711367Ssam * sectors on the track. 30811367Ssam */ 30915009Skarels for (j = (btp->bt_trksec & 0xff) + 1; j < st->nsect; j++) { 31011367Ssam bb_buf.header1 = j | HDR1_FMT22 | HDR1_SSF; 31111367Ssam ioctl(fd, SAIOHDR, (char *)0); 31211367Ssam write(fd, &bb_buf, sizeof (bb_buf)); 31311367Ssam } 31411367Ssam } 31511367Ssam } 31611367Ssam 31711367Ssam /* 31811367Ssam * Record an error, and if there's room, put 31911367Ssam * it in the appropriate bad sector table. 320*15051Skarels * 321*15051Skarels * If severe burnin store block in a list after making sure 322*15051Skarels * we have not already found it on a prev pass. 32311367Ssam */ 32411367Ssam recorderror(fd, bn, st) 32511367Ssam int fd, bn; 32611367Ssam register struct st *st; 32711367Ssam { 32811367Ssam int cn, tn, sn, strk; 329*15051Skarels register i; 33011367Ssam 331*15051Skarels 332*15051Skarels if (severe) { 333*15051Skarels for (i = 0; i < nbads; i++) 334*15051Skarels if (bads[i] == bn) 335*15051Skarels return(0); /* bn already flagged */ 336*15051Skarels if (nbads >= MAXBADDESC) { 337*15051Skarels printf("Bad sector table full, burnin terminating\n"); 338*15051Skarels return(-1); 339*15051Skarels } 340*15051Skarels bads[nbads++] = bn; 341*15051Skarels return(0); 342*15051Skarels } 34311367Ssam if (errors[FE_TOTAL] >= MAXBADDESC) { 34411367Ssam printf("Too many bad sectors\n"); 345*15051Skarels return(-1); 34611367Ssam } 34711367Ssam if (errors[FE_SSE] >= MAXBADDESC) { 34811367Ssam printf("Too many skip sector errors\n"); 349*15051Skarels return(-1); 35011367Ssam } 35115009Skarels if (errno < EBSE || errno > EHER) 352*15051Skarels return(0); 35315009Skarels errno -= EBSE; 35411367Ssam errors[errno]++; 35511367Ssam cn = bn / st->nspc; 35611367Ssam sn = bn % st->nspc; 35711367Ssam tn = sn / st->nsect; 35811367Ssam sn %= st->nsect; 35911367Ssam if (SSDEV) { /* if drive has skip sector capability */ 36011367Ssam int ss = errors[FE_SSE]++; 36111367Ssam 36211367Ssam if (ss) 36311367Ssam strk = sstab.bt_bad[ss - 1].bt_trksec >> 8; 36411367Ssam else 36511367Ssam strk = -1; 36611367Ssam if (tn != strk) { /* only one skip sector/track */ 36711367Ssam sstab.bt_bad[ss].bt_cyl = cn; 36811367Ssam sstab.bt_bad[ss].bt_trksec = (tn<<8) + sn; 36911367Ssam return; 37011367Ssam } 37111367Ssam cn = -cn; 37211367Ssam } 37311367Ssam /* record the bad sector address and continue */ 37415009Skarels dkbad.bt_bad[errors[FE_TOTAL]].bt_cyl = cn; 37511367Ssam dkbad.bt_bad[errors[FE_TOTAL]++].bt_trksec = (tn << 8) + sn; 376*15051Skarels return(0); 37711367Ssam } 37811367Ssam 37911367Ssam /* 38011367Ssam * Allocate memory on a page-aligned address. 38111367Ssam * Round allocated chunk to a page multiple to 38211367Ssam * ease next request. 38311367Ssam */ 38411367Ssam char * 38511367Ssam malloc(size) 38611367Ssam int size; 38711367Ssam { 38811367Ssam char *result; 38911367Ssam static caddr_t last = 0; 39011367Ssam 39111367Ssam if (last == 0) 39211367Ssam last = (caddr_t)(((int)&end + 511) & ~0x1ff); 39311367Ssam size = (size + 511) & ~0x1ff; 39411367Ssam result = (char *)last; 39511367Ssam last += size; 39611367Ssam return (result); 39711367Ssam } 39811367Ssam 39911367Ssam /* 40011367Ssam * Prompt and verify a device name from the user. 40111367Ssam */ 40211367Ssam getdevice() 40311367Ssam { 40411367Ssam register char *cp; 40511367Ssam register struct devsw *dp; 40611367Ssam int fd; 40711367Ssam 40811367Ssam top: 40911367Ssam cp = prompt("Device to format? "); 41011367Ssam if ((fd = open(cp, 2)) < 0) { 41111367Ssam printf("Known devices are: "); 41211367Ssam for (dp = devsw; dp->dv_name; dp++) 41311367Ssam printf("%s ",dp->dv_name); 41411367Ssam printf("\n"); 41511367Ssam goto top; 41611367Ssam } 417*15051Skarels printf("Formatting drive %c%c%d on adaptor %d: ", 418*15051Skarels cp[0], cp[1], iob[fd - 3].i_unit % 8, iob[fd - 3].i_unit / 8); 41911367Ssam cp = prompt("verify (yes/no)? "); 42011367Ssam while (*cp != 'y' && *cp != 'n') 42111367Ssam cp = prompt("Huh, yes or no? "); 42211367Ssam if (*cp == 'y') 42311367Ssam return (fd); 42411367Ssam goto top; 42511367Ssam } 42611367Ssam 42711371Ssam static struct pattern { 42811371Ssam long pa_value; 42911371Ssam char *pa_name; 43011371Ssam } pat[] = { 43111371Ssam { 0xf00ff00f, "RH750 worst case" }, 43211371Ssam { 0xec6dec6d, "media worst case" }, 43311371Ssam { 0xa5a5a5a5, "alternate 1's and 0's" }, 434*15051Skarels { 0xFFFFFFFF, "Severe burnin (takes several hours)" }, 43511371Ssam { 0, 0 }, 43611371Ssam }; 43711371Ssam 43811371Ssam getpattern() 43911371Ssam { 44011371Ssam register struct pattern *p; 44111371Ssam int npatterns; 44211371Ssam char *cp; 44311371Ssam 44411371Ssam printf("Available test patterns are:\n"); 44511371Ssam for (p = pat; p->pa_value; p++) 44611371Ssam printf("\t%d - (%x) %s\n", (p - pat) + 1, 44711371Ssam p->pa_value & 0xffff, p->pa_name); 44811371Ssam npatterns = p - pat; 44911371Ssam cp = prompt("Pattern (one of the above, other to restart)? "); 45011371Ssam pattern = atoi(cp) - 1; 451*15051Skarels severe = 0; 452*15051Skarels if (pat[pattern].pa_value == -1) 453*15051Skarels severe = 1; 45411371Ssam return (pattern < 0 || pattern >= npatterns); 45511371Ssam } 45611371Ssam 45711371Ssam struct xsect { 45811371Ssam u_short hd1; 45911371Ssam u_short hd2; 46011371Ssam long buf[128]; 46111371Ssam }; 46211371Ssam 46311371Ssam /* 46411371Ssam * Initialize the buffer with the requested pattern. 46511371Ssam */ 46611371Ssam bufinit(bp, size) 46711371Ssam register struct xsect *bp; 46811371Ssam int size; 46911371Ssam { 47011371Ssam register struct pattern *pptr; 47111371Ssam register long *pp, *last; 47211371Ssam register struct xsect *lastbuf; 473*15051Skarels int patt; 47411371Ssam 47511371Ssam size /= sizeof (struct sector); 47611371Ssam lastbuf = bp + size; 477*15051Skarels if (severe) { 478*15051Skarels patt = ppat[npat] | ((long)ppat[npat] << 16); 479*15051Skarels printf("Write pattern 0x%x\n", patt&0xffff); 480*15051Skarels } else { 481*15051Skarels pptr = &pat[pattern]; 482*15051Skarels patt = pptr->pa_value; 483*15051Skarels } 48411371Ssam while (bp < lastbuf) { 48511371Ssam last = &bp->buf[128]; 48611371Ssam for (pp = bp->buf; pp < last; pp++) 487*15051Skarels *pp = patt; 48811371Ssam bp++; 48911371Ssam } 49011371Ssam } 49111371Ssam 49211367Ssam char * 49311367Ssam prompt(msg) 49411367Ssam char *msg; 49511367Ssam { 49611367Ssam static char buf[132]; 49711367Ssam 49811367Ssam printf("%s", msg); 49911367Ssam gets(buf); 50011367Ssam return (buf); 50111367Ssam } 502