1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * copyright (c) 1990, 1991 UNIX System Laboratories, Inc. 26 * copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T 27 * All rights reserved. 28 */ 29 30 /* 31 * Copyrighted as an unpublished work. 32 * (c) Copyright INTERACTIVE Systems Corporation 1986, 1988, 1990 33 * All rights reserved. 34 */ 35 36 #include <sys/types.h> 37 #include <ctype.h> 38 #include <fcntl.h> 39 #include <malloc.h> 40 #include <sys/stat.h> 41 #include <sys/swap.h> 42 #include <stdio.h> 43 #include <string.h> 44 #include <sys/vtoc.h> 45 #include <sys/param.h> 46 #include <sys/dkio.h> 47 #include <sys/dktp/altsctr.h> 48 #include <sys/dktp/fdisk.h> 49 #include "badsec.h" 50 #include "global.h" 51 #include "ctlr_ata.h" 52 #include "misc.h" 53 54 #define FAILURE 1 55 #define SUCCESS 0 56 57 #define CMD_READ 0 58 #define CMD_WRITE 1 59 60 struct badsec_lst *badsl_chain = NULL; 61 int badsl_chain_cnt = 0; 62 struct badsec_lst *gbadsl_chain = NULL; 63 int gbadsl_chain_cnt = 0; 64 65 static struct alts_mempart alts_part = { 0, NULL, 0 }; 66 struct alts_mempart *ap = &alts_part; /* pointer to incore */ 67 /* alts tables */ 68 69 /* prototypes */ 70 int updatebadsec(struct dkl_partition *, int); 71 int read_altsctr(struct dkl_partition *); 72 static int chk_badsec(); 73 static int init_altsctr(); 74 static int get_altsctr(); 75 int wr_altsctr(); 76 static void get_badsec(); 77 static int count_badsec(); 78 static int gen_alts_ent(); 79 static int assign_altsctr(); 80 static void expand_map(); 81 static void compress_map(); 82 static int altsmap_getbit(blkaddr_t); 83 static blkaddr_t altsmap_alloc(blkaddr_t, blkaddr_t, int, int); 84 static void ent_sort(struct alts_ent *, int); 85 static void ent_compress(struct alts_ent *, int); 86 static int ent_merge(struct alts_ent *, struct alts_ent *, int, 87 struct alts_ent *, int); 88 static int ent_bsearch(struct alts_ent *, int, struct alts_ent *); 89 static int chk_bad_altsctr(blkaddr_t); 90 91 /* 92 * updatebadsec () -- update bad sector/track mapping tables 93 */ 94 int 95 updatebadsec(part, init_flag) 96 int init_flag; 97 struct dkl_partition *part; 98 { 99 if (init_flag) 100 ap->ap_flag |= ALTS_ADDPART; 101 get_badsec(); 102 (void) read_altsctr(part); 103 ent_sort(ap->ap_gbadp, ap->ap_gbadcnt); 104 ent_compress(ap->ap_gbadp, ap->ap_gbadcnt); 105 (void) gen_alts_ent(); 106 compress_map(); 107 return (SUCCESS); 108 } 109 110 /* 111 * read_altsctr( ptr to alternate sector partition ) 112 * -- read the alternate sector partition tables 113 */ 114 int 115 read_altsctr(struct dkl_partition *part) 116 { 117 if (ap->ap_tblp == NULL) { 118 /* allocate buffer for the alts partition table (sector size) */ 119 ap->ap_tbl_secsiz = byte_to_secsiz(ALTS_PARTTBL_SIZE, NBPSCTR); 120 ap->ap_tblp = (struct alts_parttbl *)malloc(ap->ap_tbl_secsiz); 121 if (ap->ap_tblp == NULL) { 122 (void) fprintf(stderr, 123 "Unable to malloc alternate partition table.\n"); 124 return (50); 125 } 126 127 /* allocate buffer for the alts partition map (sector size) */ 128 /* buffers include the disk image bit map */ 129 /* and the incore transformed char map */ 130 131 if ((ap->ap_memmapp = (uchar_t *)malloc(part->p_size)) == NULL) { 132 (void) fprintf(stderr, 133 "Unable to malloc incore alternate partition map.\n"); 134 return (51); 135 } 136 ap->ap_tblp->alts_map_len = (part->p_size + 8 - 1) / 8; 137 ap->ap_map_secsiz = byte_to_secsiz(ap->ap_tblp->alts_map_len, 138 NBPSCTR); 139 ap->ap_map_sectot = ap->ap_map_secsiz / NBPSCTR; 140 if ((ap->ap_mapp = (uchar_t *)malloc(ap->ap_map_secsiz)) == NULL) { 141 (void) fprintf(stderr, 142 "Unable to malloc alternate partition map.\n"); 143 return (52); 144 } 145 /* clear the buffers to zero */ 146 (void) memset(ap->ap_memmapp, 0, part->p_size); 147 (void) memset(ap->ap_mapp, 0, ap->ap_map_secsiz); 148 ap->part = *part; /* struct copy */ 149 150 /* 151 * if add alternate partition flag is set, then install the partition 152 * otherwise read the alts partition info from disk 153 * if failed, then assume the first installation 154 */ 155 if (ap->ap_flag & ALTS_ADDPART) 156 { 157 (void) fprintf(stderr, 158 "WARNING: Manually initializing alternate table.\n"); 159 (void) init_altsctr(); 160 } else { 161 if (get_altsctr() == SUCCESS) 162 (void) chk_badsec(); 163 else 164 (void) init_altsctr(); 165 } 166 } 167 return (SUCCESS); 168 } 169 170 171 /* 172 * checking duplicate bad sectors or bad sectors in ALTSCTR partition 173 */ 174 static int 175 chk_badsec() 176 { 177 blkaddr_t badsec; 178 blkaddr_t altsp_srtsec = ap->part.p_start; 179 blkaddr_t altsp_endsec = ap->part.p_start + ap->part.p_size - 1; 180 int cnt; 181 int status; 182 183 for (cnt = 0; cnt < ap->ap_gbadcnt; cnt++) { 184 badsec = (ap->ap_gbadp)[cnt].bad_start; 185 186 /* if bad sector is within the ATLSCTR partition */ 187 if ((badsec >= altsp_srtsec) && (badsec <= altsp_endsec)) { 188 if ((ap->ap_memmapp)[badsec - altsp_srtsec] != ALTS_BAD) { 189 if ((badsec >= altsp_srtsec) && (badsec <= (altsp_srtsec + 190 ap->ap_tbl_secsiz / NBPSCTR - 1))) { 191 (void) fprintf(stderr, 192 "Alternate partition information table is bad.\n"); 193 return (53); 194 } 195 if ((badsec >= altsp_srtsec+ap->ap_tblp->alts_map_base) && 196 (badsec <= (altsp_srtsec + ap->ap_tblp->alts_map_base + 197 ap->ap_map_sectot - 1))) { 198 (void) fprintf(stderr, 199 "Alternate partition map is bad.\n"); 200 return (54); 201 } 202 if ((badsec >= altsp_srtsec+ap->ap_tblp->alts_ent_base) && 203 (badsec <= (altsp_srtsec + ap->ap_tblp->alts_ent_base + 204 ap->ap_ent_secsiz / NBPSCTR - 1))) { 205 (void) fprintf(stderr, 206 "Alternate partition entry table is bad.\n"); 207 return (55); 208 } 209 (ap->ap_memmapp)[badsec - altsp_srtsec] = ALTS_BAD; 210 (ap->ap_gbadp)[cnt].bad_start = (uint32_t)ALTS_ENT_EMPTY; 211 } else { 212 status = chk_bad_altsctr(badsec); 213 (ap->ap_gbadp)[cnt].bad_start = (uint32_t)ALTS_ENT_EMPTY; 214 } 215 } else { 216 /* 217 * binary search for bad sector in the alts entry table 218 */ 219 status = ent_bsearch(ap->ap_entp, ap->ap_tblp->alts_ent_used, 220 &((ap->ap_gbadp)[cnt])); 221 /* 222 * if the bad sector had already been remapped(found in alts_entry) 223 * then ignore the bad sector 224 */ 225 if (status != -1) { 226 (ap->ap_gbadp)[cnt].bad_start = (uint32_t)ALTS_ENT_EMPTY; 227 } 228 } 229 } 230 return (SUCCESS); 231 } 232 233 /* 234 * initialize the alternate partition tables 235 */ 236 static int 237 init_altsctr() 238 { 239 blkaddr_t badsec; 240 blkaddr_t altsp_srtsec = ap->part.p_start; 241 blkaddr_t altsp_endsec = ap->part.p_start + ap->part.p_size - 1; 242 int cnt; 243 244 ap->ap_entp = NULL; 245 ap->ap_ent_secsiz = 0; 246 ap->ap_tblp->alts_sanity = ALTS_SANITY; 247 ap->ap_tblp->alts_version = ALTS_VERSION1; 248 ap->ap_tblp->alts_map_len = (ap->part.p_size + 8 - 1) / 8; 249 ap->ap_tblp->alts_ent_used = 0; 250 ap->ap_tblp->alts_ent_base = 0; 251 ap->ap_tblp->alts_ent_end = 0; 252 ap->ap_tblp->alts_resv_base = ap->part.p_size - 1; 253 for (cnt = 0; cnt < 5; cnt++) 254 ap->ap_tblp->alts_pad[cnt] = 0; 255 256 for (cnt = 0; cnt < ap->ap_gbadcnt; cnt++) { 257 badsec = (ap->ap_gbadp)[cnt].bad_start; 258 if ((badsec >= altsp_srtsec) && (badsec <= altsp_endsec)) { 259 if (badsec == altsp_srtsec) { 260 (void) fprintf(stderr, 261 "First sector of alternate partition is bad.\n"); 262 return (56); 263 } 264 (ap->ap_memmapp)[badsec - altsp_srtsec] = ALTS_BAD; 265 (ap->ap_gbadp)[cnt].bad_start = (uint32_t)ALTS_ENT_EMPTY; 266 } 267 } 268 269 /* allocate the alts_map on disk skipping possible bad sectors */ 270 ap->ap_tblp->alts_map_base = 271 altsmap_alloc(ap->ap_tbl_secsiz / NBPSCTR, 272 ap->part.p_size, ap->ap_map_sectot, ALTS_MAP_UP); 273 if (ap->ap_tblp->alts_map_base == 0) { 274 perror("Unable to allocate alternate map on disk: "); 275 return (57); 276 } 277 (void) wr_altsctr(); 278 279 return (SUCCESS); 280 } 281 282 283 /* 284 * read the alternate partition tables from disk 285 */ 286 static int 287 get_altsctr(void) 288 { 289 int mystatus = FAILURE; 290 int status = 0; 291 292 /* get alts partition table info */ 293 294 status = ata_rdwr(DIR_READ, cur_file, altsec_offset, 295 ap->ap_tbl_secsiz / UBSIZE, (char *)ap->ap_tblp, 296 0, NULL); 297 if (status == FAILURE) { 298 perror("Unable to read alternate sector partition: "); 299 return (58); 300 } 301 if (ap->ap_tblp->alts_sanity != ALTS_SANITY) 302 return (mystatus); 303 304 /* get the alts map */ 305 status = ata_rdwr(DIR_READ, cur_file, 306 (ap->ap_tblp->alts_map_base) + altsec_offset, 307 ap->ap_map_secsiz / UBSIZE, (char *)ap->ap_mapp, 0, NULL); 308 if (status == FAILURE) { 309 perror("Unable to read alternate sector partition map: "); 310 return (59); 311 } 312 313 /* transform the disk image bit-map to incore char map */ 314 expand_map(); 315 316 if (ap->ap_tblp->alts_ent_used == 0) { 317 ap->ap_entp = NULL; 318 ap->ap_ent_secsiz = 0; 319 } else { 320 ap->ap_ent_secsiz = byte_to_secsiz( 321 (ap->ap_tblp->alts_ent_used*ALTS_ENT_SIZE), NBPSCTR); 322 if ((ap->ap_entp = 323 (struct alts_ent *)malloc(ap->ap_ent_secsiz)) == NULL) { 324 (void) fprintf(stderr, 325 "Unable to malloc alternate sector entry table.\n"); 326 return (60); 327 } 328 329 status = ata_rdwr(DIR_READ, cur_file, 330 (ap->ap_tblp->alts_ent_base) + altsec_offset, 331 ap->ap_ent_secsiz / UBSIZE, (char *)ap->ap_entp, 332 0, NULL); 333 if (status == FAILURE) { 334 perror("Unable to read alternate sector entry table: "); 335 return (61); 336 } 337 } 338 339 return (SUCCESS); 340 } 341 342 343 /* 344 * update the new alternate partition tables on disk 345 */ 346 int 347 wr_altsctr() 348 { 349 int status; 350 351 if (ap->ap_tblp == NULL) 352 return (0); 353 status = ata_rdwr(DIR_WRITE, cur_file, altsec_offset, 354 ap->ap_tbl_secsiz / UBSIZE, (char *)ap->ap_tblp, 0, NULL); 355 if (status) { 356 (void) printf("ata_rdwr status = %d need = %d\n", 357 status, ap->ap_tbl_secsiz / 512); 358 perror("Unable to write with ata_rdwr the alt sector part: "); 359 return (62); 360 } 361 362 if (ata_rdwr(DIR_WRITE, cur_file, (ap->ap_tblp->alts_map_base) + 363 altsec_offset, ap->ap_map_secsiz / UBSIZE, 364 (char *)ap->ap_mapp, 0, NULL) == FAILURE) { 365 perror("Unable to write alternate sector partition map: "); 366 return (63); 367 } 368 369 if (ap->ap_tblp->alts_ent_used != 0) { 370 if (ata_rdwr(DIR_WRITE, cur_file, 371 (ap->ap_tblp->alts_ent_base)+ altsec_offset, 372 ap->ap_ent_secsiz / UBSIZE, 373 (char *)ap->ap_entp, 0, NULL) == FAILURE) { 374 perror("Unable to write alternate sector entry table: "); 375 return (64); 376 } 377 } 378 return (0); 379 } 380 381 382 /* 383 * get a list of bad sector 384 */ 385 static void 386 get_badsec() 387 { 388 int cnt; 389 struct badsec_lst *blc_p; 390 blkaddr_t curbad; 391 blkaddr_t maxsec = cur_dtype->dtype_nhead * 392 cur_dtype->dtype_ncyl * 393 cur_dtype->dtype_nsect; 394 struct alts_ent *growbadp; 395 int i; 396 397 cnt = count_badsec(); 398 if (!cnt) { 399 ap->ap_gbadp = NULL; 400 ap->ap_gbadcnt = 0; 401 } else { 402 ap->ap_gbadp = malloc(cnt*ALTS_ENT_SIZE); 403 if (ap->ap_gbadp == NULL) { 404 err_print("get_badsec: unable to malloc %d bytes\n", 405 cnt*ALTS_ENT_SIZE); 406 fullabort(); 407 } 408 (void) memset(ap->ap_gbadp, 0, cnt*ALTS_ENT_SIZE); 409 410 for (growbadp = ap->ap_gbadp, cnt = 0, blc_p = badsl_chain; 411 blc_p; blc_p = blc_p->bl_nxt) { 412 for (i = 0; i < blc_p->bl_cnt; i++) { 413 curbad = blc_p->bl_sec[i]; 414 if (curbad < (blkaddr_t)cur_dtype->dtype_nsect) { 415 (void) fprintf(stderr, 416 "Ignoring bad sector %ld which is in first track of the drive.\n", curbad); 417 continue; 418 } 419 if (curbad >= maxsec) { 420 (void) fprintf(stderr, 421 "Ignoring bad sector %ld which is past the end of the drive.\n", curbad); 422 continue; 423 } 424 growbadp[cnt].bad_start = curbad; 425 growbadp[cnt].bad_end = curbad; 426 cnt++; 427 } 428 } 429 } 430 ap->ap_gbadcnt = cnt; 431 } 432 433 /* 434 * count number of bad sector on list 435 * merging the bad sector list from surface analysis and the 436 * one given through the command line 437 */ 438 static int 439 count_badsec() 440 { 441 442 struct badsec_lst *blc_p; 443 444 if (!badsl_chain) 445 badsl_chain = gbadsl_chain; 446 else { 447 for (blc_p = badsl_chain; blc_p->bl_nxt; blc_p = blc_p->bl_nxt) 448 ; 449 blc_p->bl_nxt = gbadsl_chain; 450 } 451 452 badsl_chain_cnt += gbadsl_chain_cnt; 453 return (badsl_chain_cnt); 454 } 455 456 457 /* 458 * generate alternate entry table by merging the existing and 459 * the new entry list. 460 */ 461 static int 462 gen_alts_ent() { 463 uint_t ent_used; 464 struct alts_ent *entp; 465 466 if (ap->ap_gbadcnt == 0) 467 return (0); 468 469 ent_used = ap->ap_tblp->alts_ent_used + ap->ap_gbadcnt; 470 ap->ap_ent_secsiz = byte_to_secsiz(ent_used*ALTS_ENT_SIZE, NBPSCTR); 471 entp = malloc(ap->ap_ent_secsiz); 472 if (entp == NULL) { 473 err_print("get_alts_ent: unable to malloc %d bytes\n", 474 ap->ap_ent_secsiz); 475 fullabort(); 476 } 477 478 ent_used = ent_merge(entp, ap->ap_entp, ap->ap_tblp->alts_ent_used, 479 ap->ap_gbadp, ap->ap_gbadcnt); 480 if (ap->ap_entp) 481 free(ap->ap_entp); 482 if (ap->ap_gbadp) 483 free(ap->ap_gbadp); 484 ap->ap_entp = entp; 485 ap->ap_ent_secsiz = byte_to_secsiz(ent_used*ALTS_ENT_SIZE, NBPSCTR); 486 ap->ap_tblp->alts_ent_used = ent_used; 487 ap->ap_gbadp = NULL; 488 ap->ap_gbadcnt = 0; 489 490 /* assign alternate sectors to the bad sectors */ 491 (void) assign_altsctr(); 492 493 /* allocate the alts_entry on disk skipping possible bad sectors */ 494 ap->ap_tblp->alts_ent_base = 495 altsmap_alloc((blkaddr_t)ap->ap_tblp->alts_map_base + 496 ap->ap_map_sectot, (blkaddr_t)ap->part.p_size, 497 ap->ap_ent_secsiz / NBPSCTR, ALTS_MAP_UP); 498 if (ap->ap_tblp->alts_ent_base == 0) { 499 perror("Unable to allocate alternate entry table on disk: "); 500 return (65); 501 } 502 503 ap->ap_tblp->alts_ent_end = ap->ap_tblp->alts_ent_base + 504 (ap->ap_ent_secsiz / NBPSCTR) - 1; 505 return (0); 506 } 507 508 509 /* 510 * assign alternate sectors for bad sector mapping 511 */ 512 static int 513 assign_altsctr() 514 { 515 uint_t i; 516 uint_t j; 517 blkaddr_t alts_ind; 518 uint_t cluster; 519 520 for (i = 0; i < ap->ap_tblp->alts_ent_used; i++) { 521 if ((ap->ap_entp)[i].bad_start == (uint32_t)ALTS_ENT_EMPTY) 522 continue; 523 if ((ap->ap_entp)[i].good_start != 0) 524 continue; 525 cluster = (ap->ap_entp)[i].bad_end-(ap->ap_entp)[i].bad_start +1; 526 alts_ind = 527 altsmap_alloc(ap->part.p_size-1, ap->ap_tblp->alts_map_base + 528 ap->ap_map_sectot - 1, cluster, ALTS_MAP_DOWN); 529 if (alts_ind == 0) { 530 (void) fprintf(stderr, 531 "Unable to allocate alternates for bad starting sector %u.\n", 532 (ap->ap_entp)[i].bad_start); 533 return (65); 534 } 535 alts_ind = alts_ind - cluster + 1; 536 (ap->ap_entp)[i].good_start = alts_ind +ap->part.p_start; 537 for (j = 0; j < cluster; j++) { 538 (ap->ap_memmapp)[alts_ind+j] = ALTS_BAD; 539 } 540 541 } 542 return (SUCCESS); 543 } 544 545 /* 546 * transform the disk image alts bit map to incore char map 547 */ 548 static void 549 expand_map(void) 550 { 551 int i; 552 553 for (i = 0; i < ap->part.p_size; i++) { 554 (ap->ap_memmapp)[i] = altsmap_getbit(i); 555 } 556 } 557 558 /* 559 * transform the incore alts char map to the disk image bit map 560 */ 561 static void 562 compress_map(void) 563 { 564 int i; 565 int bytesz; 566 char mask = 0; 567 int maplen = 0; 568 569 for (i = 0, bytesz = 7; i < ap->part.p_size; i++) { 570 mask |= ((ap->ap_memmapp)[i] << bytesz--); 571 if (bytesz < 0) { 572 (ap->ap_mapp)[maplen++] = mask; 573 bytesz = 7; 574 mask = 0; 575 } 576 } 577 /* 578 * if partition size != multiple number of bytes 579 * then record the last partial byte 580 */ 581 if (bytesz != 7) 582 (ap->ap_mapp)[maplen] = mask; 583 584 } 585 586 /* 587 * given a bad sector number, search in the alts bit map 588 * and identify the sector as good or bad 589 */ 590 static int 591 altsmap_getbit(badsec) 592 blkaddr_t badsec; 593 { 594 uint_t slot = badsec / 8; 595 uint_t field = badsec % 8; 596 uchar_t mask; 597 598 mask = ALTS_BAD<<7; 599 mask >>= field; 600 if ((ap->ap_mapp)[slot] & mask) 601 return (ALTS_BAD); 602 return (ALTS_GOOD); 603 } 604 605 606 /* 607 * allocate a range of sectors from the alternate partition 608 */ 609 static blkaddr_t 610 altsmap_alloc(srt_ind, end_ind, cnt, dir) 611 blkaddr_t srt_ind; 612 blkaddr_t end_ind; 613 int cnt; 614 int dir; 615 { 616 blkaddr_t i; 617 blkaddr_t total; 618 blkaddr_t first_ind; 619 620 for (i = srt_ind, first_ind = srt_ind, total = 0; 621 i != end_ind; i += dir) { 622 if ((ap->ap_memmapp)[i] == ALTS_BAD) { 623 total = 0; 624 first_ind = i + dir; 625 continue; 626 } 627 total++; 628 if (total == cnt) 629 return (first_ind); 630 631 } 632 return (0); 633 } 634 635 636 637 /* 638 * bubble sort the entry table into ascending order 639 */ 640 static void 641 ent_sort(buf, cnt) 642 struct alts_ent buf[]; 643 int cnt; 644 { 645 struct alts_ent temp; 646 int flag; 647 int i, j; 648 649 for (i = 0; i < cnt-1; i++) { 650 temp = buf[cnt-1]; 651 flag = 1; 652 653 for (j = cnt-1; j > i; j--) { 654 if (buf[j-1].bad_start < temp.bad_start) { 655 buf[j] = temp; 656 temp = buf[j-1]; 657 } else { 658 buf[j] = buf[j-1]; 659 flag = 0; 660 } 661 } 662 buf[i] = temp; 663 if (flag) break; 664 } 665 666 } 667 668 669 /* 670 * compress all the contiguous bad sectors into a single entry 671 * in the entry table. The entry table must be sorted into ascending 672 * before the compression. 673 */ 674 static void 675 ent_compress(buf, cnt) 676 struct alts_ent buf[]; 677 int cnt; 678 { 679 int keyp; 680 int movp; 681 int i; 682 683 for (i = 0; i < cnt; i++) { 684 if (buf[i].bad_start == (uint32_t)ALTS_ENT_EMPTY) 685 continue; 686 for (keyp = i, movp = i+1; movp < cnt; movp++) { 687 if (buf[movp].bad_start == (uint32_t)ALTS_ENT_EMPTY) 688 continue; 689 if (buf[keyp].bad_end+1 != buf[movp].bad_start) 690 break; 691 buf[keyp].bad_end++; 692 buf[movp].bad_start = (uint32_t)ALTS_ENT_EMPTY; 693 } 694 if (movp == cnt) break; 695 } 696 } 697 698 699 /* 700 * merging two entry tables into a single table. In addition, 701 * all empty slots in the entry table will be removed. 702 */ 703 static int 704 ent_merge(buf, list1, lcnt1, list2, lcnt2) 705 struct alts_ent buf[]; 706 struct alts_ent list1[]; 707 int lcnt1; 708 struct alts_ent list2[]; 709 int lcnt2; 710 { 711 int i; 712 int j1, j2; 713 714 for (i = 0, j1 = 0, j2 = 0; j1 < lcnt1 && j2 < lcnt2; ) { 715 if (list1[j1].bad_start == (uint32_t)ALTS_ENT_EMPTY) { 716 j1++; 717 continue; 718 } 719 if (list2[j2].bad_start == (uint32_t)ALTS_ENT_EMPTY) { 720 j2++; 721 continue; 722 } 723 if (list1[j1].bad_start < list2[j2].bad_start) 724 buf[i++] = list1[j1++]; 725 else 726 buf[i++] = list2[j2++]; 727 } 728 for (; j1 < lcnt1; j1++) { 729 if (list1[j1].bad_start == (uint32_t)ALTS_ENT_EMPTY) 730 continue; 731 buf[i++] = list1[j1]; 732 } 733 for (; j2 < lcnt2; j2++) { 734 if (list2[j2].bad_start == (uint32_t)ALTS_ENT_EMPTY) 735 continue; 736 buf[i++] = list2[j2]; 737 } 738 return (i); 739 } 740 741 742 /* 743 * binary search for bad sector in the alternate entry table 744 */ 745 static int 746 ent_bsearch(buf, cnt, key) 747 struct alts_ent buf[]; 748 int cnt; 749 struct alts_ent *key; 750 { 751 int i; 752 int ind; 753 int interval; 754 int mystatus = -1; 755 756 if (!cnt) 757 return (mystatus); 758 759 for (i = 1; i <= cnt; i <<= 1) 760 ind = i; 761 762 for (interval = ind; interval; ) { 763 if ((key->bad_start >= buf[ind-1].bad_start) && 764 (key->bad_start <= buf[ind-1].bad_end)) { 765 return (mystatus = ind-1); 766 } else { 767 interval >>= 1; 768 if (!interval) break; 769 if (key->bad_start < buf[ind-1].bad_start) { 770 ind = ind - interval; 771 } else { 772 /* if key is larger than the last element then break */ 773 if (ind == cnt) break; 774 if ((ind+interval) <= cnt) 775 ind += interval; 776 } 777 } 778 } 779 return (mystatus); 780 } 781 782 /* 783 * check for bad sector in assigned alternate sectors 784 */ 785 static int 786 chk_bad_altsctr(badsec) 787 blkaddr_t badsec; 788 { 789 int i; 790 blkaddr_t numsec; 791 int cnt = ap->ap_tblp->alts_ent_used; 792 /* 793 * daddr_t intv[3]; 794 */ 795 796 for (i = 0; i < cnt; i++) { 797 numsec = (ap->ap_entp)[i].bad_end - (ap->ap_entp)[i].bad_start; 798 if ((badsec >= (ap->ap_entp)[i].good_start) && 799 (badsec <= ((ap->ap_entp)[i].good_start + numsec))) { 800 (void) fprintf(stderr, 801 "Bad sector %ld is an assigned alternate sector.\n", badsec); 802 return (66); 803 /* 804 * if (!numsec) { 805 * (ap->ap_entp)[i].good_start = 0; 806 * return (FAILURE); 807 * } 808 * intv[0] = badsec - (ap->ap_entp)[i].good_start; 809 * intv[1] = 1; 810 * intv[2] = (ap->ap_entp)[i].good_start + numsec - badsec; 811 */ 812 } 813 } 814 /* the bad sector has already been identified as bad */ 815 return (SUCCESS); 816 817 } 818