1 /* 2 * Copyright (c) 1980,1986,1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1980,1986,1988 Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif not lint 13 14 #ifndef lint 15 static char sccsid[] = "@(#)bad144.c 5.19 (Berkeley) 04/11/91"; 16 #endif not lint 17 18 /* 19 * bad144 20 * 21 * This program prints and/or initializes a bad block record for a pack, 22 * in the format used by the DEC standard 144. 23 * It can also add bad sector(s) to the record, moving the sector 24 * replacements as necessary. 25 * 26 * It is preferable to write the bad information with a standard formatter, 27 * but this program will do. 28 * 29 * RP06 sectors are marked as bad by inverting the format bit in the 30 * header; on other drives the valid-sector bit is cleared. 31 */ 32 #include <sys/param.h> 33 #include <sys/dkbad.h> 34 #include <sys/ioctl.h> 35 #include <ufs/fs.h> 36 #include <sys/file.h> 37 #include <sys/disklabel.h> 38 39 #include <stdio.h> 40 #include <paths.h> 41 42 #define RETRIES 10 /* number of retries on reading old sectors */ 43 #define RAWPART "c" /* disk partition containing badsector tables */ 44 45 int fflag, add, copy, verbose, nflag; 46 int compare(); 47 int dups; 48 int badfile = -1; /* copy of badsector table to use, -1 if any */ 49 #define MAXSECSIZE 1024 50 struct dkbad curbad, oldbad; 51 #define DKBAD_MAGIC 0 52 53 char label[BBSIZE]; 54 daddr_t size, getold(), badsn(); 55 struct disklabel *dp; 56 char name[BUFSIZ]; 57 char *malloc(); 58 off_t lseek(); 59 60 main(argc, argv) 61 int argc; 62 char *argv[]; 63 { 64 register struct bt_bad *bt; 65 daddr_t sn, bn[126]; 66 int i, f, nbad, new, bad, errs; 67 68 argc--, argv++; 69 while (argc > 0 && **argv == '-') { 70 (*argv)++; 71 while (**argv) { 72 switch (**argv) { 73 #if vax 74 case 'f': 75 fflag++; 76 break; 77 #endif 78 case 'a': 79 add++; 80 break; 81 case 'c': 82 copy++; 83 break; 84 case 'v': 85 verbose++; 86 break; 87 case 'n': 88 nflag++; 89 verbose++; 90 break; 91 default: 92 if (**argv >= '0' && **argv <= '4') { 93 badfile = **argv - '0'; 94 break; 95 } 96 goto usage; 97 } 98 (*argv)++; 99 } 100 argc--, argv++; 101 } 102 if (argc < 1) { 103 usage: 104 fprintf(stderr, 105 "usage: bad144 [ -f ] disk [ snum [ bn ... ] ]\n"); 106 fprintf(stderr, 107 "to read or overwrite bad-sector table, e.g.: bad144 hp0\n"); 108 fprintf(stderr, 109 "or bad144 -a [ -f ] [ -c ] disk bn ...\n"); 110 fprintf(stderr, "where options are:\n"); 111 fprintf(stderr, "\t-a add new bad sectors to the table\n"); 112 fprintf(stderr, "\t-f reformat listed sectors as bad\n"); 113 fprintf(stderr, "\t-c copy original sector to replacement\n"); 114 exit(1); 115 } 116 if (argv[0][0] != '/') 117 (void)sprintf(name, "%s/r%s%s", _PATH_DEV, argv[0], RAWPART); 118 else 119 strcpy(name, argv[0]); 120 f = open(name, argc == 1? O_RDONLY : O_RDWR); 121 if (f < 0) 122 Perror(name); 123 if (read(f, label, sizeof(label)) < 0) 124 Perror("read"); 125 for (dp = (struct disklabel *)(label + LABELOFFSET); 126 dp < (struct disklabel *) 127 (label + sizeof(label) - sizeof(struct disklabel)); 128 dp = (struct disklabel *)((char *)dp + 64)) 129 if (dp->d_magic == DISKMAGIC && dp->d_magic2 == DISKMAGIC) 130 break; 131 if (dp->d_magic != DISKMAGIC || dp->d_magic2 != DISKMAGIC) { 132 fprintf(stderr, "Bad pack magic number (pack is unlabeled)\n"); 133 exit(1); 134 } 135 if (dp->d_secsize > MAXSECSIZE || dp->d_secsize <= 0) { 136 fprintf(stderr, "Disk sector size too large/small (%d)\n", 137 dp->d_secsize); 138 exit(7); 139 } 140 size = dp->d_nsectors * dp->d_ntracks * dp->d_ncylinders; 141 argc--; 142 argv++; 143 if (argc == 0) { 144 sn = getold(f, &oldbad); 145 printf("bad block information at sector %d in %s:\n", 146 sn, name); 147 printf("cartridge serial number: %d(10)\n", oldbad.bt_csn); 148 switch (oldbad.bt_flag) { 149 150 case (u_short)-1: 151 printf("alignment cartridge\n"); 152 break; 153 154 case DKBAD_MAGIC: 155 break; 156 157 default: 158 printf("bt_flag=%x(16)?\n", oldbad.bt_flag); 159 break; 160 } 161 bt = oldbad.bt_bad; 162 for (i = 0; i < 126; i++) { 163 bad = (bt->bt_cyl<<16) + bt->bt_trksec; 164 if (bad < 0) 165 break; 166 printf("sn=%d, cn=%d, tn=%d, sn=%d\n", badsn(bt), 167 bt->bt_cyl, bt->bt_trksec>>8, bt->bt_trksec&0xff); 168 bt++; 169 } 170 (void) checkold(&oldbad); 171 exit(0); 172 } 173 if (add) { 174 /* 175 * Read in the old badsector table. 176 * Verify that it makes sense, and the bad sectors 177 * are in order. Copy the old table to the new one. 178 */ 179 (void) getold(f, &oldbad); 180 i = checkold(&oldbad); 181 if (verbose) 182 printf("Had %d bad sectors, adding %d\n", i, argc); 183 if (i + argc > 126) { 184 printf("bad144: not enough room for %d more sectors\n", 185 argc); 186 printf("limited to 126 by information format\n"); 187 exit(1); 188 } 189 curbad = oldbad; 190 } else { 191 curbad.bt_csn = atoi(*argv++); 192 argc--; 193 curbad.bt_mbz = 0; 194 curbad.bt_flag = DKBAD_MAGIC; 195 if (argc > 126) { 196 printf("bad144: too many bad sectors specified\n"); 197 printf("limited to 126 by information format\n"); 198 exit(1); 199 } 200 i = 0; 201 } 202 errs = 0; 203 new = argc; 204 while (argc > 0) { 205 daddr_t sn = atoi(*argv++); 206 argc--; 207 if (sn < 0 || sn >= size) { 208 printf("%d: out of range [0,%d) for disk %s\n", 209 sn, size, dp->d_typename); 210 errs++; 211 continue; 212 } 213 bn[i] = sn; 214 curbad.bt_bad[i].bt_cyl = sn / (dp->d_nsectors*dp->d_ntracks); 215 sn %= (dp->d_nsectors*dp->d_ntracks); 216 curbad.bt_bad[i].bt_trksec = 217 ((sn/dp->d_nsectors) << 8) + (sn%dp->d_nsectors); 218 i++; 219 } 220 if (errs) 221 exit(1); 222 nbad = i; 223 while (i < 126) { 224 curbad.bt_bad[i].bt_trksec = -1; 225 curbad.bt_bad[i].bt_cyl = -1; 226 i++; 227 } 228 if (add) { 229 /* 230 * Sort the new bad sectors into the list. 231 * Then shuffle the replacement sectors so that 232 * the previous bad sectors get the same replacement data. 233 */ 234 qsort((char *)curbad.bt_bad, nbad, sizeof (struct bt_bad), 235 compare); 236 if (dups) { 237 fprintf(stderr, 238 "bad144: bad sectors have been duplicated; can't add existing sectors\n"); 239 exit(3); 240 } 241 shift(f, nbad, nbad-new); 242 } 243 if (badfile == -1) 244 i = 0; 245 else 246 i = badfile * 2; 247 for (; i < 10 && i < dp->d_nsectors; i += 2) { 248 if (lseek(f, dp->d_secsize * (size - dp->d_nsectors + i), 249 L_SET) < 0) 250 Perror("lseek"); 251 if (verbose) 252 printf("write badsect file at %d\n", 253 size - dp->d_nsectors + i); 254 if (nflag == 0 && write(f, (caddr_t)&curbad, sizeof(curbad)) != 255 sizeof(curbad)) { 256 char msg[80]; 257 (void)sprintf(msg, "bad144: write bad sector file %d", 258 i/2); 259 perror(msg); 260 } 261 if (badfile != -1) 262 break; 263 } 264 #ifdef vax 265 if (nflag == 0 && fflag) 266 for (i = nbad - new; i < nbad; i++) 267 format(f, bn[i]); 268 #endif 269 #ifdef DIOCSBAD 270 if (nflag == 0 && ioctl(f, DIOCSBAD, (caddr_t)&curbad) < 0) 271 fprintf(stderr, 272 "Can't sync bad-sector file; reboot for changes to take effect\n"); 273 #endif 274 exit(0); 275 } 276 277 daddr_t 278 getold(f, bad) 279 struct dkbad *bad; 280 { 281 register int i; 282 daddr_t sn; 283 char msg[80]; 284 285 if (badfile == -1) 286 i = 0; 287 else 288 i = badfile * 2; 289 for (; i < 10 && i < dp->d_nsectors; i += 2) { 290 sn = size - dp->d_nsectors + i; 291 if (lseek(f, sn * dp->d_secsize, L_SET) < 0) 292 Perror("lseek"); 293 if (read(f, (char *) bad, dp->d_secsize) == dp->d_secsize) { 294 if (i > 0) 295 printf("Using bad-sector file %d\n", i/2); 296 return(sn); 297 } 298 (void)sprintf(msg, "bad144: read bad sector file at sn %d", sn); 299 perror(msg); 300 if (badfile != -1) 301 break; 302 } 303 fprintf(stderr, "bad144: %s: can't read bad block info\n", name); 304 exit(1); 305 /*NOTREACHED*/ 306 } 307 308 checkold() 309 { 310 register int i; 311 register struct bt_bad *bt; 312 daddr_t sn, lsn; 313 int errors = 0, warned = 0; 314 315 if (oldbad.bt_flag != DKBAD_MAGIC) { 316 fprintf(stderr, "bad144: %s: bad flag in bad-sector table\n", 317 name); 318 errors++; 319 } 320 if (oldbad.bt_mbz != 0) { 321 fprintf(stderr, "bad144: %s: bad magic number\n", name); 322 errors++; 323 } 324 bt = oldbad.bt_bad; 325 for (i = 0; i < 126; i++, bt++) { 326 if (bt->bt_cyl == 0xffff && bt->bt_trksec == 0xffff) 327 break; 328 if ((bt->bt_cyl >= dp->d_ncylinders) || 329 ((bt->bt_trksec >> 8) >= dp->d_ntracks) || 330 ((bt->bt_trksec & 0xff) >= dp->d_nsectors)) { 331 fprintf(stderr, 332 "bad144: cyl/trk/sect out of range in existing entry: "); 333 fprintf(stderr, "sn=%d, cn=%d, tn=%d, sn=%d\n", 334 badsn(bt), bt->bt_cyl, bt->bt_trksec>>8, 335 bt->bt_trksec & 0xff); 336 errors++; 337 } 338 sn = (bt->bt_cyl * dp->d_ntracks + 339 (bt->bt_trksec >> 8)) * 340 dp->d_nsectors + (bt->bt_trksec & 0xff); 341 if (i > 0 && sn < lsn && !warned) { 342 fprintf(stderr, 343 "bad144: bad sector file is out of order\n"); 344 errors++; 345 warned++; 346 } 347 if (i > 0 && sn == lsn) { 348 fprintf(stderr, 349 "bad144: bad sector file contains duplicates (sn %d)\n", 350 sn); 351 errors++; 352 } 353 lsn = sn; 354 } 355 if (errors) 356 exit(1); 357 return (i); 358 } 359 360 /* 361 * Move the bad sector replacements 362 * to make room for the new bad sectors. 363 * new is the new number of bad sectors, old is the previous count. 364 */ 365 shift(f, new, old) 366 { 367 daddr_t repl; 368 369 /* 370 * First replacement is last sector of second-to-last track. 371 */ 372 repl = size - dp->d_nsectors - 1; 373 new--; old--; 374 while (new >= 0 && new != old) { 375 if (old < 0 || 376 compare(&curbad.bt_bad[new], &oldbad.bt_bad[old]) > 0) { 377 /* 378 * Insert new replacement here-- copy original 379 * sector if requested and possible, 380 * otherwise write a zero block. 381 */ 382 if (!copy || 383 !blkcopy(f, badsn(&curbad.bt_bad[new]), repl - new)) 384 blkzero(f, repl - new); 385 } else { 386 if (blkcopy(f, repl - old, repl - new) == 0) 387 fprintf(stderr, 388 "Can't copy replacement sector %d to %d\n", 389 repl-old, repl-new); 390 old--; 391 } 392 new--; 393 } 394 } 395 396 char *buf; 397 398 /* 399 * Copy disk sector s1 to s2. 400 */ 401 blkcopy(f, s1, s2) 402 daddr_t s1, s2; 403 { 404 register tries, n; 405 406 if (buf == (char *)NULL) { 407 buf = malloc((unsigned)dp->d_secsize); 408 if (buf == (char *)NULL) { 409 fprintf(stderr, "Out of memory\n"); 410 exit(20); 411 } 412 } 413 for (tries = 0; tries < RETRIES; tries++) { 414 if (lseek(f, dp->d_secsize * s1, L_SET) < 0) 415 Perror("lseek"); 416 if ((n = read(f, buf, dp->d_secsize)) == dp->d_secsize) 417 break; 418 } 419 if (n != dp->d_secsize) { 420 fprintf(stderr, "bad144: can't read sector, %d: ", s1); 421 if (n < 0) 422 perror((char *)0); 423 return(0); 424 } 425 if (lseek(f, dp->d_secsize * s2, L_SET) < 0) 426 Perror("lseek"); 427 if (verbose) 428 printf("copying %d to %d\n", s1, s2); 429 if (nflag == 0 && write(f, buf, dp->d_secsize) != dp->d_secsize) { 430 fprintf(stderr, 431 "bad144: can't write replacement sector, %d: ", s2); 432 perror((char *)0); 433 return(0); 434 } 435 return(1); 436 } 437 438 char *zbuf; 439 440 blkzero(f, sn) 441 daddr_t sn; 442 { 443 444 if (zbuf == (char *)NULL) { 445 zbuf = malloc((unsigned)dp->d_secsize); 446 if (zbuf == (char *)NULL) { 447 fprintf(stderr, "Out of memory\n"); 448 exit(20); 449 } 450 } 451 if (lseek(f, dp->d_secsize * sn, L_SET) < 0) 452 Perror("lseek"); 453 if (verbose) 454 printf("zeroing %d\n", sn); 455 if (nflag == 0 && write(f, zbuf, dp->d_secsize) != dp->d_secsize) { 456 fprintf(stderr, 457 "bad144: can't write replacement sector, %d: ", sn); 458 perror((char *)0); 459 } 460 } 461 462 compare(b1, b2) 463 register struct bt_bad *b1, *b2; 464 { 465 if (b1->bt_cyl > b2->bt_cyl) 466 return(1); 467 if (b1->bt_cyl < b2->bt_cyl) 468 return(-1); 469 if (b1->bt_trksec == b2->bt_trksec) 470 dups++; 471 return (b1->bt_trksec - b2->bt_trksec); 472 } 473 474 daddr_t 475 badsn(bt) 476 register struct bt_bad *bt; 477 { 478 return ((bt->bt_cyl*dp->d_ntracks + (bt->bt_trksec>>8)) * dp->d_nsectors 479 + (bt->bt_trksec&0xff)); 480 } 481 482 #ifdef vax 483 484 struct rp06hdr { 485 short h_cyl; 486 short h_trksec; 487 short h_key1; 488 short h_key2; 489 char h_data[512]; 490 #define RP06_FMT 010000 /* 1 == 16 bit, 0 == 18 bit */ 491 }; 492 493 /* 494 * Most massbus and unibus drives 495 * have headers of this form 496 */ 497 struct hpuphdr { 498 u_short hpup_cyl; 499 u_char hpup_sect; 500 u_char hpup_track; 501 char hpup_data[512]; 502 #define HPUP_OKSECT 0xc000 /* this normally means sector is good */ 503 #define HPUP_16BIT 0x1000 /* 1 == 16 bit format */ 504 }; 505 int rp06format(), hpupformat(); 506 507 struct formats { 508 char *f_name; /* disk name */ 509 int f_bufsize; /* size of sector + header */ 510 int f_bic; /* value to bic in hpup_cyl */ 511 int (*f_routine)(); /* routine for special handling */ 512 } formats[] = { 513 { "rp06", sizeof (struct rp06hdr), RP06_FMT, rp06format }, 514 { "eagle", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, 515 { "capricorn", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, 516 { "rm03", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, 517 { "rm05", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, 518 { "9300", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, 519 { "9766", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, 520 { 0, 0, 0, 0 } 521 }; 522 523 /*ARGSUSED*/ 524 hpupformat(fp, dp, blk, buf, count) 525 struct formats *fp; 526 struct disklabel *dp; 527 daddr_t blk; 528 char *buf; 529 int count; 530 { 531 struct hpuphdr *hdr = (struct hpuphdr *)buf; 532 int sect; 533 534 if (count < sizeof(struct hpuphdr)) { 535 hdr->hpup_cyl = (HPUP_OKSECT | HPUP_16BIT) | 536 (blk / (dp->d_nsectors * dp->d_ntracks)); 537 sect = blk % (dp->d_nsectors * dp->d_ntracks); 538 hdr->hpup_track = (u_char)(sect / dp->d_nsectors); 539 hdr->hpup_sect = (u_char)(sect % dp->d_nsectors); 540 } 541 return (0); 542 } 543 544 /*ARGSUSED*/ 545 rp06format(fp, dp, blk, buf, count) 546 struct formats *fp; 547 struct disklabel *dp; 548 daddr_t blk; 549 char *buf; 550 int count; 551 { 552 553 if (count < sizeof(struct rp06hdr)) { 554 fprintf(stderr, "Can't read header on blk %d, can't reformat\n", 555 blk); 556 return (-1); 557 } 558 return (0); 559 } 560 561 format(fd, blk) 562 int fd; 563 daddr_t blk; 564 { 565 register struct formats *fp; 566 static char *buf; 567 static char bufsize; 568 struct format_op fop; 569 int n; 570 571 for (fp = formats; fp->f_name; fp++) 572 if (strcmp(dp->d_typename, fp->f_name) == 0) 573 break; 574 if (fp->f_name == 0) { 575 fprintf(stderr, "bad144: don't know how to format %s disks\n", 576 dp->d_typename); 577 exit(2); 578 } 579 if (buf && bufsize < fp->f_bufsize) { 580 free(buf); 581 buf = NULL; 582 } 583 if (buf == NULL) 584 buf = malloc((unsigned)fp->f_bufsize); 585 if (buf == NULL) { 586 fprintf(stderr, "bad144: can't allocate sector buffer\n"); 587 exit(3); 588 } 589 bufsize = fp->f_bufsize; 590 /* 591 * Here we do the actual formatting. All we really 592 * do is rewrite the sector header and flag the bad sector 593 * according to the format table description. If a special 594 * purpose format routine is specified, we allow it to 595 * process the sector as well. 596 */ 597 if (verbose) 598 printf("format blk %d\n", blk); 599 bzero((char *)&fop, sizeof(fop)); 600 fop.df_buf = buf; 601 fop.df_count = fp->f_bufsize; 602 fop.df_startblk = blk; 603 bzero(buf, fp->f_bufsize); 604 if (ioctl(fd, DIOCRFORMAT, &fop) < 0) 605 perror("bad144: read format"); 606 if (fp->f_routine && 607 (*fp->f_routine)(fp, dp, blk, buf, fop.df_count) != 0) 608 return; 609 if (fp->f_bic) { 610 struct hpuphdr *xp = (struct hpuphdr *)buf; 611 612 xp->hpup_cyl &= ~fp->f_bic; 613 } 614 if (nflag) 615 return; 616 bzero((char *)&fop, sizeof(fop)); 617 fop.df_buf = buf; 618 fop.df_count = fp->f_bufsize; 619 fop.df_startblk = blk; 620 if (ioctl(fd, DIOCWFORMAT, &fop) < 0) 621 Perror("write format"); 622 if (fop.df_count != fp->f_bufsize) { 623 char msg[80]; 624 (void)sprintf(msg, "bad144: write format %d", blk); 625 perror(msg); 626 } 627 } 628 #endif 629 630 Perror(op) 631 char *op; 632 { 633 634 fprintf(stderr, "bad144: "); perror(op); 635 exit(4); 636 } 637