1*11367Ssam /* format.c 4.1 83/03/01 */ 2*11367Ssam 3*11367Ssam /* 4*11367Ssam * Standalone program to do media checking 5*11367Ssam * and record bad block information on any 6*11367Ssam * disk with the appropriate driver. 7*11367Ssam */ 8*11367Ssam #include "../h/param.h" 9*11367Ssam #include "../h/fs.h" 10*11367Ssam #include "../h/inode.h" 11*11367Ssam #include "../h/dkbad.h" 12*11367Ssam #include "../h/vmmac.h" 13*11367Ssam 14*11367Ssam #include "saio.h" 15*11367Ssam #include "savax.h" 16*11367Ssam 17*11367Ssam #define MAXBADDESC 126 /* size of bad block table */ 18*11367Ssam #define CHUNK 48 /* max # of sectors/io operation */ 19*11367Ssam #define SECTSIZ 512 /* standard sector size */ 20*11367Ssam #define HDRSIZ 4 /* number of bytes in sector header */ 21*11367Ssam 22*11367Ssam #define SSERR 0 23*11367Ssam #define BSERR 1 24*11367Ssam 25*11367Ssam #define SSDEV ((ioctl(iob[fd-3], SAIOSSDEV, (char *)0) == 0)) 26*11367Ssam 27*11367Ssam struct sector { 28*11367Ssam u_short header1; 29*11367Ssam u_short header2; 30*11367Ssam char buf[SECTSIZ]; 31*11367Ssam }; 32*11367Ssam 33*11367Ssam struct dkbad dkbad; /* bad sector table */ 34*11367Ssam struct dkbad sstab; /* skip sector table */ 35*11367Ssam 36*11367Ssam #define NERRORS 6 37*11367Ssam char *errornames[NERRORS] = { 38*11367Ssam #define FE_WCE 0 39*11367Ssam "Write check", 40*11367Ssam #define FE_BSE 1 41*11367Ssam "Bad sector", 42*11367Ssam #define FE_ECC 2 43*11367Ssam "ECC", 44*11367Ssam #define FE_HARD 3 45*11367Ssam "Other hard", 46*11367Ssam #define FE_TOTAL 4 47*11367Ssam "Total", 48*11367Ssam #define FE_SSE 5 49*11367Ssam "Skip sector", 50*11367Ssam }; 51*11367Ssam 52*11367Ssam int errors[NERRORS]; /* histogram of errors */ 53*11367Ssam 54*11367Ssam char *malloc(); 55*11367Ssam char *prompt(); 56*11367Ssam extern int end; 57*11367Ssam 58*11367Ssam main() 59*11367Ssam { 60*11367Ssam register int sector, sn; 61*11367Ssam int pattern, lastsector, tracksize; 62*11367Ssam int unit, fd, resid, i, trk, cyl, debug; 63*11367Ssam struct st st; 64*11367Ssam struct sector *bp, *cbp; 65*11367Ssam char *cp; 66*11367Ssam 67*11367Ssam printf("Disk format/check utility\n\n"); 68*11367Ssam 69*11367Ssam again: 70*11367Ssam cp = prompt("Enable debugging (1=bse, 2=ecc, 3=bse+ecc)? "); 71*11367Ssam debug = atoi(cp); 72*11367Ssam if (debug < 0) 73*11367Ssam debug = 0; 74*11367Ssam for (i = 0; i < NERRORS; i++) 75*11367Ssam errors[i] = 0; 76*11367Ssam fd = getdevice(); 77*11367Ssam ioctl(fd, SAIODEVDATA, &st); 78*11367Ssam printf("Device data: #cylinders=%d, #tracks=%d, #sectors=%d\n", 79*11367Ssam st.ncyl, st.ntrak, st.nsect); 80*11367Ssam printf("Available test patterns are:\n"); 81*11367Ssam printf("\t0 - (f00f) RH750 worst case\n"); 82*11367Ssam printf("\t1 - (ec6d) media worst case\n"); 83*11367Ssam printf("\t2 - (a5a5) alternate 1's & 0's\n"); 84*11367Ssam cp = prompt("Pattern (0, 1, 2, other to restart)? "); 85*11367Ssam pattern = atoi(cp); 86*11367Ssam if (pattern < 0 || pattern > 2) 87*11367Ssam goto again; 88*11367Ssam printf("Start formatting...make sure the drive is online\n"); 89*11367Ssam ioctl(fd, SAIONOBAD, (char *)0); 90*11367Ssam ioctl(fd, SAIOECCLIM, (char *)0); 91*11367Ssam ioctl(fd, SAIODEBUG, (char *)debug); 92*11367Ssam if (SSDEV) { 93*11367Ssam ioctl(fd, SAIOSSI, (char *)0); /* set skip sector inhibit */ 94*11367Ssam st.nsect++; 95*11367Ssam st.nspc += st.ntrak; 96*11367Ssam } 97*11367Ssam tracksize = sizeof (struct sector) * st.nsect; 98*11367Ssam bp = (struct sector *)malloc(tracksize); 99*11367Ssam bufinit(bp, tracksize, pattern); 100*11367Ssam /* 101*11367Ssam * Begin check, for each track, 102*11367Ssam * 103*11367Ssam * 1) Write header and test pattern. 104*11367Ssam * 2) Write check header and data. 105*11367Ssam */ 106*11367Ssam lastsector = st.nspc * st.ncyl; 107*11367Ssam for (sector = 0; sector < lastsector; sector += st.nsect) { 108*11367Ssam cyl = sector / st.nspc; 109*11367Ssam trk = (sector % st.nspc) / st.nsect; 110*11367Ssam for (i = 0; i < st.nsect; i++) { 111*11367Ssam bp[i].header1 = 112*11367Ssam (u_short) cyl | HDR1_FMT22 | HDR1_OKSCT; 113*11367Ssam bp[i].header2 = ((u_short)trk << 8) + i; 114*11367Ssam } 115*11367Ssam if (sector && (sector % (st.nspc * 10)) == 0) 116*11367Ssam printf("sector %d\n", sector); 117*11367Ssam /* 118*11367Ssam * Try and write the headers and data patterns into 119*11367Ssam * each sector in the track. Continue until such 120*11367Ssam * we're done, or until there's less than a sector's 121*11367Ssam * worth of data to transfer. 122*11367Ssam * 123*11367Ssam * The lseek call is necessary because of 124*11367Ssam * the odd sector size (516 bytes) 125*11367Ssam */ 126*11367Ssam for (resid = tracksize, cbp = bp, sn = sector;;) { 127*11367Ssam int cc; 128*11367Ssam 129*11367Ssam lseek(fd, sn * SECTSIZ, 0); 130*11367Ssam ioctl(fd, SAIOHDR, (char *)0); 131*11367Ssam cc = write(fd, cbp, resid); 132*11367Ssam if (cc == resid) 133*11367Ssam break; 134*11367Ssam /* 135*11367Ssam * Don't record errors during write, 136*11367Ssam * all errors will be found during 137*11367Ssam * writecheck performed below. 138*11367Ssam */ 139*11367Ssam sn = iob[fd - 3].i_errblk; 140*11367Ssam cbp += sn - sector; 141*11367Ssam resid -= (sn - sector) * sizeof (struct sector); 142*11367Ssam if (resid < sizeof (struct sector)) 143*11367Ssam break; 144*11367Ssam } 145*11367Ssam /* 146*11367Ssam * Write check headers and test patterns. 147*11367Ssam * Retry remainder of track on error until 148*11367Ssam * we're done, or until there's less than a 149*11367Ssam * sector to verify. 150*11367Ssam */ 151*11367Ssam for (resid = tracksize, cbp = bp, sn = sector;;) { 152*11367Ssam int cc; 153*11367Ssam 154*11367Ssam lseek(fd, sn * SECTSIZ, 0); 155*11367Ssam ioctl(fd, SAIOHCHECK, (char *)0); 156*11367Ssam cc = read(fd, cbp, resid); 157*11367Ssam if (cc == resid) 158*11367Ssam break; 159*11367Ssam sn = iob[fd-3].i_errblk; 160*11367Ssam printf("sector %d, write check error\n", sn); 161*11367Ssam recorderror(fd, sn, &st); 162*11367Ssam /* advance past bad sector */ 163*11367Ssam sn++; 164*11367Ssam cbp += sn - sector; 165*11367Ssam resid -= (sn - sector) * sizeof (struct sector); 166*11367Ssam if (resid < sizeof (struct sector)) 167*11367Ssam break; 168*11367Ssam } 169*11367Ssam } 170*11367Ssam /* 171*11367Ssam * Checking finished. 172*11367Ssam */ 173*11367Ssam if (errors[FE_TOTAL] || errors[FE_SSE]) { 174*11367Ssam printf("Errors:\n"); 175*11367Ssam for (i = 0; i < NERRORS; i++) 176*11367Ssam printf("%s: %d\n", errornames[i], errors[i]); 177*11367Ssam printf("Total of %d hard errors found\n", 178*11367Ssam errors[FE_TOTAL] + errors[FE_SSE]); 179*11367Ssam /* change the headers of all the bad sectors */ 180*11367Ssam writebb(fd, errors[FE_SSE], &sstab, &st, SSERR); 181*11367Ssam writebb(fd, errors[FE_TOTAL], &dkbad, &st, BSERR); 182*11367Ssam } 183*11367Ssam while (errors[FE_TOTAL] < MAXBADDESC) { 184*11367Ssam int i = errors[FE_TOTAL]++; 185*11367Ssam 186*11367Ssam dkbad.bt_bad[i].bt_cyl = -1; 187*11367Ssam dkbad.bt_bad[i].bt_trksec = -1; 188*11367Ssam } 189*11367Ssam printf("\nWriting bad sector table at sector #%d\n", 190*11367Ssam st.ncyl * st.nspc - st.nsect); 191*11367Ssam /* place on disk */ 192*11367Ssam for (i = 0; i < 10; i += 2) { 193*11367Ssam lseek(fd, SECTSIZ * (st.ncyl * st.nspc - st.nsect + i), 0); 194*11367Ssam write(fd, &dkbad, sizeof (dkbad)); 195*11367Ssam } 196*11367Ssam printf("Done\n"); 197*11367Ssam ioctl(fd,SAIONOSSI,(char *)0); 198*11367Ssam close(fd); 199*11367Ssam #ifndef JUSTEXIT 200*11367Ssam goto again; 201*11367Ssam #endif 202*11367Ssam } 203*11367Ssam 204*11367Ssam static struct pat { 205*11367Ssam long pt[2]; 206*11367Ssam } pat[3] = { 207*11367Ssam { 0xf00ff00f, 0xf00ff00f }, /* worst case for RH750 */ 208*11367Ssam { 0xec6dec6d, 0xec6dec6d }, /* worst case for media */ 209*11367Ssam { 0xa5a5a5a5, 0xa5a5a5a5 } 210*11367Ssam }; 211*11367Ssam 212*11367Ssam struct xsect { 213*11367Ssam u_short hd1; 214*11367Ssam u_short hd2; 215*11367Ssam struct pat buf[64]; 216*11367Ssam }; 217*11367Ssam 218*11367Ssam /* 219*11367Ssam * Initialize the buffer with the requested pattern. 220*11367Ssam */ 221*11367Ssam bufinit(bufptr, size, pattern) 222*11367Ssam register struct xsect bufptr[]; 223*11367Ssam int size, pattern; 224*11367Ssam { 225*11367Ssam register struct pat *pptr; 226*11367Ssam 227*11367Ssam int i, j; 228*11367Ssam 229*11367Ssam size /= sizeof (struct sector); 230*11367Ssam pptr = &pat[pattern]; 231*11367Ssam for (i = 0; i < size; i++) 232*11367Ssam for (j = 0; j < 64; j++) 233*11367Ssam bufptr[i].buf[j] = *pptr; 234*11367Ssam } 235*11367Ssam 236*11367Ssam /* 237*11367Ssam * Write out the bad blocks. 238*11367Ssam */ 239*11367Ssam writebb(fd, nsects, dbad, st, sw) 240*11367Ssam int nsects, fd; 241*11367Ssam struct dkbad *dbad; 242*11367Ssam register struct st *st; 243*11367Ssam { 244*11367Ssam struct sector bb_buf; /* buffer for one sector plus 4 byte header */ 245*11367Ssam register int i; 246*11367Ssam int bn, j; 247*11367Ssam struct bt_bad *btp; 248*11367Ssam 249*11367Ssam for (i = 0; i < nsects; i++) { 250*11367Ssam btp = &dbad->bt_bad[i]; 251*11367Ssam if (sw == BSERR) { 252*11367Ssam bb_buf.header1 = HDR1_FMT22|btp->bt_cyl; 253*11367Ssam if (SSDEV) 254*11367Ssam bb_buf.header1 |= HDR1_SSF; 255*11367Ssam } else 256*11367Ssam bb_buf.header1 = 257*11367Ssam btp->bt_cyl | HDR1_FMT22 | HDR1_SSF | HDR1_OKSCT; 258*11367Ssam bb_buf.header2 = btp->bt_trksec; 259*11367Ssam bn = st->nspc * btp->bt_cyl + 260*11367Ssam st->nsect * (btp->bt_trksec >> 8) + 261*11367Ssam (btp->bt_trksec & 0x1f); 262*11367Ssam lseek(fd, bn * SECTSIZ, 0); 263*11367Ssam ioctl(fd, SAIOHDR, (char *)0); 264*11367Ssam write(fd, &bb_buf, sizeof (bb_buf)); 265*11367Ssam if (!SSDEV) 266*11367Ssam continue; 267*11367Ssam /* 268*11367Ssam * If skip sector, mark all remaining 269*11367Ssam * sectors on the track. 270*11367Ssam */ 271*11367Ssam for (j = (btp->bt_trksec & 0x1f) + 1; j < st->nsect; j++) { 272*11367Ssam bb_buf.header1 = j | HDR1_FMT22 | HDR1_SSF; 273*11367Ssam ioctl(fd, SAIOHDR, (char *)0); 274*11367Ssam write(fd, &bb_buf, sizeof (bb_buf)); 275*11367Ssam } 276*11367Ssam } 277*11367Ssam } 278*11367Ssam 279*11367Ssam /* 280*11367Ssam * Record an error, and if there's room, put 281*11367Ssam * it in the appropriate bad sector table. 282*11367Ssam */ 283*11367Ssam recorderror(fd, bn, st) 284*11367Ssam int fd, bn; 285*11367Ssam register struct st *st; 286*11367Ssam { 287*11367Ssam int cn, tn, sn, strk; 288*11367Ssam 289*11367Ssam if (errors[FE_TOTAL] >= MAXBADDESC) { 290*11367Ssam printf("Too many bad sectors\n"); 291*11367Ssam return; 292*11367Ssam } 293*11367Ssam if (errors[FE_SSE] >= MAXBADDESC) { 294*11367Ssam printf("Too many skip sector errors\n"); 295*11367Ssam return; 296*11367Ssam } 297*11367Ssam if (errno <= ECMD || errno > EHER) 298*11367Ssam return; 299*11367Ssam errors[errno]++; 300*11367Ssam cn = bn / st->nspc; 301*11367Ssam sn = bn % st->nspc; 302*11367Ssam tn = sn / st->nsect; 303*11367Ssam sn %= st->nsect; 304*11367Ssam if (SSDEV) { /* if drive has skip sector capability */ 305*11367Ssam int ss = errors[FE_SSE]++; 306*11367Ssam 307*11367Ssam if (ss) 308*11367Ssam strk = sstab.bt_bad[ss - 1].bt_trksec >> 8; 309*11367Ssam else 310*11367Ssam strk = -1; 311*11367Ssam if (tn != strk) { /* only one skip sector/track */ 312*11367Ssam sstab.bt_bad[ss].bt_cyl = cn; 313*11367Ssam sstab.bt_bad[ss].bt_trksec = (tn<<8) + sn; 314*11367Ssam return; 315*11367Ssam } 316*11367Ssam cn = -cn; 317*11367Ssam } 318*11367Ssam /* record the bad sector address and continue */ 319*11367Ssam dkbad.bt_bad[errors[FE_TOTAL]++].bt_cyl = cn; 320*11367Ssam dkbad.bt_bad[errors[FE_TOTAL]++].bt_trksec = (tn << 8) + sn; 321*11367Ssam } 322*11367Ssam 323*11367Ssam /* 324*11367Ssam * Allocate memory on a page-aligned address. 325*11367Ssam * Round allocated chunk to a page multiple to 326*11367Ssam * ease next request. 327*11367Ssam */ 328*11367Ssam char * 329*11367Ssam malloc(size) 330*11367Ssam int size; 331*11367Ssam { 332*11367Ssam char *result; 333*11367Ssam static caddr_t last = 0; 334*11367Ssam 335*11367Ssam if (last == 0) 336*11367Ssam last = (caddr_t)(((int)&end + 511) & ~0x1ff); 337*11367Ssam size = (size + 511) & ~0x1ff; 338*11367Ssam result = (char *)last; 339*11367Ssam last += size; 340*11367Ssam return (result); 341*11367Ssam } 342*11367Ssam 343*11367Ssam /* 344*11367Ssam * Prompt and verify a device name from the user. 345*11367Ssam */ 346*11367Ssam getdevice() 347*11367Ssam { 348*11367Ssam register char *cp; 349*11367Ssam register struct devsw *dp; 350*11367Ssam int fd; 351*11367Ssam 352*11367Ssam top: 353*11367Ssam cp = prompt("Device to format? "); 354*11367Ssam if ((fd = open(cp, 2)) < 0) { 355*11367Ssam printf("Known devices are: "); 356*11367Ssam for (dp = devsw; dp->dv_name; dp++) 357*11367Ssam printf("%s ",dp->dv_name); 358*11367Ssam printf("\n"); 359*11367Ssam goto top; 360*11367Ssam } 361*11367Ssam printf("Formatting drive %d on %c%c%d ", 362*11367Ssam iob[fd - 3].i_unit % 8, cp[0], cp[1], iob[fd - 3].i_unit / 8); 363*11367Ssam printf("will destroy everything on the disk, "); 364*11367Ssam cp = prompt("verify (yes/no)? "); 365*11367Ssam while (*cp != 'y' && *cp != 'n') 366*11367Ssam cp = prompt("Huh, yes or no? "); 367*11367Ssam if (*cp == 'y') 368*11367Ssam return (fd); 369*11367Ssam goto top; 370*11367Ssam } 371*11367Ssam 372*11367Ssam char * 373*11367Ssam prompt(msg) 374*11367Ssam char *msg; 375*11367Ssam { 376*11367Ssam static char buf[132]; 377*11367Ssam 378*11367Ssam printf("%s", msg); 379*11367Ssam gets(buf); 380*11367Ssam return (buf); 381*11367Ssam } 382