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