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