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