1 #ifndef lint 2 static char sccsid[] = "@(#)maps.c 1.8 (Berkeley/CCI) 06/24/90"; 3 #endif 4 5 6 #include "vdfmt.h" 7 8 9 /* 10 ** 11 */ 12 13 boolean align_buf(buf, sync) 14 unsigned long *buf; 15 unsigned long sync; 16 { 17 register int i, shift; 18 19 /* find shift amount */ 20 for(shift=0; shift < 32; shift++) { 21 if((*buf >> shift ) == sync) { 22 for(i=(512/sizeof(long))-1; i >= 0; i--) { 23 *(buf+i+1) |= *(buf+i) << (32 - shift); 24 *(buf+i) = *(buf+i) >> shift; 25 } 26 return true; 27 } 28 } 29 return false; 30 } 31 32 33 /* 34 ** Looks for two maps in a row that are the same. 35 */ 36 37 boolean 38 read_map(flags) 39 short flags; 40 { 41 register int trk, i; 42 register bs_map *map; 43 dskadr dskaddr; 44 45 dskaddr.cylinder = (lab->d_ncylinders - 1) | flags; 46 for(trk=0; trk < lab->d_ntracks; trk++) { 47 dskaddr.track = trk; 48 dskaddr.sector = 0; 49 if(access_dsk((char *)map_space, &dskaddr, VDOP_RD, 50 lab->d_nsectors, 1) & VDERR_HARD) 51 continue; 52 map = &norm_bad_map; 53 /* 54 * If this doesn't look like a new-style map, 55 * but (as an old-style map) bs_count and bs_max are sensible, 56 * munge pointer to prepend fields missing in old map. 57 */ 58 if (map->bs_magic != BSMAGIC && 59 map->bs_cksum <= MAX_FLAWMAP(bytes_trk) /* bs_count */ 60 && map->bs_id <= MAX_FLAWMAP(bytes_trk)) /* bs_max */ 61 map = &offset_bad_map; 62 if (trk > 0 && 63 bcmp((char *)map_space, (char *)save, bytes_trk) == 0 && 64 map->bs_count <= MAX_FLAWMAP(bytes_trk)) { 65 for (i=0; i < map->bs_count; i++) { 66 if (map->list[i].bs_cyl >= 67 lab->d_ncylinders) 68 break; 69 if (map->list[i].bs_trk >= 70 lab->d_ntracks) 71 break; 72 if (map->list[i].bs_offset >= 73 lab->d_traksize) 74 break; 75 } 76 if (i == map->bs_count) { 77 bad_map = map; 78 load_free_table(); 79 return true; 80 } 81 } 82 bcopy((char *)map_space, (char *)save, bytes_trk); 83 } 84 map = &norm_bad_map; 85 bad_map = map; 86 bzero((char *)map, bytes_trk); 87 map->bs_magic = BSMAGIC; 88 map->bs_id = 0; 89 map->bs_max = MAX_FLAWS; 90 return false; 91 } 92 93 94 /* 95 ** 96 */ 97 98 boolean read_bad_sector_map() 99 { 100 dskadr dskaddr; 101 102 dskaddr.cylinder = lab->d_ncylinders - 1; 103 dskaddr.track = 0; 104 dskaddr.sector = 0; 105 offset_bad_map.bs_magic = BSMAGIC; 106 offset_bad_map.bs_cksum = 0; 107 bad_map = &norm_bad_map; 108 /* start with nothing in map */ 109 bzero(map_space, bytes_trk); 110 bad_map->bs_magic = BSMAGIC; 111 bad_map->bs_id = 0; 112 bad_map->bs_max = MAX_FLAWS; 113 if (C_INFO->type == VDTYPE_SMDE) { 114 access_dsk((char *)save, &dskaddr, VDOP_RDRAW, 1, 1); 115 if (align_buf((unsigned long *)save, CDCSYNC) == true) { 116 read_flaw_map(); 117 return (false); 118 } else if (read_map(NRM) == true) { 119 return (true); 120 } else { 121 get_smde_relocations(); 122 return false; 123 } 124 } else { 125 if (read_map(WPT) == true) 126 return (true); 127 else { 128 get_relocations_the_hard_way(); 129 return (false); 130 } 131 } 132 } 133 134 135 /* 136 ** 137 */ 138 139 get_relocations_the_hard_way() 140 { 141 register int cyl, trk; 142 register int status; 143 dskadr dskaddr; 144 145 dskaddr.sector = 0; 146 /* scan each sector to see if it is relocated and take note if it is */ 147 for(cyl=0; cyl < lab->d_ncylinders - NUMSYS; cyl++) { 148 dskaddr.cylinder = cyl; 149 for(trk=0; trk < lab->d_ntracks; trk++) { 150 dskaddr.track = trk; 151 status=access_dsk((char *)scratch, &dskaddr, 152 VDOP_RD, lab->d_nsectors, 1); 153 if(status & DCBS_ATA) 154 get_track_relocations(dskaddr); 155 } 156 } 157 load_free_table(); 158 } 159 160 161 /* 162 ** 163 */ 164 165 get_track_relocations(dskaddr) 166 dskadr dskaddr; 167 { 168 register int status; 169 bs_entry temp; 170 fmt_err error; 171 172 for(dskaddr.sector=0; dskaddr.sector < lab->d_nsectors; dskaddr.sector++) { 173 status = access_dsk((char *)scratch, &dskaddr, VDOP_RD, 1, 1); 174 if(status & DCBS_ATA) { 175 error.err_adr = dskaddr; 176 error.err_stat = DATA_ERROR; 177 (*C_INFO->code_pos)(&error, &temp); 178 temp.bs_how = operator; 179 add_flaw(&temp); 180 } 181 } 182 } 183 184 185 /* 186 ** 187 */ 188 189 remove_user_relocations(entry) 190 bs_entry *entry; 191 { 192 register int i, j; 193 fmt_err temp; 194 fmt_err error; 195 register bs_entry *ptr; 196 197 (*C_INFO->decode_pos)(entry, &error); 198 ptr = bad_map->list; 199 for(i=0; i < bad_map->bs_count; i++) { 200 if (ptr->bs_cyl != entry->bs_cyl || 201 ptr->bs_trk != entry->bs_trk) 202 continue; 203 (*C_INFO->decode_pos)(ptr, &temp); 204 if((ptr->bs_how != flaw_map) && 205 (temp.err_adr.cylinder == error.err_adr.cylinder) && 206 (temp.err_adr.track == error.err_adr.track) && 207 (temp.err_adr.sector == error.err_adr.sector)) { 208 if(temp.err_stat & HEADER_ERROR) 209 remove_track(&temp, ptr); 210 else 211 remove_sector(&temp, ptr); 212 for(j=i+1; j < bad_map->bs_count; j++) 213 bad_map->list[j-1] = bad_map->list[j]; 214 bad_map->bs_count--; 215 return; 216 } 217 ptr++; 218 } 219 indent(); 220 print("Sector %d is not in bad sector map!\n", 221 to_sector(error.err_adr)); 222 exdent(1); 223 } 224 225 clear_relocations(reformat) 226 boolean reformat; 227 { 228 fmt_err temp; 229 register bs_entry *ptr1, *ptr2, *end; 230 int oldsub = cur.substate; 231 232 cur.substate = sub_rel; 233 ptr1 = bad_map->list; 234 ptr2 = bad_map->list; 235 end = &bad_map->list[bad_map->bs_count]; 236 for (; ptr1 < end; ptr1++) { 237 if (ptr1->bs_how != flaw_map) { 238 if (reformat == true) { 239 (*C_INFO->decode_pos)(ptr1, &temp); 240 if(temp.err_stat & HEADER_ERROR) 241 remove_track(&temp, ptr1); 242 else 243 remove_sector(&temp, ptr1); 244 } 245 bad_map->bs_count--; 246 } else { 247 if (ptr1 != ptr2) 248 *ptr2 = *ptr1; 249 ptr2++; 250 } 251 } 252 cur.substate = oldsub; 253 } 254 255 256 /* 257 ** 258 */ 259 260 remove_sector(error, entry) 261 fmt_err *error; 262 bs_entry *entry; 263 { 264 format_sectors(&error->err_adr, &error->err_adr, NRM, 1); 265 format_sectors(&entry->bs_alt, &entry->bs_alt, NRM, 1); 266 } 267 268 269 /* 270 ** 271 */ 272 273 remove_track(error, entry) 274 fmt_err *error; 275 bs_entry *entry; 276 { 277 format_sectors(&error->err_adr,&error->err_adr,NRM,(long)lab->d_nsectors); 278 format_sectors(&entry->bs_alt,&entry->bs_alt,NRM,(long)lab->d_nsectors); 279 } 280 281 282 /* 283 ** 284 */ 285 286 write_bad_sector_map() 287 { 288 register int trk, sec; 289 dskadr dskaddr; 290 291 bad_map->bs_magic = BSMAGIC; 292 bad_map->bs_id = 0; 293 dskaddr.cylinder = (lab->d_ncylinders - NUMMAP); 294 for(trk=0; trk < lab->d_ntracks; trk++) { 295 for(sec = 0; sec < lab->d_nsectors; sec++) { 296 bcopy((char *)bad_map + (sec * lab->d_secsize), 297 (char *)scratch, lab->d_secsize); 298 dskaddr.track = trk; 299 dskaddr.sector = sec; 300 format_sectors(&dskaddr, &dskaddr, WPT, 1); 301 } 302 } 303 } 304 305 306 /* 307 ** 308 */ 309 310 zero_bad_sector_map() 311 { 312 bs_map *bm = bad_map; 313 register int i; 314 dskadr zero; 315 316 zero.cylinder = 0; 317 zero.track = 0; 318 zero.sector = 0; 319 for(i=0; i < bm->bs_count; i++) 320 bm->list[i].bs_alt = zero; 321 load_free_table(); 322 } 323 324 325 /* 326 ** 327 */ 328 329 read_flaw_map() 330 { 331 register int cyl, trk; 332 dskadr dskaddr; 333 flaw buffer; 334 335 dskaddr.sector = 0; 336 for (cyl=0; cyl < lab->d_ncylinders; cyl++) { 337 dskaddr.cylinder = cyl; 338 for (trk=0; trk < lab->d_ntracks; trk++) { 339 dskaddr.track = trk; 340 access_dsk(&buffer, &dskaddr, VDOP_RDRAW, 1, 1); 341 if(align_buf(&buffer, CDCSYNC) == true) { 342 add_flaw_entries(&buffer); 343 continue; 344 } 345 } 346 } 347 load_free_table(); 348 } 349 350 351 /* 352 ** 353 */ 354 355 get_smde_relocations() 356 { 357 register int cyl, trk, sec; 358 smde_hdr buffer; 359 dskadr dskaddr; 360 fmt_err bad; 361 bs_entry temp; 362 boolean bad_track; 363 364 /* Read any old drive relocations */ 365 for(cyl=0; cyl < NUMREL; cyl++) { 366 dskaddr.cylinder = lab->d_ncylinders - NUMSYS + cyl; 367 for(trk=0; trk < lab->d_ntracks; trk++) { 368 dskaddr.track = trk; 369 bad_track = true; 370 for(sec=0; sec < lab->d_nsectors; sec++) { 371 dskaddr.sector = sec; 372 access_dsk(&buffer, &dskaddr, VDOP_RDRAW, 1, 1); 373 if(align_buf(&buffer, SMDE1SYNC) == false) { 374 bad_track = false; 375 break; 376 } 377 } 378 if(bad_track == true) { 379 dskaddr.sector = 0; 380 bad.err_adr.cylinder = buffer.alt_cyl; 381 bad.err_adr.track = buffer.alt_trk; 382 bad.err_adr.sector = 0; 383 bad.err_stat = HEADER_ERROR; 384 (*C_INFO->code_pos)(&bad, &temp); 385 temp.bs_alt = dskaddr; 386 temp.bs_how = scanning; 387 add_flaw(&temp); 388 continue; 389 } 390 for(sec=0; sec < lab->d_nsectors; sec++) { 391 dskaddr.sector = sec; 392 access_dsk(&buffer, &dskaddr, VDOP_RDRAW, 1, 1); 393 if(align_buf(&buffer, SMDE1SYNC) == true) { 394 bad.err_adr.cylinder = buffer.alt_cyl; 395 bad.err_adr.track = buffer.alt_trk; 396 bad.err_adr.sector = buffer.alt_sec; 397 bad.err_stat = DATA_ERROR; 398 (*C_INFO->code_pos)(&bad, &temp); 399 temp.bs_alt = dskaddr; 400 temp.bs_how = scanning; 401 add_flaw(&temp); 402 } 403 } 404 } 405 } 406 load_free_table(); 407 } 408 409 410 /* 411 ** 412 */ 413 414 add_flaw_entries(buffer) 415 flaw *buffer; 416 { 417 register int i; 418 bs_entry temp; 419 420 temp.bs_cyl = buffer->flaw_cyl & 0x7fff; /* clear off bad track bit */ 421 temp.bs_trk = buffer->flaw_trk; 422 for(i=0; i < 4; i++) { 423 if(buffer->flaw_pos[i].flaw_length != 0) { 424 temp.bs_offset = buffer->flaw_pos[i].flaw_offset; 425 temp.bs_length = buffer->flaw_pos[i].flaw_length; 426 temp.bs_alt.cylinder = 0; 427 temp.bs_alt.track = 0; 428 temp.bs_alt.sector = 0; 429 temp.bs_how = flaw_map; 430 add_flaw(&temp); 431 } 432 } 433 } 434 435 436 cmp_entry(a, b) 437 bs_entry *a; 438 bs_entry *b; 439 { 440 if(a->bs_cyl == b->bs_cyl) { 441 if(a->bs_trk == b->bs_trk) { 442 if(a->bs_offset == b->bs_offset) 443 return 0; 444 else if(a->bs_offset < b->bs_offset) 445 return -1; 446 } 447 else if(a->bs_trk < b->bs_trk) 448 return -1; 449 } 450 else if(a->bs_cyl < b->bs_cyl) 451 return -1; 452 return 1; 453 } 454 455 456 /* 457 * Add flaw to map. 458 * Return value: 459 * 1 OK 460 * 0 sector was in map 461 * -1 failure 462 */ 463 add_flaw(entry) 464 bs_entry *entry; 465 { 466 extern int cmp_entry(); 467 bs_map *bm = bad_map; 468 register int i; 469 470 if(bm->bs_count > MAX_FLAWS) 471 return (-1); 472 if (entry->bs_cyl >= lab->d_ncylinders || 473 entry->bs_trk >= lab->d_ntracks || 474 entry->bs_offset >= lab->d_traksize) 475 return (-1); 476 for(i=0; i < bm->bs_count; i++) { 477 if(((bm->list[i].bs_cyl == entry->bs_cyl)) && 478 (bm->list[i].bs_trk == entry->bs_trk) && 479 (bm->list[i].bs_offset == entry->bs_offset)) { 480 if((int)bm->list[i].bs_how > (int)entry->bs_how) 481 bm->list[i].bs_how = entry->bs_how; 482 return (0); 483 } 484 } 485 bm->list[i] = *entry; 486 bm->list[i].bs_alt.cylinder = 0; 487 bm->list[i].bs_alt.track = 0; 488 bm->list[i].bs_alt.sector = 0; 489 bm->bs_count++; 490 qsort((char *)&(bm->list[0]), (unsigned)bm->bs_count, 491 sizeof(bs_entry), cmp_entry); 492 return (1); 493 } 494 495 496 /* 497 ** Is_in_map checks to see if a block is known to be bad already. 498 */ 499 500 boolean is_in_map(dskaddr) 501 dskadr *dskaddr; 502 { 503 register int i; 504 fmt_err temp; 505 506 for(i=0; i < bad_map->bs_count; i++) { 507 (*C_INFO->decode_pos)(&bad_map->list[i], &temp); 508 if((temp.err_adr.cylinder == dskaddr->cylinder) && 509 (temp.err_adr.track == dskaddr->track) && 510 (temp.err_adr.sector == dskaddr->sector)) { 511 return true; 512 } 513 } 514 return false; 515 } 516 517 518 /* 519 ** 520 */ 521 522 print_bad_sector_list() 523 { 524 register int i; 525 fmt_err errloc; 526 register bs_entry *bad; 527 528 if(bad_map->bs_magic != BSMAGIC) 529 print("Bad-sector map magic number wrong! (%x != %x)\n", 530 bad_map->bs_magic, BSMAGIC); 531 if(bad_map->bs_count == 0) { 532 print("There are no bad sectors in bad sector map.\n"); 533 return; 534 } 535 print("The following %d sector%s known to be bad:\n", 536 bad_map->bs_count, (bad_map->bs_count == 1) ? " is" : "s are"); 537 exdent(0); 538 for(i=0, bad = bad_map->list; i < bad_map->bs_count; i++, bad++) { 539 (*C_INFO->decode_pos)(bad, &errloc); 540 print("%c %d cn %d tn %d sn %d pos %d len %d ", 541 errloc.err_stat & HEADER_ERROR ? 'T' : 'S', 542 to_sector(errloc.err_adr), 543 bad->bs_cyl, 544 bad->bs_trk, 545 errloc.err_adr.sector, 546 bad->bs_offset, 547 bad->bs_length); 548 if (bad->bs_how == flaw_map) 549 printf("(flawmap) "); 550 else if (bad->bs_how == scanning) 551 printf("(verify) "); 552 else 553 printf("(operator) "); 554 if((bad->bs_alt.cylinder != 0) || (bad->bs_alt.track != 0) || 555 (bad->bs_alt.sector != 0)) { 556 printf("-> "); 557 printf("cn %d tn %d sn %d", bad->bs_alt.cylinder, 558 bad->bs_alt.track, bad->bs_alt.sector); 559 } 560 printf("\n"); 561 } 562 } 563 564 565 /* 566 ** load_free_table checks each block in the bad block relocation area 567 ** to see if it is used. If it is, the free relocation block table is updated. 568 */ 569 570 load_free_table() 571 { 572 register int i, j; 573 fmt_err temp; 574 575 /* Clear free table before starting */ 576 for(i = 0; i < (lab->d_ntracks * NUMREL); i++) { 577 for(j=0; j < lab->d_nsectors; j++) 578 free_tbl[i][j].free_status = NOTALLOCATED; 579 } 580 for(i=0; i < bad_map->bs_count; i++) 581 if((bad_map->list[i].bs_alt.cylinder != 0) || 582 (bad_map->list[i].bs_alt.track != 0) || 583 (bad_map->list[i].bs_alt.sector != 0)) { 584 (*C_INFO->decode_pos)(&bad_map->list[i], &temp); 585 allocate(&(bad_map->list[i].bs_alt), temp.err_stat); 586 } 587 } 588 589 590 /* 591 ** allocate marks a replacement sector as used. 592 */ 593 594 allocate(dskaddr, status) 595 dskadr *dskaddr; 596 long status; 597 { 598 register int trk, sec; 599 600 trk = dskaddr->cylinder - (lab->d_ncylinders - NUMSYS); 601 if((trk < 0) || (trk >= NUMREL)) 602 return; 603 trk *= lab->d_ntracks; 604 trk += dskaddr->track; 605 if(status & HEADER_ERROR) 606 for(sec=0; sec < lab->d_nsectors; sec++) 607 free_tbl[trk][sec].free_status = ALLOCATED; 608 else 609 free_tbl[trk][dskaddr->sector].free_status = ALLOCATED; 610 } 611 612 613 /* 614 ** 615 */ 616 617 boolean mapping_collision(entry) 618 bs_entry *entry; 619 { 620 register int trk, sec; 621 fmt_err temp; 622 623 trk = entry->bs_cyl - (lab->d_ncylinders - NUMSYS); 624 if((trk < 0) || (trk >= NUMREL)) 625 return false; 626 trk *= lab->d_ntracks; 627 trk += entry->bs_trk; 628 (*C_INFO->decode_pos)(entry, &temp); 629 /* if this relocation should take up the whole track */ 630 if(temp.err_stat & HEADER_ERROR) { 631 for(sec=0; sec < lab->d_nsectors; sec++) 632 if(free_tbl[trk][sec].free_status == ALLOCATED) 633 return true; 634 } 635 /* else just check the current sector */ 636 else { 637 if(free_tbl[trk][temp.err_adr.sector].free_status == ALLOCATED) 638 return true; 639 } 640 return false; 641 } 642 643 644 /* 645 ** 646 */ 647 648 report_collision() 649 { 650 indent(); 651 print("Sector resides in relocation area"); 652 printf("but it has a sector mapped to it already.\n"); 653 print("Please reformat disk with 0 patterns to eliminate problem.\n"); 654 exdent(1); 655 } 656 657 658 /* 659 ** 660 */ 661 662 add_user_relocations(entry) 663 bs_entry *entry; 664 { 665 fmt_err error; 666 667 (*C_INFO->decode_pos)(entry, &error); 668 if(is_in_map(&error.err_adr) == false) { 669 if(mapping_collision(entry) == true) 670 report_collision(); 671 entry->bs_how = operator; 672 add_flaw(entry); 673 } 674 else { 675 indent(); 676 print("Sector %d is already mapped out!\n", 677 to_sector(error.err_adr)); 678 exdent(1); 679 } 680 } 681 682 683 /* 684 ** New_location allocates a replacement block given a bad block address. 685 ** The algorithm is fairly simple; it simply searches for the first 686 ** free sector that has the same sector number of the bad sector. If no sector 687 ** is found then the drive should be considered bad because of a microcode bug 688 ** in the controller that forces us to use the same sector number as the bad 689 ** sector for relocation purposes. Using different tracks and cylinders is ok 690 ** of course. 691 */ 692 693 dskadr *new_location(entry) 694 bs_entry *entry; 695 { 696 register int i, sec; 697 static fmt_err temp; 698 static dskadr newaddr; 699 700 newaddr.cylinder = 0; 701 newaddr.track = 0; 702 newaddr.sector = 0; 703 (*C_INFO->decode_pos)(entry, &temp); 704 /* If it is ouside of the user's data area */ 705 if(entry->bs_cyl >= lab->d_ncylinders-NUMSYS) { 706 /* if it is in the relocation area */ 707 if(entry->bs_cyl < (lab->d_ncylinders - NUMMAP - NUMMNT)) { 708 /* mark space as allocated */ 709 allocate(&temp.err_adr, temp.err_stat); 710 return &temp.err_adr; 711 } 712 /* if it is in the map area forget about it */ 713 if(entry->bs_cyl != (lab->d_ncylinders - NUMMAP - NUMMNT)) 714 return &temp.err_adr; 715 /* otherwise treat maintainence cylinder normally */ 716 } 717 if(temp.err_stat & (HEADER_ERROR)) { 718 for(i = 0; i < (lab->d_ntracks * NUMREL); i++) { 719 for(sec=0; sec < lab->d_nsectors; sec++) { 720 if(free_tbl[i][sec].free_status == ALLOCATED) 721 break; 722 } 723 if(sec == lab->d_nsectors) { 724 for(sec = 0; sec < lab->d_nsectors; sec++) 725 free_tbl[i][sec].free_status=ALLOCATED; 726 newaddr.cylinder = i / lab->d_ntracks + 727 (lab->d_ncylinders - NUMSYS); 728 newaddr.track = i % lab->d_ntracks; 729 break; 730 } 731 } 732 } 733 else if(C_INFO->type == VDTYPE_VDDC) { 734 for(i = 0; i < (lab->d_ntracks * NUMREL); i++) { 735 if(free_tbl[i][temp.err_adr.sector].free_status != 736 ALLOCATED) { 737 free_tbl[i][temp.err_adr.sector].free_status = 738 ALLOCATED; 739 newaddr.cylinder = i / lab->d_ntracks + 740 (lab->d_ncylinders - NUMSYS); 741 newaddr.track = i % lab->d_ntracks; 742 newaddr.sector = temp.err_adr.sector; 743 break; 744 } 745 } 746 } 747 else { 748 for(i = 0; i < (lab->d_ntracks * NUMREL); i++) { 749 for(sec=0; sec < lab->d_nsectors; sec++) 750 if(free_tbl[i][sec].free_status != ALLOCATED) 751 break; 752 if(sec < lab->d_nsectors) { 753 free_tbl[i][sec].free_status = ALLOCATED; 754 newaddr.cylinder = i / lab->d_ntracks + 755 (lab->d_ncylinders - NUMSYS); 756 newaddr.track = i % lab->d_ntracks; 757 newaddr.sector = sec; 758 break; 759 } 760 } 761 } 762 return &newaddr; 763 } 764