123251Smckusick /* 223251Smckusick * Copyright (c) 1980 Regents of the University of California. 323251Smckusick * All rights reserved. The Berkeley software License Agreement 423251Smckusick * specifies the terms and conditions for redistribution. 523251Smckusick */ 611367Ssam 723251Smckusick #ifndef lint 823251Smckusick char copyright[] = 923251Smckusick "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 1023251Smckusick All rights reserved.\n"; 1123251Smckusick #endif not lint 1215051Skarels 1323251Smckusick #ifndef lint 14*25212Skarels static char sccsid[] = "@(#)format.c 6.6 (Berkeley) 10/15/85"; 1523251Smckusick #endif not lint 1623251Smckusick 17*25212Skarels 1811367Ssam /* 1911367Ssam * Standalone program to do media checking 2011367Ssam * and record bad block information on any 2115009Skarels * disk with the appropriate driver and RM03-style headers. 22*25212Skarels * TODO: 23*25212Skarels * add new bad sectors to bad-sector table when formatting by track 24*25212Skarels * (rearranging replacements ala bad144 -a) 25*25212Skarels * multi-pass format for disks with skip-sector capability 2611367Ssam */ 2711367Ssam #include "../h/param.h" 2811367Ssam #include "../h/fs.h" 2911367Ssam #include "../h/inode.h" 3011367Ssam #include "../h/dkbad.h" 3111367Ssam #include "../h/vmmac.h" 3211367Ssam 3311367Ssam #include "saio.h" 3411367Ssam #include "savax.h" 3511367Ssam 3611367Ssam #define MAXBADDESC 126 /* size of bad block table */ 3711367Ssam #define CHUNK 48 /* max # of sectors/io operation */ 3811367Ssam #define SECTSIZ 512 /* standard sector size */ 3911367Ssam #define HDRSIZ 4 /* number of bytes in sector header */ 4011367Ssam 4111367Ssam #define SSERR 0 4211367Ssam #define BSERR 1 4311367Ssam 4411367Ssam #define SSDEV ((ioctl(iob[fd-3], SAIOSSDEV, (char *)0) == 0)) 4511367Ssam 4611367Ssam struct sector { 4711367Ssam u_short header1; 4811367Ssam u_short header2; 4911367Ssam char buf[SECTSIZ]; 5011367Ssam }; 5111367Ssam 5211367Ssam struct dkbad dkbad; /* bad sector table */ 5311367Ssam struct dkbad sstab; /* skip sector table */ 5411367Ssam 5511367Ssam #define NERRORS 6 5611371Ssam static char * 5711371Ssam errornames[NERRORS] = { 5815009Skarels #define FE_BSE 0 5915009Skarels "Bad sector", 6015009Skarels #define FE_WCE 1 6111367Ssam "Write check", 6211367Ssam #define FE_ECC 2 6311367Ssam "ECC", 6411367Ssam #define FE_HARD 3 6511367Ssam "Other hard", 6611367Ssam #define FE_TOTAL 4 6711367Ssam "Total", 6811367Ssam #define FE_SSE 5 6911367Ssam "Skip sector", 7011367Ssam }; 7111367Ssam 7211367Ssam int errors[NERRORS]; /* histogram of errors */ 7311371Ssam int pattern; 7411367Ssam 7515051Skarels /* 7615051Skarels * Purdue/EE severe burnin patterns. 7715051Skarels */ 7815051Skarels unsigned short ppat[] = { 7917426Skarels 0xf00f, 0xec6d, 0031463,0070707,0133333,0155555,0161616,0143434, 8015051Skarels 0107070,0016161,0034343,0044444,0022222,0111111,0125252, 052525, 8115051Skarels 0125252,0125252,0125252,0125252,0125252,0125252,0125252,0125252, 8215051Skarels #ifndef SHORTPASS 8315051Skarels 0125252,0125252,0125252,0125252,0125252,0125252,0125252,0125252, 8415051Skarels 052525, 052525, 052525, 052525, 052525, 052525, 052525, 052525, 8515051Skarels #endif 8615051Skarels 052525, 052525, 052525, 052525, 052525, 052525, 052525, 052525 8715051Skarels }; 8815051Skarels 8915051Skarels #define NPT (sizeof (ppat) / sizeof (short)) 9017426Skarels int maxpass, npat; /* subscript to ppat[] */ 9115051Skarels int severe; /* nz if running "severe" burnin */ 92*25212Skarels int startcyl, endcyl, starttrack, endtrack; 9315051Skarels int nbads; /* subscript for bads */ 9415051Skarels long bads[MAXBADDESC]; /* Bad blocks accumulated */ 9515051Skarels 9611367Ssam char *malloc(); 9715051Skarels int qcompar(); 9811367Ssam char *prompt(); 99*25212Skarels daddr_t badsn(); 10011367Ssam extern int end; 10111367Ssam 10211367Ssam main() 10311367Ssam { 10411367Ssam register int sector, sn; 10515051Skarels int lastsector, tracksize, rtracksize; 10611367Ssam int unit, fd, resid, i, trk, cyl, debug; 10711367Ssam struct st st; 10811367Ssam struct sector *bp, *cbp; 10915051Skarels char *rbp, *rcbp; 11017426Skarels int pass; 11111367Ssam char *cp; 11211367Ssam 11311367Ssam printf("Disk format/check utility\n\n"); 11411367Ssam 11511367Ssam again: 11615051Skarels nbads = 0; 11715051Skarels cp = prompt("Enable debugging (0=none, 1=bse, 2=ecc, 3=bse+ecc)? "); 11811367Ssam debug = atoi(cp); 11911367Ssam if (debug < 0) 12011367Ssam debug = 0; 12111367Ssam for (i = 0; i < NERRORS; i++) 12211367Ssam errors[i] = 0; 12311367Ssam fd = getdevice(); 12411367Ssam ioctl(fd, SAIODEVDATA, &st); 12511367Ssam printf("Device data: #cylinders=%d, #tracks=%d, #sectors=%d\n", 12611367Ssam st.ncyl, st.ntrak, st.nsect); 127*25212Skarels getrange(&st); 12811371Ssam if (getpattern()) 12911367Ssam goto again; 13011367Ssam printf("Start formatting...make sure the drive is online\n"); 13115051Skarels if (severe) 13215051Skarels ioctl(fd, SAIOSEVRE, (char *) 0); 13311367Ssam ioctl(fd, SAIONOBAD, (char *)0); 13411367Ssam ioctl(fd, SAIOECCLIM, (char *)0); 13511367Ssam ioctl(fd, SAIODEBUG, (char *)debug); 13611367Ssam if (SSDEV) { 13715051Skarels if (severe) { 13815051Skarels printf("Severe burnin doesn't work with RM80 yet\n"); 13915051Skarels exit(1); 14015051Skarels } 14111367Ssam ioctl(fd, SAIOSSI, (char *)0); /* set skip sector inhibit */ 14211367Ssam st.nsect++; 14311367Ssam st.nspc += st.ntrak; 14411367Ssam } 14511367Ssam tracksize = sizeof (struct sector) * st.nsect; 14615051Skarels rtracksize = SECTSIZ * st.nsect; 14711367Ssam bp = (struct sector *)malloc(tracksize); 14815051Skarels rbp = malloc(rtracksize); 14917426Skarels pass = 0; 15017426Skarels npat = 0; 15117426Skarels more: 15217426Skarels for (; pass < maxpass; pass++) { 15315051Skarels if (severe) 15415051Skarels printf("Begin pass %d\n", pass); 15515051Skarels bufinit(bp, tracksize); 15615051Skarels if (severe) 15715051Skarels npat++; 15811367Ssam /* 15915051Skarels * Begin check, for each track, 16011367Ssam * 16115051Skarels * 1) Write header and test pattern. 16215051Skarels * 2) Read data. Hardware checks header and data ECC. 16317426Skarels * Read data (esp on Eagles) is much faster than write check. 16411367Ssam */ 165*25212Skarels sector = ((startcyl * st.ntrak) + starttrack) * st.nsect; 166*25212Skarels lastsector = ((endcyl * st.ntrak) + endtrack) * st.nsect 167*25212Skarels + st.nsect; 168*25212Skarels for ( ; sector < lastsector; sector += st.nsect) { 16915051Skarels cyl = sector / st.nspc; 17015051Skarels trk = (sector % st.nspc) / st.nsect; 17115051Skarels for (i = 0; i < st.nsect; i++) { 17215051Skarels bp[i].header1 = 17315051Skarels (u_short) cyl | HDR1_FMT22 | HDR1_OKSCT; 17415051Skarels bp[i].header2 = ((u_short)trk << 8) + i; 17515051Skarels } 17615051Skarels if (sector && (sector % (st.nspc * 100)) == 0) 17715051Skarels printf("cylinder %d\n", cyl); 17815051Skarels /* 17915051Skarels * Try and write the headers and data patterns into 18015051Skarels * each sector in the track. Continue until such 18115051Skarels * we're done, or until there's less than a sector's 18215051Skarels * worth of data to transfer. 18315051Skarels * 18415051Skarels * The lseek call is necessary because of 18515051Skarels * the odd sector size (516 bytes) 18615051Skarels */ 18715051Skarels for (resid = tracksize, cbp = bp, sn = sector;;) { 18815051Skarels int cc; 18911367Ssam 19015051Skarels lseek(fd, sn * SECTSIZ, 0); 19115051Skarels ioctl(fd, SAIOHDR, (char *)0); 19215051Skarels cc = write(fd, cbp, resid); 19315051Skarels if (cc == resid) 19415051Skarels break; 19515051Skarels /* 19615051Skarels * Don't record errors during write, 19715051Skarels * all errors will be found during 19815051Skarels * writecheck performed below. 19915051Skarels */ 20015051Skarels sn = iob[fd - 3].i_errblk; 20115051Skarels cbp += sn - sector; 20215051Skarels resid -= (sn - sector) * sizeof (struct sector); 20315051Skarels if (resid < sizeof (struct sector)) 20415051Skarels break; 20515051Skarels } 20611367Ssam /* 20715051Skarels * Read test patterns. 20815051Skarels * Retry remainder of track on error until 20915051Skarels * we're done, or until there's less than a 21015051Skarels * sector to verify. 21111367Ssam */ 21215051Skarels for (resid = rtracksize, rcbp = rbp, sn = sector;;) { 21315051Skarels int cc; 21411367Ssam 21515051Skarels lseek(fd, sn * SECTSIZ, 0); 21615051Skarels cc = read(fd, rcbp, resid); 21715051Skarels if (cc == resid) 21815051Skarels break; 21915051Skarels sn = iob[fd-3].i_errblk; 22015051Skarels printf("sector %d, read error\n", sn); 22115051Skarels if (recorderror(fd, sn, &st) < 0 && pass > 0) 22215051Skarels goto out; 22315051Skarels /* advance past bad sector */ 22415051Skarels sn++; 22515051Skarels rcbp += sn - sector; 22615051Skarels resid -= ((sn - sector) * SECTSIZ); 22715051Skarels if (resid < SECTSIZ) 22815051Skarels break; 22915051Skarels } 23011367Ssam } 23111367Ssam } 23211367Ssam /* 23311367Ssam * Checking finished. 23411367Ssam */ 23515051Skarels out: 23617426Skarels if (errors[FE_TOTAL] || errors[FE_SSE]) { 23717426Skarels printf("Errors:\n"); 23817426Skarels for (i = 0; i < NERRORS; i++) 23917426Skarels printf("%s: %d\n", errornames[i], errors[i]); 240*25212Skarels printf("Total of %d hard errors revectored\n", 24117426Skarels errors[FE_TOTAL] + errors[FE_SSE]); 24217426Skarels } 24317426Skarels if (severe && maxpass < NPT) { 24417426Skarels cp = prompt("More passes? (0 or number) "); 24517426Skarels maxpass = atoi(cp); 24617426Skarels if (maxpass > 0) { 24717426Skarels maxpass += pass; 24817426Skarels goto more; 24917426Skarels } 25017426Skarels } 25115051Skarels if (severe && nbads) { 25215051Skarels /* 25315051Skarels * Sort bads and insert in bad block table. 25415051Skarels */ 25515051Skarels qsort(bads, nbads, sizeof (long), qcompar); 25615051Skarels severe = 0; 25717426Skarels errno = 0; 25817426Skarels for (i = 0; i < nbads; i++) 25915051Skarels recorderror(fd, bads[i], &st); 26015051Skarels severe++; 26115051Skarels } 26211367Ssam if (errors[FE_TOTAL] || errors[FE_SSE]) { 26311367Ssam /* change the headers of all the bad sectors */ 26411367Ssam writebb(fd, errors[FE_SSE], &sstab, &st, SSERR); 26511367Ssam writebb(fd, errors[FE_TOTAL], &dkbad, &st, BSERR); 26611367Ssam } 267*25212Skarels if (endcyl == st.ncyl - 1 && 268*25212Skarels (startcyl < st.ncyl - 1 || starttrack == 0)) { 269*25212Skarels while (errors[FE_TOTAL] < MAXBADDESC) { 270*25212Skarels int i = errors[FE_TOTAL]++; 27111367Ssam 272*25212Skarels dkbad.bt_bad[i].bt_cyl = -1; 273*25212Skarels dkbad.bt_bad[i].bt_trksec = -1; 274*25212Skarels } 275*25212Skarels printf("\nWriting bad sector table at sector #%d\n", 276*25212Skarels st.ncyl * st.nspc - st.nsect); 277*25212Skarels /* place on disk */ 278*25212Skarels for (i = 0; i < 10 && i < st.nsect; i += 2) { 279*25212Skarels lseek(fd, SECTSIZ * (st.ncyl * st.nspc - st.nsect + i), 0); 280*25212Skarels write(fd, &dkbad, sizeof (dkbad)); 281*25212Skarels } 282*25212Skarels } else if (errors[FE_TOTAL]) { 283*25212Skarels struct bt_bad *bt; 284*25212Skarels 285*25212Skarels printf("New bad sectors (not added to table):\n"); 286*25212Skarels bt = dkbad.bt_bad; 287*25212Skarels for (i = 0; i < errors[FE_TOTAL]; i++) { 288*25212Skarels printf("sn %d (cn=%d, tn=%d, sn=%d)\n", badsn(bt, st), 289*25212Skarels bt->bt_cyl, bt->bt_trksec>>8, bt->bt_trksec&0xff); 290*25212Skarels bt++; 291*25212Skarels } 29211367Ssam } 29311367Ssam printf("Done\n"); 29411367Ssam ioctl(fd,SAIONOSSI,(char *)0); 29511367Ssam close(fd); 29611367Ssam #ifndef JUSTEXIT 29711367Ssam goto again; 29811367Ssam #endif 29911367Ssam } 30011367Ssam 30115051Skarels qcompar(l1, l2) 30215051Skarels register long *l1, *l2; 30315051Skarels { 30415051Skarels if (*l1 < *l2) 30515051Skarels return(-1); 30615051Skarels if (*l1 == *l2) 30715051Skarels return(0); 30815051Skarels return(1); 30915051Skarels } 31015051Skarels 311*25212Skarels daddr_t 312*25212Skarels badsn(bt, st) 313*25212Skarels register struct bt_bad *bt; 314*25212Skarels register struct st *st; 315*25212Skarels { 316*25212Skarels return ((bt->bt_cyl*st->ntrak + (bt->bt_trksec>>8)) * st->nsect 317*25212Skarels + (bt->bt_trksec&0xff)); 318*25212Skarels } 319*25212Skarels 32011367Ssam /* 321*25212Skarels * Mark the bad/skipped sectors. 322*25212Skarels * Bad sectors on skip-sector devices are assumed to be skipped also. 32311367Ssam */ 32411367Ssam writebb(fd, nsects, dbad, st, sw) 32511367Ssam int nsects, fd; 32611367Ssam struct dkbad *dbad; 32711367Ssam register struct st *st; 32811367Ssam { 32911367Ssam struct sector bb_buf; /* buffer for one sector plus 4 byte header */ 33011367Ssam register int i; 33111367Ssam int bn, j; 33211367Ssam struct bt_bad *btp; 33311367Ssam 33411367Ssam for (i = 0; i < nsects; i++) { 33511367Ssam btp = &dbad->bt_bad[i]; 33611367Ssam if (sw == BSERR) { 33711367Ssam bb_buf.header1 = HDR1_FMT22|btp->bt_cyl; 33811367Ssam if (SSDEV) 33911367Ssam bb_buf.header1 |= HDR1_SSF; 34011367Ssam } else 34111367Ssam bb_buf.header1 = 34211367Ssam btp->bt_cyl | HDR1_FMT22 | HDR1_SSF | HDR1_OKSCT; 34311367Ssam bb_buf.header2 = btp->bt_trksec; 34411367Ssam bn = st->nspc * btp->bt_cyl + 34511367Ssam st->nsect * (btp->bt_trksec >> 8) + 34615009Skarels (btp->bt_trksec & 0xff); 34711367Ssam lseek(fd, bn * SECTSIZ, 0); 34811367Ssam ioctl(fd, SAIOHDR, (char *)0); 34911367Ssam write(fd, &bb_buf, sizeof (bb_buf)); 35011367Ssam if (!SSDEV) 35111367Ssam continue; 35211367Ssam /* 35311367Ssam * If skip sector, mark all remaining 35411367Ssam * sectors on the track. 35511367Ssam */ 356*25212Skarels for (j = (btp->bt_trksec & 0xff) + 1, bn++; 357*25212Skarels j <= st->nsect; j++, bn++) { 358*25212Skarels bb_buf.header2 = j | (btp->bt_trksec & 0xff00); 359*25212Skarels lseek(fd, bn * SECTSIZ, 0); 36011367Ssam ioctl(fd, SAIOHDR, (char *)0); 36111367Ssam write(fd, &bb_buf, sizeof (bb_buf)); 36211367Ssam } 36311367Ssam } 36411367Ssam } 36511367Ssam 36611367Ssam /* 36711367Ssam * Record an error, and if there's room, put 36811367Ssam * it in the appropriate bad sector table. 36915051Skarels * 37015051Skarels * If severe burnin store block in a list after making sure 37115051Skarels * we have not already found it on a prev pass. 37211367Ssam */ 37311367Ssam recorderror(fd, bn, st) 37411367Ssam int fd, bn; 37511367Ssam register struct st *st; 37611367Ssam { 377*25212Skarels int cn, tn, sn; 37815051Skarels register i; 37911367Ssam 38015051Skarels 38115051Skarels if (severe) { 38215051Skarels for (i = 0; i < nbads; i++) 38315051Skarels if (bads[i] == bn) 38415051Skarels return(0); /* bn already flagged */ 38515051Skarels if (nbads >= MAXBADDESC) { 386*25212Skarels printf("Bad sector table full, format terminating\n"); 38715051Skarels return(-1); 38815051Skarels } 38915051Skarels bads[nbads++] = bn; 39017426Skarels if (errno < EBSE || errno > EHER) 39117426Skarels return(0); 39217426Skarels errno -= EBSE; 39317426Skarels errors[errno]++; 39415051Skarels return(0); 39515051Skarels } 39617426Skarels if (errno >= EBSE && errno <= EHER) { 39717426Skarels errno -= EBSE; 39817426Skarels errors[errno]++; 39911367Ssam } 40011367Ssam cn = bn / st->nspc; 40111367Ssam sn = bn % st->nspc; 40211367Ssam tn = sn / st->nsect; 40311367Ssam sn %= st->nsect; 40411367Ssam if (SSDEV) { /* if drive has skip sector capability */ 405*25212Skarels int ss = errors[FE_SSE]; 40611367Ssam 407*25212Skarels if (errors[FE_SSE] >= MAXBADDESC) { 408*25212Skarels /* this is bogus, we don't maintain skip sector table */ 409*25212Skarels printf("Too many skip sector errors\n"); 410*25212Skarels return(-1); 411*25212Skarels } 412*25212Skarels /* only one skip sector/track */ 413*25212Skarels if (ss == 0 || 414*25212Skarels tn != (sstab.bt_bad[ss - 1].bt_trksec >> 8) || 415*25212Skarels cn != sstab.bt_bad[ss - 1].bt_cyl) { 41611367Ssam sstab.bt_bad[ss].bt_cyl = cn; 41711367Ssam sstab.bt_bad[ss].bt_trksec = (tn<<8) + sn; 418*25212Skarels errors[FE_SSE]++; 419*25212Skarels return(0); 42011367Ssam } 42111367Ssam } 422*25212Skarels if (errors[FE_TOTAL] >= MAXBADDESC) { 423*25212Skarels printf("Too many bad sectors\n"); 424*25212Skarels return(-1); 425*25212Skarels } 42611367Ssam /* record the bad sector address and continue */ 42715009Skarels dkbad.bt_bad[errors[FE_TOTAL]].bt_cyl = cn; 42811367Ssam dkbad.bt_bad[errors[FE_TOTAL]++].bt_trksec = (tn << 8) + sn; 42915051Skarels return(0); 43011367Ssam } 43111367Ssam 43211367Ssam /* 43311367Ssam * Allocate memory on a page-aligned address. 43411367Ssam * Round allocated chunk to a page multiple to 43511367Ssam * ease next request. 43611367Ssam */ 43711367Ssam char * 43811367Ssam malloc(size) 43911367Ssam int size; 44011367Ssam { 44111367Ssam char *result; 44211367Ssam static caddr_t last = 0; 44311367Ssam 44411367Ssam if (last == 0) 44511367Ssam last = (caddr_t)(((int)&end + 511) & ~0x1ff); 44611367Ssam size = (size + 511) & ~0x1ff; 44711367Ssam result = (char *)last; 44811367Ssam last += size; 44911367Ssam return (result); 45011367Ssam } 45111367Ssam 45211367Ssam /* 45311367Ssam * Prompt and verify a device name from the user. 45411367Ssam */ 45511367Ssam getdevice() 45611367Ssam { 45711367Ssam register char *cp; 45811367Ssam register struct devsw *dp; 45911367Ssam int fd; 46011367Ssam 46111367Ssam top: 46211367Ssam cp = prompt("Device to format? "); 46311367Ssam if ((fd = open(cp, 2)) < 0) { 46411367Ssam printf("Known devices are: "); 46511367Ssam for (dp = devsw; dp->dv_name; dp++) 46611367Ssam printf("%s ",dp->dv_name); 46711367Ssam printf("\n"); 46811367Ssam goto top; 46911367Ssam } 47015051Skarels printf("Formatting drive %c%c%d on adaptor %d: ", 47115051Skarels cp[0], cp[1], iob[fd - 3].i_unit % 8, iob[fd - 3].i_unit / 8); 47211367Ssam cp = prompt("verify (yes/no)? "); 47311367Ssam while (*cp != 'y' && *cp != 'n') 47411367Ssam cp = prompt("Huh, yes or no? "); 47511367Ssam if (*cp == 'y') 47611367Ssam return (fd); 47711367Ssam goto top; 47811367Ssam } 47911367Ssam 480*25212Skarels /* 481*25212Skarels * Find range of tracks to format. 482*25212Skarels */ 483*25212Skarels getrange(st) 484*25212Skarels struct st *st; 485*25212Skarels { 486*25212Skarels startcyl = getnum("Starting cylinder", 0, st->ncyl - 1, 0); 487*25212Skarels endcyl = getnum("Ending cylinder", 0, st->ncyl - 1, st->ncyl - 1); 488*25212Skarels starttrack = getnum("Starting track", 0, st->ntrak - 1, 0); 489*25212Skarels endtrack = getnum("Ending track", 0, st->ntrak - 1, st->ntrak - 1); 490*25212Skarels } 491*25212Skarels 492*25212Skarels getnum(s, low, high, dflt) 493*25212Skarels { 494*25212Skarels char buf[132]; 495*25212Skarels unsigned val; 496*25212Skarels 497*25212Skarels while (1) { 498*25212Skarels printf("%s (%d): ", s, dflt); 499*25212Skarels gets(buf); 500*25212Skarels if (buf[0] == 0) 501*25212Skarels return (dflt); 502*25212Skarels val = atoi(buf); 503*25212Skarels if (val >= low && val <= high) 504*25212Skarels return ((int)val); 505*25212Skarels printf("Value must be in range [%d,%d]\n", low, high); 506*25212Skarels } 507*25212Skarels } 508*25212Skarels 50911371Ssam static struct pattern { 51011371Ssam long pa_value; 51111371Ssam char *pa_name; 51211371Ssam } pat[] = { 51311371Ssam { 0xf00ff00f, "RH750 worst case" }, 51411371Ssam { 0xec6dec6d, "media worst case" }, 51511371Ssam { 0xa5a5a5a5, "alternate 1's and 0's" }, 51617426Skarels { 0xFFFFFFFF, "Severe burnin (up to 48 passes)" }, 51711371Ssam { 0, 0 }, 51811371Ssam }; 51911371Ssam 52011371Ssam getpattern() 52111371Ssam { 52211371Ssam register struct pattern *p; 52311371Ssam int npatterns; 52411371Ssam char *cp; 52511371Ssam 52611371Ssam printf("Available test patterns are:\n"); 52711371Ssam for (p = pat; p->pa_value; p++) 52811371Ssam printf("\t%d - (%x) %s\n", (p - pat) + 1, 52911371Ssam p->pa_value & 0xffff, p->pa_name); 53011371Ssam npatterns = p - pat; 53111371Ssam cp = prompt("Pattern (one of the above, other to restart)? "); 53211371Ssam pattern = atoi(cp) - 1; 53317426Skarels if (pattern < 0 || pattern >= npatterns) 53417426Skarels return(1); 53515051Skarels severe = 0; 53617426Skarels maxpass = 1; 53717426Skarels if (pat[pattern].pa_value == -1) { 53815051Skarels severe = 1; 53917426Skarels cp = prompt("How many passes (up to 48)? "); 54017426Skarels maxpass = atoi(cp); 54117426Skarels if (maxpass > NPT) 54217426Skarels maxpass = NPT; 54317426Skarels } 54417426Skarels return (0); 54511371Ssam } 54611371Ssam 54711371Ssam struct xsect { 54811371Ssam u_short hd1; 54911371Ssam u_short hd2; 55011371Ssam long buf[128]; 55111371Ssam }; 55211371Ssam 55311371Ssam /* 55411371Ssam * Initialize the buffer with the requested pattern. 55511371Ssam */ 55611371Ssam bufinit(bp, size) 55711371Ssam register struct xsect *bp; 55811371Ssam int size; 55911371Ssam { 56011371Ssam register struct pattern *pptr; 56111371Ssam register long *pp, *last; 56211371Ssam register struct xsect *lastbuf; 56315051Skarels int patt; 56411371Ssam 56511371Ssam size /= sizeof (struct sector); 56611371Ssam lastbuf = bp + size; 56715051Skarels if (severe) { 56815051Skarels patt = ppat[npat] | ((long)ppat[npat] << 16); 56915051Skarels printf("Write pattern 0x%x\n", patt&0xffff); 57015051Skarels } else { 57115051Skarels pptr = &pat[pattern]; 57215051Skarels patt = pptr->pa_value; 57315051Skarels } 57411371Ssam while (bp < lastbuf) { 57511371Ssam last = &bp->buf[128]; 57611371Ssam for (pp = bp->buf; pp < last; pp++) 57715051Skarels *pp = patt; 57811371Ssam bp++; 57911371Ssam } 58011371Ssam } 58111371Ssam 58211367Ssam char * 58311367Ssam prompt(msg) 58411367Ssam char *msg; 58511367Ssam { 58611367Ssam static char buf[132]; 58711367Ssam 58811367Ssam printf("%s", msg); 58911367Ssam gets(buf); 59011367Ssam return (buf); 59111367Ssam } 592