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