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