1*23251Smckusick /* 2*23251Smckusick * Copyright (c) 1980 Regents of the University of California. 3*23251Smckusick * All rights reserved. The Berkeley software License Agreement 4*23251Smckusick * specifies the terms and conditions for redistribution. 5*23251Smckusick */ 611367Ssam 7*23251Smckusick #ifndef lint 8*23251Smckusick char copyright[] = 9*23251Smckusick "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 10*23251Smckusick All rights reserved.\n"; 11*23251Smckusick #endif not lint 1215051Skarels 13*23251Smckusick #ifndef lint 14*23251Smckusick static char sccsid[] = "@(#)format.c 6.5 (Berkeley) 06/08/85"; 15*23251Smckusick #endif not lint 16*23251Smckusick 1711367Ssam /* 1811367Ssam * Standalone program to do media checking 1911367Ssam * and record bad block information on any 2015009Skarels * disk with the appropriate driver and RM03-style headers. 2111367Ssam */ 2211367Ssam #include "../h/param.h" 2311367Ssam #include "../h/fs.h" 2411367Ssam #include "../h/inode.h" 2511367Ssam #include "../h/dkbad.h" 2611367Ssam #include "../h/vmmac.h" 2711367Ssam 2811367Ssam #include "saio.h" 2911367Ssam #include "savax.h" 3011367Ssam 3111367Ssam #define MAXBADDESC 126 /* size of bad block table */ 3211367Ssam #define CHUNK 48 /* max # of sectors/io operation */ 3311367Ssam #define SECTSIZ 512 /* standard sector size */ 3411367Ssam #define HDRSIZ 4 /* number of bytes in sector header */ 3511367Ssam 3611367Ssam #define SSERR 0 3711367Ssam #define BSERR 1 3811367Ssam 3911367Ssam #define SSDEV ((ioctl(iob[fd-3], SAIOSSDEV, (char *)0) == 0)) 4011367Ssam 4111367Ssam struct sector { 4211367Ssam u_short header1; 4311367Ssam u_short header2; 4411367Ssam char buf[SECTSIZ]; 4511367Ssam }; 4611367Ssam 4711367Ssam struct dkbad dkbad; /* bad sector table */ 4811367Ssam struct dkbad sstab; /* skip sector table */ 4911367Ssam 5011367Ssam #define NERRORS 6 5111371Ssam static char * 5211371Ssam errornames[NERRORS] = { 5315009Skarels #define FE_BSE 0 5415009Skarels "Bad sector", 5515009Skarels #define FE_WCE 1 5611367Ssam "Write check", 5711367Ssam #define FE_ECC 2 5811367Ssam "ECC", 5911367Ssam #define FE_HARD 3 6011367Ssam "Other hard", 6111367Ssam #define FE_TOTAL 4 6211367Ssam "Total", 6311367Ssam #define FE_SSE 5 6411367Ssam "Skip sector", 6511367Ssam }; 6611367Ssam 6711367Ssam int errors[NERRORS]; /* histogram of errors */ 6811371Ssam int pattern; 6911367Ssam 7015051Skarels /* 7115051Skarels * Purdue/EE severe burnin patterns. 7215051Skarels */ 7315051Skarels unsigned short ppat[] = { 7417426Skarels 0xf00f, 0xec6d, 0031463,0070707,0133333,0155555,0161616,0143434, 7515051Skarels 0107070,0016161,0034343,0044444,0022222,0111111,0125252, 052525, 7615051Skarels 0125252,0125252,0125252,0125252,0125252,0125252,0125252,0125252, 7715051Skarels #ifndef SHORTPASS 7815051Skarels 0125252,0125252,0125252,0125252,0125252,0125252,0125252,0125252, 7915051Skarels 052525, 052525, 052525, 052525, 052525, 052525, 052525, 052525, 8015051Skarels #endif 8115051Skarels 052525, 052525, 052525, 052525, 052525, 052525, 052525, 052525 8215051Skarels }; 8315051Skarels 8415051Skarels #define NPT (sizeof (ppat) / sizeof (short)) 8517426Skarels int maxpass, npat; /* subscript to ppat[] */ 8615051Skarels int severe; /* nz if running "severe" burnin */ 8715051Skarels int nbads; /* subscript for bads */ 8815051Skarels long bads[MAXBADDESC]; /* Bad blocks accumulated */ 8915051Skarels 9011367Ssam char *malloc(); 9115051Skarels int qcompar(); 9211367Ssam char *prompt(); 9311367Ssam extern int end; 9411367Ssam 9511367Ssam main() 9611367Ssam { 9711367Ssam register int sector, sn; 9815051Skarels int lastsector, tracksize, rtracksize; 9911367Ssam int unit, fd, resid, i, trk, cyl, debug; 10011367Ssam struct st st; 10111367Ssam struct sector *bp, *cbp; 10215051Skarels char *rbp, *rcbp; 10317426Skarels int pass; 10411367Ssam char *cp; 10511367Ssam 10611367Ssam printf("Disk format/check utility\n\n"); 10711367Ssam 10811367Ssam again: 10915051Skarels nbads = 0; 11015051Skarels cp = prompt("Enable debugging (0=none, 1=bse, 2=ecc, 3=bse+ecc)? "); 11111367Ssam debug = atoi(cp); 11211367Ssam if (debug < 0) 11311367Ssam debug = 0; 11411367Ssam for (i = 0; i < NERRORS; i++) 11511367Ssam errors[i] = 0; 11611367Ssam fd = getdevice(); 11711367Ssam ioctl(fd, SAIODEVDATA, &st); 11811367Ssam printf("Device data: #cylinders=%d, #tracks=%d, #sectors=%d\n", 11911367Ssam st.ncyl, st.ntrak, st.nsect); 12011371Ssam if (getpattern()) 12111367Ssam goto again; 12211367Ssam printf("Start formatting...make sure the drive is online\n"); 12315051Skarels if (severe) 12415051Skarels ioctl(fd, SAIOSEVRE, (char *) 0); 12511367Ssam ioctl(fd, SAIONOBAD, (char *)0); 12611367Ssam ioctl(fd, SAIOECCLIM, (char *)0); 12711367Ssam ioctl(fd, SAIODEBUG, (char *)debug); 12811367Ssam if (SSDEV) { 12915051Skarels if (severe) { 13015051Skarels printf("Severe burnin doesn't work with RM80 yet\n"); 13115051Skarels exit(1); 13215051Skarels } 13311367Ssam ioctl(fd, SAIOSSI, (char *)0); /* set skip sector inhibit */ 13411367Ssam st.nsect++; 13511367Ssam st.nspc += st.ntrak; 13611367Ssam } 13711367Ssam tracksize = sizeof (struct sector) * st.nsect; 13815051Skarels rtracksize = SECTSIZ * st.nsect; 13911367Ssam bp = (struct sector *)malloc(tracksize); 14015051Skarels rbp = malloc(rtracksize); 14117426Skarels pass = 0; 14217426Skarels npat = 0; 14317426Skarels more: 14417426Skarels for (; pass < maxpass; pass++) { 14515051Skarels if (severe) 14615051Skarels printf("Begin pass %d\n", pass); 14715051Skarels bufinit(bp, tracksize); 14815051Skarels if (severe) 14915051Skarels npat++; 15011367Ssam /* 15115051Skarels * Begin check, for each track, 15211367Ssam * 15315051Skarels * 1) Write header and test pattern. 15415051Skarels * 2) Read data. Hardware checks header and data ECC. 15517426Skarels * Read data (esp on Eagles) is much faster than write check. 15611367Ssam */ 15715051Skarels lastsector = st.nspc * st.ncyl; 15815051Skarels for (sector = 0; sector < lastsector; sector += st.nsect) { 15915051Skarels cyl = sector / st.nspc; 16015051Skarels trk = (sector % st.nspc) / st.nsect; 16115051Skarels for (i = 0; i < st.nsect; i++) { 16215051Skarels bp[i].header1 = 16315051Skarels (u_short) cyl | HDR1_FMT22 | HDR1_OKSCT; 16415051Skarels bp[i].header2 = ((u_short)trk << 8) + i; 16515051Skarels } 16615051Skarels if (sector && (sector % (st.nspc * 100)) == 0) 16715051Skarels printf("cylinder %d\n", cyl); 16815051Skarels /* 16915051Skarels * Try and write the headers and data patterns into 17015051Skarels * each sector in the track. Continue until such 17115051Skarels * we're done, or until there's less than a sector's 17215051Skarels * worth of data to transfer. 17315051Skarels * 17415051Skarels * The lseek call is necessary because of 17515051Skarels * the odd sector size (516 bytes) 17615051Skarels */ 17715051Skarels for (resid = tracksize, cbp = bp, sn = sector;;) { 17815051Skarels int cc; 17911367Ssam 18015051Skarels lseek(fd, sn * SECTSIZ, 0); 18115051Skarels ioctl(fd, SAIOHDR, (char *)0); 18215051Skarels cc = write(fd, cbp, resid); 18315051Skarels if (cc == resid) 18415051Skarels break; 18515051Skarels /* 18615051Skarels * Don't record errors during write, 18715051Skarels * all errors will be found during 18815051Skarels * writecheck performed below. 18915051Skarels */ 19015051Skarels sn = iob[fd - 3].i_errblk; 19115051Skarels cbp += sn - sector; 19215051Skarels resid -= (sn - sector) * sizeof (struct sector); 19315051Skarels if (resid < sizeof (struct sector)) 19415051Skarels break; 19515051Skarels } 19611367Ssam /* 19715051Skarels * Read test patterns. 19815051Skarels * Retry remainder of track on error until 19915051Skarels * we're done, or until there's less than a 20015051Skarels * sector to verify. 20111367Ssam */ 20215051Skarels for (resid = rtracksize, rcbp = rbp, sn = sector;;) { 20315051Skarels int cc; 20411367Ssam 20515051Skarels lseek(fd, sn * SECTSIZ, 0); 20615051Skarels cc = read(fd, rcbp, resid); 20715051Skarels if (cc == resid) 20815051Skarels break; 20915051Skarels sn = iob[fd-3].i_errblk; 21015051Skarels printf("sector %d, read error\n", sn); 21115051Skarels if (recorderror(fd, sn, &st) < 0 && pass > 0) 21215051Skarels goto out; 21315051Skarels /* advance past bad sector */ 21415051Skarels sn++; 21515051Skarels rcbp += sn - sector; 21615051Skarels resid -= ((sn - sector) * SECTSIZ); 21715051Skarels if (resid < SECTSIZ) 21815051Skarels break; 21915051Skarels } 22011367Ssam } 22111367Ssam } 22211367Ssam /* 22311367Ssam * Checking finished. 22411367Ssam */ 22515051Skarels out: 22617426Skarels if (errors[FE_TOTAL] || errors[FE_SSE]) { 22717426Skarels printf("Errors:\n"); 22817426Skarels for (i = 0; i < NERRORS; i++) 22917426Skarels printf("%s: %d\n", errornames[i], errors[i]); 23017426Skarels printf("Total of %d hard errors found\n", 23117426Skarels errors[FE_TOTAL] + errors[FE_SSE]); 23217426Skarels } 23317426Skarels if (severe && maxpass < NPT) { 23417426Skarels cp = prompt("More passes? (0 or number) "); 23517426Skarels maxpass = atoi(cp); 23617426Skarels if (maxpass > 0) { 23717426Skarels maxpass += pass; 23817426Skarels goto more; 23917426Skarels } 24017426Skarels } 24115051Skarels if (severe && nbads) { 24215051Skarels /* 24315051Skarels * Sort bads and insert in bad block table. 24415051Skarels */ 24515051Skarels qsort(bads, nbads, sizeof (long), qcompar); 24615051Skarels severe = 0; 24717426Skarels errno = 0; 24817426Skarels for (i = 0; i < nbads; i++) 24915051Skarels recorderror(fd, bads[i], &st); 25015051Skarels severe++; 25115051Skarels } 25211367Ssam if (errors[FE_TOTAL] || errors[FE_SSE]) { 25311367Ssam /* change the headers of all the bad sectors */ 25411367Ssam writebb(fd, errors[FE_SSE], &sstab, &st, SSERR); 25511367Ssam writebb(fd, errors[FE_TOTAL], &dkbad, &st, BSERR); 25611367Ssam } 25711367Ssam while (errors[FE_TOTAL] < MAXBADDESC) { 25811367Ssam int i = errors[FE_TOTAL]++; 25911367Ssam 26011367Ssam dkbad.bt_bad[i].bt_cyl = -1; 26111367Ssam dkbad.bt_bad[i].bt_trksec = -1; 26211367Ssam } 26311367Ssam printf("\nWriting bad sector table at sector #%d\n", 26411367Ssam st.ncyl * st.nspc - st.nsect); 26511367Ssam /* place on disk */ 26611367Ssam for (i = 0; i < 10; i += 2) { 26711367Ssam lseek(fd, SECTSIZ * (st.ncyl * st.nspc - st.nsect + i), 0); 26811367Ssam write(fd, &dkbad, sizeof (dkbad)); 26911367Ssam } 27011367Ssam printf("Done\n"); 27111367Ssam ioctl(fd,SAIONOSSI,(char *)0); 27211367Ssam close(fd); 27311367Ssam #ifndef JUSTEXIT 27411367Ssam goto again; 27511367Ssam #endif 27611367Ssam } 27711367Ssam 27815051Skarels qcompar(l1, l2) 27915051Skarels register long *l1, *l2; 28015051Skarels { 28115051Skarels if (*l1 < *l2) 28215051Skarels return(-1); 28315051Skarels if (*l1 == *l2) 28415051Skarels return(0); 28515051Skarels return(1); 28615051Skarels } 28715051Skarels 28811367Ssam /* 28911367Ssam * Write out the bad blocks. 29011367Ssam */ 29111367Ssam writebb(fd, nsects, dbad, st, sw) 29211367Ssam int nsects, fd; 29311367Ssam struct dkbad *dbad; 29411367Ssam register struct st *st; 29511367Ssam { 29611367Ssam struct sector bb_buf; /* buffer for one sector plus 4 byte header */ 29711367Ssam register int i; 29811367Ssam int bn, j; 29911367Ssam struct bt_bad *btp; 30011367Ssam 30111367Ssam for (i = 0; i < nsects; i++) { 30211367Ssam btp = &dbad->bt_bad[i]; 30311367Ssam if (sw == BSERR) { 30411367Ssam bb_buf.header1 = HDR1_FMT22|btp->bt_cyl; 30511367Ssam if (SSDEV) 30611367Ssam bb_buf.header1 |= HDR1_SSF; 30711367Ssam } else 30811367Ssam bb_buf.header1 = 30911367Ssam btp->bt_cyl | HDR1_FMT22 | HDR1_SSF | HDR1_OKSCT; 31011367Ssam bb_buf.header2 = btp->bt_trksec; 31111367Ssam bn = st->nspc * btp->bt_cyl + 31211367Ssam st->nsect * (btp->bt_trksec >> 8) + 31315009Skarels (btp->bt_trksec & 0xff); 31411367Ssam lseek(fd, bn * SECTSIZ, 0); 31511367Ssam ioctl(fd, SAIOHDR, (char *)0); 31611367Ssam write(fd, &bb_buf, sizeof (bb_buf)); 31711367Ssam if (!SSDEV) 31811367Ssam continue; 31911367Ssam /* 32011367Ssam * If skip sector, mark all remaining 32111367Ssam * sectors on the track. 32211367Ssam */ 32315009Skarels for (j = (btp->bt_trksec & 0xff) + 1; j < st->nsect; j++) { 32411367Ssam bb_buf.header1 = j | HDR1_FMT22 | HDR1_SSF; 32511367Ssam ioctl(fd, SAIOHDR, (char *)0); 32611367Ssam write(fd, &bb_buf, sizeof (bb_buf)); 32711367Ssam } 32811367Ssam } 32911367Ssam } 33011367Ssam 33111367Ssam /* 33211367Ssam * Record an error, and if there's room, put 33311367Ssam * it in the appropriate bad sector table. 33415051Skarels * 33515051Skarels * If severe burnin store block in a list after making sure 33615051Skarels * we have not already found it on a prev pass. 33711367Ssam */ 33811367Ssam recorderror(fd, bn, st) 33911367Ssam int fd, bn; 34011367Ssam register struct st *st; 34111367Ssam { 34211367Ssam int cn, tn, sn, strk; 34315051Skarels register i; 34411367Ssam 34515051Skarels 34615051Skarels if (severe) { 34715051Skarels for (i = 0; i < nbads; i++) 34815051Skarels if (bads[i] == bn) 34915051Skarels return(0); /* bn already flagged */ 35015051Skarels if (nbads >= MAXBADDESC) { 35115051Skarels printf("Bad sector table full, burnin terminating\n"); 35215051Skarels return(-1); 35315051Skarels } 35415051Skarels bads[nbads++] = bn; 35517426Skarels if (errno < EBSE || errno > EHER) 35617426Skarels return(0); 35717426Skarels errno -= EBSE; 35817426Skarels errors[errno]++; 35915051Skarels return(0); 36015051Skarels } 36117426Skarels if (errno >= EBSE && errno <= EHER) { 36217426Skarels if (errors[FE_TOTAL] >= MAXBADDESC) { 36317426Skarels printf("Too many bad sectors\n"); 36417426Skarels return(-1); 36517426Skarels } 36617426Skarels if (errors[FE_SSE] >= MAXBADDESC) { 36717426Skarels printf("Too many skip sector errors\n"); 36817426Skarels return(-1); 36917426Skarels } 37017426Skarels errno -= EBSE; 37117426Skarels errors[errno]++; 37211367Ssam } 37311367Ssam cn = bn / st->nspc; 37411367Ssam sn = bn % st->nspc; 37511367Ssam tn = sn / st->nsect; 37611367Ssam sn %= st->nsect; 37711367Ssam if (SSDEV) { /* if drive has skip sector capability */ 37811367Ssam int ss = errors[FE_SSE]++; 37911367Ssam 38011367Ssam if (ss) 38111367Ssam strk = sstab.bt_bad[ss - 1].bt_trksec >> 8; 38211367Ssam else 38311367Ssam strk = -1; 38411367Ssam if (tn != strk) { /* only one skip sector/track */ 38511367Ssam sstab.bt_bad[ss].bt_cyl = cn; 38611367Ssam sstab.bt_bad[ss].bt_trksec = (tn<<8) + sn; 38711367Ssam return; 38811367Ssam } 38911367Ssam cn = -cn; 39011367Ssam } 39111367Ssam /* record the bad sector address and continue */ 39215009Skarels dkbad.bt_bad[errors[FE_TOTAL]].bt_cyl = cn; 39311367Ssam dkbad.bt_bad[errors[FE_TOTAL]++].bt_trksec = (tn << 8) + sn; 39415051Skarels return(0); 39511367Ssam } 39611367Ssam 39711367Ssam /* 39811367Ssam * Allocate memory on a page-aligned address. 39911367Ssam * Round allocated chunk to a page multiple to 40011367Ssam * ease next request. 40111367Ssam */ 40211367Ssam char * 40311367Ssam malloc(size) 40411367Ssam int size; 40511367Ssam { 40611367Ssam char *result; 40711367Ssam static caddr_t last = 0; 40811367Ssam 40911367Ssam if (last == 0) 41011367Ssam last = (caddr_t)(((int)&end + 511) & ~0x1ff); 41111367Ssam size = (size + 511) & ~0x1ff; 41211367Ssam result = (char *)last; 41311367Ssam last += size; 41411367Ssam return (result); 41511367Ssam } 41611367Ssam 41711367Ssam /* 41811367Ssam * Prompt and verify a device name from the user. 41911367Ssam */ 42011367Ssam getdevice() 42111367Ssam { 42211367Ssam register char *cp; 42311367Ssam register struct devsw *dp; 42411367Ssam int fd; 42511367Ssam 42611367Ssam top: 42711367Ssam cp = prompt("Device to format? "); 42811367Ssam if ((fd = open(cp, 2)) < 0) { 42911367Ssam printf("Known devices are: "); 43011367Ssam for (dp = devsw; dp->dv_name; dp++) 43111367Ssam printf("%s ",dp->dv_name); 43211367Ssam printf("\n"); 43311367Ssam goto top; 43411367Ssam } 43515051Skarels printf("Formatting drive %c%c%d on adaptor %d: ", 43615051Skarels cp[0], cp[1], iob[fd - 3].i_unit % 8, iob[fd - 3].i_unit / 8); 43711367Ssam cp = prompt("verify (yes/no)? "); 43811367Ssam while (*cp != 'y' && *cp != 'n') 43911367Ssam cp = prompt("Huh, yes or no? "); 44011367Ssam if (*cp == 'y') 44111367Ssam return (fd); 44211367Ssam goto top; 44311367Ssam } 44411367Ssam 44511371Ssam static struct pattern { 44611371Ssam long pa_value; 44711371Ssam char *pa_name; 44811371Ssam } pat[] = { 44911371Ssam { 0xf00ff00f, "RH750 worst case" }, 45011371Ssam { 0xec6dec6d, "media worst case" }, 45111371Ssam { 0xa5a5a5a5, "alternate 1's and 0's" }, 45217426Skarels { 0xFFFFFFFF, "Severe burnin (up to 48 passes)" }, 45311371Ssam { 0, 0 }, 45411371Ssam }; 45511371Ssam 45611371Ssam getpattern() 45711371Ssam { 45811371Ssam register struct pattern *p; 45911371Ssam int npatterns; 46011371Ssam char *cp; 46111371Ssam 46211371Ssam printf("Available test patterns are:\n"); 46311371Ssam for (p = pat; p->pa_value; p++) 46411371Ssam printf("\t%d - (%x) %s\n", (p - pat) + 1, 46511371Ssam p->pa_value & 0xffff, p->pa_name); 46611371Ssam npatterns = p - pat; 46711371Ssam cp = prompt("Pattern (one of the above, other to restart)? "); 46811371Ssam pattern = atoi(cp) - 1; 46917426Skarels if (pattern < 0 || pattern >= npatterns) 47017426Skarels return(1); 47115051Skarels severe = 0; 47217426Skarels maxpass = 1; 47317426Skarels if (pat[pattern].pa_value == -1) { 47415051Skarels severe = 1; 47517426Skarels cp = prompt("How many passes (up to 48)? "); 47617426Skarels maxpass = atoi(cp); 47717426Skarels if (maxpass > NPT) 47817426Skarels maxpass = NPT; 47917426Skarels } 48017426Skarels return (0); 48111371Ssam } 48211371Ssam 48311371Ssam struct xsect { 48411371Ssam u_short hd1; 48511371Ssam u_short hd2; 48611371Ssam long buf[128]; 48711371Ssam }; 48811371Ssam 48911371Ssam /* 49011371Ssam * Initialize the buffer with the requested pattern. 49111371Ssam */ 49211371Ssam bufinit(bp, size) 49311371Ssam register struct xsect *bp; 49411371Ssam int size; 49511371Ssam { 49611371Ssam register struct pattern *pptr; 49711371Ssam register long *pp, *last; 49811371Ssam register struct xsect *lastbuf; 49915051Skarels int patt; 50011371Ssam 50111371Ssam size /= sizeof (struct sector); 50211371Ssam lastbuf = bp + size; 50315051Skarels if (severe) { 50415051Skarels patt = ppat[npat] | ((long)ppat[npat] << 16); 50515051Skarels printf("Write pattern 0x%x\n", patt&0xffff); 50615051Skarels } else { 50715051Skarels pptr = &pat[pattern]; 50815051Skarels patt = pptr->pa_value; 50915051Skarels } 51011371Ssam while (bp < lastbuf) { 51111371Ssam last = &bp->buf[128]; 51211371Ssam for (pp = bp->buf; pp < last; pp++) 51315051Skarels *pp = patt; 51411371Ssam bp++; 51511371Ssam } 51611371Ssam } 51711371Ssam 51811367Ssam char * 51911367Ssam prompt(msg) 52011367Ssam char *msg; 52111367Ssam { 52211367Ssam static char buf[132]; 52311367Ssam 52411367Ssam printf("%s", msg); 52511367Ssam gets(buf); 52611367Ssam return (buf); 52711367Ssam } 528