1*12175Shelge /* format.c 4.4 83/05/03 */ 211367Ssam 311367Ssam /* 411367Ssam * Standalone program to do media checking 511367Ssam * and record bad block information on any 611367Ssam * disk with the appropriate driver. 711367Ssam */ 811367Ssam #include "../h/param.h" 911367Ssam #include "../h/fs.h" 1011367Ssam #include "../h/inode.h" 1111367Ssam #include "../h/dkbad.h" 1211367Ssam #include "../h/vmmac.h" 1311367Ssam 1411367Ssam #include "saio.h" 1511367Ssam #include "savax.h" 1611367Ssam 1711367Ssam #define MAXBADDESC 126 /* size of bad block table */ 1811367Ssam #define CHUNK 48 /* max # of sectors/io operation */ 1911367Ssam #define SECTSIZ 512 /* standard sector size */ 2011367Ssam #define HDRSIZ 4 /* number of bytes in sector header */ 2111367Ssam 2211367Ssam #define SSERR 0 2311367Ssam #define BSERR 1 2411367Ssam 2511367Ssam #define SSDEV ((ioctl(iob[fd-3], SAIOSSDEV, (char *)0) == 0)) 2611367Ssam 2711367Ssam struct sector { 2811367Ssam u_short header1; 2911367Ssam u_short header2; 3011367Ssam char buf[SECTSIZ]; 3111367Ssam }; 3211367Ssam 3311367Ssam struct dkbad dkbad; /* bad sector table */ 3411367Ssam struct dkbad sstab; /* skip sector table */ 3511367Ssam 3611367Ssam #define NERRORS 6 3711371Ssam static char * 3811371Ssam errornames[NERRORS] = { 3911367Ssam #define FE_WCE 0 4011367Ssam "Write check", 4111367Ssam #define FE_BSE 1 4211367Ssam "Bad sector", 4311367Ssam #define FE_ECC 2 4411367Ssam "ECC", 4511367Ssam #define FE_HARD 3 4611367Ssam "Other hard", 4711367Ssam #define FE_TOTAL 4 4811367Ssam "Total", 4911367Ssam #define FE_SSE 5 5011367Ssam "Skip sector", 5111367Ssam }; 5211367Ssam 5311367Ssam int errors[NERRORS]; /* histogram of errors */ 5411371Ssam int pattern; 5511367Ssam 5611367Ssam char *malloc(); 5711367Ssam char *prompt(); 5811367Ssam extern int end; 5911367Ssam 6011367Ssam main() 6111367Ssam { 6211367Ssam register int sector, sn; 6311371Ssam int lastsector, tracksize; 6411367Ssam int unit, fd, resid, i, trk, cyl, debug; 6511367Ssam struct st st; 6611367Ssam struct sector *bp, *cbp; 6711367Ssam char *cp; 6811367Ssam 6911367Ssam printf("Disk format/check utility\n\n"); 7011367Ssam 7111367Ssam again: 7211367Ssam cp = prompt("Enable debugging (1=bse, 2=ecc, 3=bse+ecc)? "); 7311367Ssam debug = atoi(cp); 7411367Ssam if (debug < 0) 7511367Ssam debug = 0; 7611367Ssam for (i = 0; i < NERRORS; i++) 7711367Ssam errors[i] = 0; 7811367Ssam fd = getdevice(); 7911367Ssam ioctl(fd, SAIODEVDATA, &st); 8011367Ssam printf("Device data: #cylinders=%d, #tracks=%d, #sectors=%d\n", 8111367Ssam st.ncyl, st.ntrak, st.nsect); 8211371Ssam if (getpattern()) 8311367Ssam goto again; 8411367Ssam printf("Start formatting...make sure the drive is online\n"); 8511367Ssam ioctl(fd, SAIONOBAD, (char *)0); 8611367Ssam ioctl(fd, SAIOECCLIM, (char *)0); 8711367Ssam ioctl(fd, SAIODEBUG, (char *)debug); 8811367Ssam if (SSDEV) { 8911367Ssam ioctl(fd, SAIOSSI, (char *)0); /* set skip sector inhibit */ 9011367Ssam st.nsect++; 9111367Ssam st.nspc += st.ntrak; 9211367Ssam } 9311367Ssam tracksize = sizeof (struct sector) * st.nsect; 9411367Ssam bp = (struct sector *)malloc(tracksize); 9511371Ssam bufinit(bp, tracksize); 9611367Ssam /* 9711367Ssam * Begin check, for each track, 9811367Ssam * 9911367Ssam * 1) Write header and test pattern. 10011367Ssam * 2) Write check header and data. 10111367Ssam */ 10211367Ssam lastsector = st.nspc * st.ncyl; 10311367Ssam for (sector = 0; sector < lastsector; sector += st.nsect) { 10411367Ssam cyl = sector / st.nspc; 10511367Ssam trk = (sector % st.nspc) / st.nsect; 10611367Ssam for (i = 0; i < st.nsect; i++) { 10711367Ssam bp[i].header1 = 10811367Ssam (u_short) cyl | HDR1_FMT22 | HDR1_OKSCT; 10911367Ssam bp[i].header2 = ((u_short)trk << 8) + i; 11011367Ssam } 11111367Ssam if (sector && (sector % (st.nspc * 10)) == 0) 112*12175Shelge printf("cylinder %d\n", cyl); 11311367Ssam /* 11411367Ssam * Try and write the headers and data patterns into 11511367Ssam * each sector in the track. Continue until such 11611367Ssam * we're done, or until there's less than a sector's 11711367Ssam * worth of data to transfer. 11811367Ssam * 11911367Ssam * The lseek call is necessary because of 12011367Ssam * the odd sector size (516 bytes) 12111367Ssam */ 12211367Ssam for (resid = tracksize, cbp = bp, sn = sector;;) { 12311367Ssam int cc; 12411367Ssam 12511367Ssam lseek(fd, sn * SECTSIZ, 0); 12611367Ssam ioctl(fd, SAIOHDR, (char *)0); 12711367Ssam cc = write(fd, cbp, resid); 12811367Ssam if (cc == resid) 12911367Ssam break; 13011367Ssam /* 13111367Ssam * Don't record errors during write, 13211367Ssam * all errors will be found during 13311367Ssam * writecheck performed below. 13411367Ssam */ 13511367Ssam sn = iob[fd - 3].i_errblk; 13611367Ssam cbp += sn - sector; 13711367Ssam resid -= (sn - sector) * sizeof (struct sector); 13811367Ssam if (resid < sizeof (struct sector)) 13911367Ssam break; 14011367Ssam } 14111367Ssam /* 14211367Ssam * Write check headers and test patterns. 14311367Ssam * Retry remainder of track on error until 14411367Ssam * we're done, or until there's less than a 14511367Ssam * sector to verify. 14611367Ssam */ 14711367Ssam for (resid = tracksize, cbp = bp, sn = sector;;) { 14811367Ssam int cc; 14911367Ssam 15011367Ssam lseek(fd, sn * SECTSIZ, 0); 15111367Ssam ioctl(fd, SAIOHCHECK, (char *)0); 15211367Ssam cc = read(fd, cbp, resid); 15311367Ssam if (cc == resid) 15411367Ssam break; 15511367Ssam sn = iob[fd-3].i_errblk; 15611367Ssam printf("sector %d, write check error\n", sn); 15711367Ssam recorderror(fd, sn, &st); 15811367Ssam /* advance past bad sector */ 15911367Ssam sn++; 16011367Ssam cbp += sn - sector; 16111367Ssam resid -= (sn - sector) * sizeof (struct sector); 16211367Ssam if (resid < sizeof (struct sector)) 16311367Ssam break; 16411367Ssam } 16511367Ssam } 16611367Ssam /* 16711367Ssam * Checking finished. 16811367Ssam */ 16911367Ssam if (errors[FE_TOTAL] || errors[FE_SSE]) { 17011367Ssam printf("Errors:\n"); 17111367Ssam for (i = 0; i < NERRORS; i++) 17211367Ssam printf("%s: %d\n", errornames[i], errors[i]); 17311367Ssam printf("Total of %d hard errors found\n", 17411367Ssam errors[FE_TOTAL] + errors[FE_SSE]); 17511367Ssam /* change the headers of all the bad sectors */ 17611367Ssam writebb(fd, errors[FE_SSE], &sstab, &st, SSERR); 17711367Ssam writebb(fd, errors[FE_TOTAL], &dkbad, &st, BSERR); 17811367Ssam } 17911367Ssam while (errors[FE_TOTAL] < MAXBADDESC) { 18011367Ssam int i = errors[FE_TOTAL]++; 18111367Ssam 18211367Ssam dkbad.bt_bad[i].bt_cyl = -1; 18311367Ssam dkbad.bt_bad[i].bt_trksec = -1; 18411367Ssam } 18511367Ssam printf("\nWriting bad sector table at sector #%d\n", 18611367Ssam st.ncyl * st.nspc - st.nsect); 18711367Ssam /* place on disk */ 18811367Ssam for (i = 0; i < 10; i += 2) { 18911367Ssam lseek(fd, SECTSIZ * (st.ncyl * st.nspc - st.nsect + i), 0); 19011367Ssam write(fd, &dkbad, sizeof (dkbad)); 19111367Ssam } 19211367Ssam printf("Done\n"); 19311367Ssam ioctl(fd,SAIONOSSI,(char *)0); 19411367Ssam close(fd); 19511367Ssam #ifndef JUSTEXIT 19611367Ssam goto again; 19711367Ssam #endif 19811367Ssam } 19911367Ssam 20011367Ssam /* 20111367Ssam * Write out the bad blocks. 20211367Ssam */ 20311367Ssam writebb(fd, nsects, dbad, st, sw) 20411367Ssam int nsects, fd; 20511367Ssam struct dkbad *dbad; 20611367Ssam register struct st *st; 20711367Ssam { 20811367Ssam struct sector bb_buf; /* buffer for one sector plus 4 byte header */ 20911367Ssam register int i; 21011367Ssam int bn, j; 21111367Ssam struct bt_bad *btp; 21211367Ssam 21311367Ssam for (i = 0; i < nsects; i++) { 21411367Ssam btp = &dbad->bt_bad[i]; 21511367Ssam if (sw == BSERR) { 21611367Ssam bb_buf.header1 = HDR1_FMT22|btp->bt_cyl; 21711367Ssam if (SSDEV) 21811367Ssam bb_buf.header1 |= HDR1_SSF; 21911367Ssam } else 22011367Ssam bb_buf.header1 = 22111367Ssam btp->bt_cyl | HDR1_FMT22 | HDR1_SSF | HDR1_OKSCT; 22211367Ssam bb_buf.header2 = btp->bt_trksec; 22311367Ssam bn = st->nspc * btp->bt_cyl + 22411367Ssam st->nsect * (btp->bt_trksec >> 8) + 22511367Ssam (btp->bt_trksec & 0x1f); 22611367Ssam lseek(fd, bn * SECTSIZ, 0); 22711367Ssam ioctl(fd, SAIOHDR, (char *)0); 22811367Ssam write(fd, &bb_buf, sizeof (bb_buf)); 22911367Ssam if (!SSDEV) 23011367Ssam continue; 23111367Ssam /* 23211367Ssam * If skip sector, mark all remaining 23311367Ssam * sectors on the track. 23411367Ssam */ 23511367Ssam for (j = (btp->bt_trksec & 0x1f) + 1; j < st->nsect; j++) { 23611367Ssam bb_buf.header1 = j | HDR1_FMT22 | HDR1_SSF; 23711367Ssam ioctl(fd, SAIOHDR, (char *)0); 23811367Ssam write(fd, &bb_buf, sizeof (bb_buf)); 23911367Ssam } 24011367Ssam } 24111367Ssam } 24211367Ssam 24311367Ssam /* 24411367Ssam * Record an error, and if there's room, put 24511367Ssam * it in the appropriate bad sector table. 24611367Ssam */ 24711367Ssam recorderror(fd, bn, st) 24811367Ssam int fd, bn; 24911367Ssam register struct st *st; 25011367Ssam { 25111367Ssam int cn, tn, sn, strk; 25211367Ssam 25311367Ssam if (errors[FE_TOTAL] >= MAXBADDESC) { 25411367Ssam printf("Too many bad sectors\n"); 25511367Ssam return; 25611367Ssam } 25711367Ssam if (errors[FE_SSE] >= MAXBADDESC) { 25811367Ssam printf("Too many skip sector errors\n"); 25911367Ssam return; 26011367Ssam } 26111367Ssam if (errno <= ECMD || errno > EHER) 26211367Ssam return; 26311367Ssam errors[errno]++; 26411367Ssam cn = bn / st->nspc; 26511367Ssam sn = bn % st->nspc; 26611367Ssam tn = sn / st->nsect; 26711367Ssam sn %= st->nsect; 26811367Ssam if (SSDEV) { /* if drive has skip sector capability */ 26911367Ssam int ss = errors[FE_SSE]++; 27011367Ssam 27111367Ssam if (ss) 27211367Ssam strk = sstab.bt_bad[ss - 1].bt_trksec >> 8; 27311367Ssam else 27411367Ssam strk = -1; 27511367Ssam if (tn != strk) { /* only one skip sector/track */ 27611367Ssam sstab.bt_bad[ss].bt_cyl = cn; 27711367Ssam sstab.bt_bad[ss].bt_trksec = (tn<<8) + sn; 27811367Ssam return; 27911367Ssam } 28011367Ssam cn = -cn; 28111367Ssam } 28211367Ssam /* record the bad sector address and continue */ 28311367Ssam dkbad.bt_bad[errors[FE_TOTAL]++].bt_cyl = cn; 28411367Ssam dkbad.bt_bad[errors[FE_TOTAL]++].bt_trksec = (tn << 8) + sn; 28511367Ssam } 28611367Ssam 28711367Ssam /* 28811367Ssam * Allocate memory on a page-aligned address. 28911367Ssam * Round allocated chunk to a page multiple to 29011367Ssam * ease next request. 29111367Ssam */ 29211367Ssam char * 29311367Ssam malloc(size) 29411367Ssam int size; 29511367Ssam { 29611367Ssam char *result; 29711367Ssam static caddr_t last = 0; 29811367Ssam 29911367Ssam if (last == 0) 30011367Ssam last = (caddr_t)(((int)&end + 511) & ~0x1ff); 30111367Ssam size = (size + 511) & ~0x1ff; 30211367Ssam result = (char *)last; 30311367Ssam last += size; 30411367Ssam return (result); 30511367Ssam } 30611367Ssam 30711367Ssam /* 30811367Ssam * Prompt and verify a device name from the user. 30911367Ssam */ 31011367Ssam getdevice() 31111367Ssam { 31211367Ssam register char *cp; 31311367Ssam register struct devsw *dp; 31411367Ssam int fd; 31511367Ssam 31611367Ssam top: 31711367Ssam cp = prompt("Device to format? "); 31811367Ssam if ((fd = open(cp, 2)) < 0) { 31911367Ssam printf("Known devices are: "); 32011367Ssam for (dp = devsw; dp->dv_name; dp++) 32111367Ssam printf("%s ",dp->dv_name); 32211367Ssam printf("\n"); 32311367Ssam goto top; 32411367Ssam } 32511367Ssam printf("Formatting drive %d on %c%c%d ", 32611367Ssam iob[fd - 3].i_unit % 8, cp[0], cp[1], iob[fd - 3].i_unit / 8); 32711367Ssam cp = prompt("verify (yes/no)? "); 32811367Ssam while (*cp != 'y' && *cp != 'n') 32911367Ssam cp = prompt("Huh, yes or no? "); 33011367Ssam if (*cp == 'y') 33111367Ssam return (fd); 33211367Ssam goto top; 33311367Ssam } 33411367Ssam 33511371Ssam static struct pattern { 33611371Ssam long pa_value; 33711371Ssam char *pa_name; 33811371Ssam } pat[] = { 33911371Ssam { 0xf00ff00f, "RH750 worst case" }, 34011371Ssam { 0xec6dec6d, "media worst case" }, 34111371Ssam { 0xa5a5a5a5, "alternate 1's and 0's" }, 34211371Ssam { 0, 0 }, 34311371Ssam }; 34411371Ssam 34511371Ssam getpattern() 34611371Ssam { 34711371Ssam register struct pattern *p; 34811371Ssam int npatterns; 34911371Ssam char *cp; 35011371Ssam 35111371Ssam printf("Available test patterns are:\n"); 35211371Ssam for (p = pat; p->pa_value; p++) 35311371Ssam printf("\t%d - (%x) %s\n", (p - pat) + 1, 35411371Ssam p->pa_value & 0xffff, p->pa_name); 35511371Ssam npatterns = p - pat; 35611371Ssam cp = prompt("Pattern (one of the above, other to restart)? "); 35711371Ssam pattern = atoi(cp) - 1; 35811371Ssam return (pattern < 0 || pattern >= npatterns); 35911371Ssam } 36011371Ssam 36111371Ssam struct xsect { 36211371Ssam u_short hd1; 36311371Ssam u_short hd2; 36411371Ssam long buf[128]; 36511371Ssam }; 36611371Ssam 36711371Ssam /* 36811371Ssam * Initialize the buffer with the requested pattern. 36911371Ssam */ 37011371Ssam bufinit(bp, size) 37111371Ssam register struct xsect *bp; 37211371Ssam int size; 37311371Ssam { 37411371Ssam register struct pattern *pptr; 37511371Ssam register long *pp, *last; 37611371Ssam register struct xsect *lastbuf; 37711371Ssam 37811371Ssam size /= sizeof (struct sector); 37911371Ssam lastbuf = bp + size; 38011371Ssam pptr = &pat[pattern]; 38111371Ssam while (bp < lastbuf) { 38211371Ssam last = &bp->buf[128]; 38311371Ssam for (pp = bp->buf; pp < last; pp++) 38411371Ssam *pp = pptr->pa_value; 38511371Ssam bp++; 38611371Ssam } 38711371Ssam } 38811371Ssam 38911367Ssam char * 39011367Ssam prompt(msg) 39111367Ssam char *msg; 39211367Ssam { 39311367Ssam static char buf[132]; 39411367Ssam 39511367Ssam printf("%s", msg); 39611367Ssam gets(buf); 39711367Ssam return (buf); 39811367Ssam } 399