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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 * copyright (c) 1990, 1991 UNIX System Laboratories, Inc.
26 * copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T
27 * All rights reserved.
31 * Copyrighted as an unpublished work.
32 * (c) Copyright INTERACTIVE Systems Corporation 1986, 1988, 1990
33 * All rights reserved.
36 #include <sys/types.h>
47 #include <sys/param.h>
49 #include <sys/dktp/altsctr.h>
50 #include <sys/dktp/fdisk.h>
59 struct badsec_lst
*badsl_chain
;
61 struct badsec_lst
*gbadsl_chain
;
64 extern struct dk_geom dkg
;
67 struct alts_mempart alts_part
= { 0, NULL
, 0 };
68 struct alts_mempart
*ap
= &alts_part
; /* pointer to incore alts tables */
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
,
83 static void ent_sort(struct alts_ent buf
[], int cnt
);
84 static void ent_compress(struct alts_ent buf
[], int cnt
);
86 struct alts_ent buf
[],
87 struct alts_ent list1
[],
89 struct alts_ent list2
[],
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
);
95 static void print_altsctr(void);
96 static int absdsk_io(int fd
, uint_t srtsec
, char *bufp
, uint_t len
,
100 * updatebadsec () -- update bad sector/track mapping tables
103 updatebadsec(struct extpartition
*part
, int init_flag
)
106 ap
->ap_flag
|= ALTS_ADDPART
;
108 read_altsctr(part
, 1);
109 ent_sort(ap
->ap_gbadp
, ap
->ap_gbadcnt
);
110 ent_compress(ap
->ap_gbadp
, ap
->ap_gbadcnt
);
117 * read_altsctr( ptr to alternate sector partition )
118 * -- read the alternate sector partition tables
121 read_altsctr(struct extpartition
*part
, int badok
)
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");
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 */
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");
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
,
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");
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 */
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
161 if (ap
->ap_flag
& ALTS_ADDPART
) {
162 (void) fprintf(stderr
,
163 "WARNING: Manually initializing alternate table.\n");
166 if (get_altsctr(badok
) == SUCCESS
)
176 * checking duplicate bad sectors or bad sectors in ALTSCTR partition
182 blkaddr_t altsp_srtsec
= ap
->part
.p_start
;
183 blkaddr_t altsp_endsec
= ap
->part
.p_start
+ ap
->part
.p_size
- 1;
187 for (cnt
= 0; cnt
< ap
->ap_gbadcnt
; cnt
++) {
188 badsec
= (ap
->ap_gbadp
)[cnt
].bad_start
;
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");
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");
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");
213 (ap
->ap_memmapp
)[badsec
- altsp_srtsec
] = ALTS_BAD
;
214 (ap
->ap_gbadp
)[cnt
].bad_start
= (uint32_t)ALTS_ENT_EMPTY
;
216 status
= chk_bad_altsctr(badsec
);
217 (ap
->ap_gbadp
)[cnt
].bad_start
= (uint32_t)ALTS_ENT_EMPTY
;
221 * binary search for bad sector in the alts entry table
223 status
= ent_bsearch(ap
->ap_entp
, ap
->ap_tblp
->alts_ent_used
,
224 &((ap
->ap_gbadp
)[cnt
]));
226 * if the bad sector had already been remapped(found in alts_entry)
227 * then ignore the bad sector
230 (ap
->ap_gbadp
)[cnt
].bad_start
= (uint32_t)ALTS_ENT_EMPTY
;
238 * initialize the alternate partition tables
244 blkaddr_t altsp_srtsec
= ap
->part
.p_start
;
245 blkaddr_t altsp_endsec
= ap
->part
.p_start
+ ap
->part
.p_size
- 1;
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;
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");
268 (ap
->ap_memmapp
)[badsec
- altsp_srtsec
] = ALTS_BAD
;
269 (ap
->ap_gbadp
)[cnt
].bad_start
= (uint32_t)ALTS_ENT_EMPTY
;
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: ");
286 * read the alternate partition tables from disk
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
) {
297 perror("Unable to read alternate sector partition: ");
300 if (ap
->ap_tblp
->alts_sanity
!= ALTS_SANITY
) {
303 (void) fprintf(stderr
, "Bad alternate sector magic number.\n");
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
) {
312 perror("Unable to read alternate sector partition map: ");
316 /* transform the disk image bit-map to incore char map */
319 if (ap
->ap_tblp
->alts_ent_used
== 0) {
321 ap
->ap_ent_secsiz
= 0;
323 ap
->ap_ent_secsiz
= byte_to_secsiz(
324 (ap
->ap_tblp
->alts_ent_used
*ALTS_ENT_SIZE
),NBPSCTR
);
326 (struct alts_ent
*)malloc(ap
->ap_ent_secsiz
)) == NULL
) {
329 (void) fprintf(stderr
,
330 "Unable to malloc alternate sector entry table.\n");
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
){
339 perror("Unable to read alternate sector entry table: ");
348 * update the new alternate partition tables on disk
353 if (ap
->ap_tblp
== NULL
)
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: ");
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: ");
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: ");
379 * get a list of bad sector
385 struct badsec_lst
*blc_p
;
387 blkaddr_t maxsec
= (blkaddr_t
)dkg
.dkg_nhead
*
388 dkg
.dkg_ncyl
* dkg
.dkg_nsect
;
389 struct alts_ent
*growbadp
;
392 cnt
= count_badsec();
397 ap
->ap_gbadp
= (struct alts_ent
*)malloc(cnt
*ALTS_ENT_SIZE
);
398 (void) memset(ap
->ap_gbadp
,0,cnt
*ALTS_ENT_SIZE
);
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
);
410 if (curbad
>= maxsec
) {
411 (void) fprintf(stderr
,
412 "Ignoring bad sector %ld which is past"
413 " the end of the drive.\n", curbad
);
416 growbadp
[cnt
].bad_start
= curbad
;
417 growbadp
[cnt
].bad_end
= curbad
;
422 ap
->ap_gbadcnt
= cnt
;
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
434 struct badsec_lst
*blc_p
;
437 badsl_chain
= gbadsl_chain
;
439 for (blc_p
= badsl_chain
; blc_p
->bl_nxt
; blc_p
= blc_p
->bl_nxt
)
441 blc_p
->bl_nxt
= gbadsl_chain
;
444 badsl_chain_cnt
+= gbadsl_chain_cnt
;
445 return(badsl_chain_cnt
);
450 * generate alternate entry table by merging the existing and
451 * the new entry list.
457 struct alts_ent
*entp
;
459 if (ap
->ap_gbadcnt
== 0)
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
);
472 ap
->ap_ent_secsiz
= byte_to_secsiz(ent_used
*ALTS_ENT_SIZE
, NBPSCTR
);
473 ap
->ap_tblp
->alts_ent_used
= ent_used
;
477 /* assign alternate sectors to the bad sectors */
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
,
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: ");
490 ap
->ap_tblp
->alts_ent_end
= ap
->ap_tblp
->alts_ent_base
+
491 (ap
->ap_ent_secsiz
/ NBPSCTR
) - 1;
496 * assign alternate sectors for bad sector mapping
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
)
509 if ((ap
->ap_entp
)[i
].good_start
!= 0)
511 cluster
= (ap
->ap_entp
)[i
].bad_end
-(ap
->ap_entp
)[i
].bad_start
+1;
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
);
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
;
532 * transform the disk image alts bit map to incore char map
539 for (i
= 0; i
< ap
->part
.p_size
; i
++) {
540 (ap
->ap_memmapp
)[i
] = altsmap_getbit(i
);
545 * transform the incore alts char map to the disk image bit map
556 for (i
= 0, bytesz
= 7; i
< ap
->part
.p_size
; i
++) {
557 mask
|= ((ap
->ap_memmapp
)[i
] << bytesz
--);
559 (ap
->ap_mapp
)[maplen
++] = mask
;
565 * if partition size != multiple number of bytes
566 * then record the last partial byte
569 (ap
->ap_mapp
)[maplen
] = mask
;
574 * given a bad sector number, search in the alts bit map
575 * and identify the sector as good or bad
578 altsmap_getbit(blkaddr_t badsec
)
580 uint_t slot
= badsec
/ 8;
581 uint_t field
= badsec
% 8;
586 if ((ap
->ap_mapp
)[slot
] & mask
)
593 * allocate a range of sectors from the alternate partition
596 altsmap_alloc(blkaddr_t srt_ind
, blkaddr_t end_ind
, int cnt
, int dir
)
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
) {
620 * bubble sort the entry table into ascending order
623 ent_sort(struct alts_ent buf
[], int cnt
)
625 struct alts_ent temp
;
629 for (i
= 0; i
< cnt
-1; i
++) {
633 for (j
= cnt
-1; j
> i
; j
--) {
634 if (buf
[j
-1].bad_start
< temp
.bad_start
) {
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.
655 ent_compress(struct alts_ent buf
[], int cnt
)
661 for (i
= 0; i
< cnt
; i
++) {
662 if (buf
[i
].bad_start
== (uint32_t)ALTS_ENT_EMPTY
)
664 for (keyp
= i
, movp
= i
+1; movp
< cnt
; movp
++) {
665 if (buf
[movp
].bad_start
== (uint32_t)ALTS_ENT_EMPTY
)
667 if (buf
[keyp
].bad_end
+1 != buf
[movp
].bad_start
)
670 buf
[movp
].bad_start
= (uint32_t)ALTS_ENT_EMPTY
;
672 if (movp
== cnt
) break;
678 * merging two entry tables into a single table. In addition,
679 * all empty slots in the entry table will be removed.
683 struct alts_ent buf
[],
684 struct alts_ent list1
[],
686 struct alts_ent list2
[],
692 for (i
= 0, j1
= 0, j2
= 0; j1
< lcnt1
&& j2
< lcnt2
; ) {
693 if (list1
[j1
].bad_start
== (uint32_t)ALTS_ENT_EMPTY
) {
697 if (list2
[j2
].bad_start
== (uint32_t)ALTS_ENT_EMPTY
) {
701 if (list1
[j1
].bad_start
< list2
[j2
].bad_start
)
702 buf
[i
++] = list1
[j1
++];
704 buf
[i
++] = list2
[j2
++];
706 for (; j1
< lcnt1
; j1
++) {
707 if (list1
[j1
].bad_start
== (uint32_t)ALTS_ENT_EMPTY
)
709 buf
[i
++] = list1
[j1
];
711 for (; j2
< lcnt2
; j2
++) {
712 if (list2
[j2
].bad_start
== (uint32_t)ALTS_ENT_EMPTY
)
714 buf
[i
++] = list2
[j2
];
721 * binary search for bad sector in the alternate entry table
724 ent_bsearch(struct alts_ent buf
[], int cnt
, struct alts_ent
*key
)
734 for (i
= 1; i
<= cnt
; i
<<= 1)
737 for (interval
= ind
; interval
; ) {
739 printf("ind= %d, intv= %d; ",ind, interval);
741 if ((key
->bad_start
>= buf
[ind
-1].bad_start
) &&
742 (key
->bad_start
<= buf
[ind
-1].bad_end
)) {
743 return(mystatus
= ind
-1);
746 if (!interval
) break;
747 if (key
->bad_start
< buf
[ind
-1].bad_start
) {
748 ind
= ind
- interval
;
750 /* if key is larger than the last element then break */
751 if (ind
== cnt
) break;
752 if ((ind
+interval
) <= cnt
)
761 * check for bad sector in assigned alternate sectors
764 chk_bad_altsctr(blkaddr_t badsec
)
768 int cnt
= ap
->ap_tblp
->alts_ent_used
;
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
);
782 * (ap->ap_entp)[i].good_start = 0;
785 * intv[0] = badsec - (ap->ap_entp)[i].good_start;
787 * intv[2] = (ap->ap_entp)[i].good_start + numsec - badsec;
791 /* the bad sector has already been identified as bad */
797 * print_altsec () -- print alternate sector information
800 print_altsec(struct extpartition
*part
)
803 ap
->ap_flag
&= ~ALTS_ADDPART
;
804 read_altsctr(part
, 0);
816 /* find # of available alternate sectors */
817 for (i
=0, totalloc
=0; i
<ap
->part
.p_size
; i
++) {
818 if ((ap
->ap_memmapp
)[i
])
822 * available = size of partition - allocated sectors/bad sectors
823 * - partition table - partition map
826 avail
= ap
->part
.p_size
- totalloc
;
827 avail
= avail
- (ap
->ap_tbl_secsiz
/NBPSCTR
)
829 avail
= avail
-(ap
->ap_tblp
->alts_ent_end
-ap
->ap_tblp
->alts_ent_base
+1);
830 if (avail
< 0) avail
= 0;
832 (void) printf("\nALTERNATE SECTOR/TRACK MAPPING TABLE:\n");
833 (void) printf("\nBad Sector Start\tAlternate Sector Start\t\tCount\n");
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));
841 (void) printf("\n %d alternate sector(s) left for allocation.\n",
847 absdsk_io(int fd
, uint_t srtsec
, char *bufp
, uint_t len
, int ioflag
)
851 if (llseek (fd
, (offset_t
)srtsec
* NBPSCTR
, SEEK_SET
) == -1)
856 rc
= read (fd
, bufp
, len
);
859 rc
= write (fd
, bufp
, len
);