xref: /netbsd-src/sys/arch/atari/atari/disksubr.c (revision 2a399c6883d870daece976daec6ffa7bb7f934ce)
1 /*	$NetBSD: disksubr.c,v 1.13 1997/04/25 19:16:30 leo Exp $	*/
2 
3 /*
4  * Copyright (c) 1995 Leo Weppelman.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by Leo Weppelman.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #ifndef DISKLABEL_NBDA
34 #define	DISKLABEL_NBDA	/* required */
35 #endif
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/buf.h>
40 #include <ufs/ffs/fs.h>
41 #include <sys/disk.h>
42 #include <sys/disklabel.h>
43 #include <machine/ahdilabel.h>
44 
45 /*
46  * BBSIZE in <ufs/ffs/fs.h> must be greater than
47  * or equal to BBMINSIZE in <machine/disklabel.h>
48  */
49 #if BBSIZE < BBMINSIZE
50 #error BBSIZE smaller than BBMINSIZE
51 #endif
52 
53 static void  ck_label __P((struct disklabel *, struct cpu_disklabel *));
54 static int   bsd_label __P((dev_t, void (*)(struct buf *),
55 			struct disklabel *, u_int, u_int *));
56 static int   ahdi_label __P((dev_t, void (*)(struct buf *),
57 			struct disklabel *, struct cpu_disklabel *));
58 static void  ahdi_to_bsd __P((struct disklabel *, struct ahdi_ptbl *));
59 static u_int ahdi_getparts __P((dev_t, void (*)(struct buf *), u_int,
60 					u_int, u_int, struct ahdi_ptbl *));
61 
62 /*
63  * XXX unknown function but needed for /sys/scsi to link
64  */
65 void
66 dk_establish(disk, device)
67 	struct disk	*disk;
68 	struct device	*device;
69 {
70 }
71 
72 /*
73  * Determine the size of the transfer, and make sure it is
74  * within the boundaries of the partition. Adjust transfer
75  * if needed, and signal errors or early completion.
76  */
77 int
78 bounds_check_with_label(bp, lp, wlabel)
79 	struct buf		*bp;
80 	struct disklabel	*lp;
81 	int			wlabel;
82 {
83 	struct partition	*pp;
84 	u_int			maxsz, sz;
85 
86 	pp = &lp->d_partitions[DISKPART(bp->b_dev)];
87 	if (bp->b_flags & B_RAW) {
88 		if (bp->b_bcount & (lp->d_secsize - 1)) {
89 			bp->b_error = EINVAL;
90 			bp->b_flags |= B_ERROR;
91 			return(-1);
92 		}
93 		if (lp->d_secsize < DEV_BSIZE)
94 			maxsz = pp->p_size / (DEV_BSIZE / lp->d_secsize);
95 		else maxsz = pp->p_size * (lp->d_secsize / DEV_BSIZE);
96 		sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;
97 	} else {
98 		maxsz = pp->p_size;
99 		sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize;
100 	}
101 
102 	if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) {
103 		if (bp->b_blkno == maxsz) {
104 			/*
105 			 * trying to get one block beyond return EOF.
106 			 */
107 			bp->b_resid = bp->b_bcount;
108 			return(0);
109 		}
110 		if (bp->b_blkno > maxsz || bp->b_blkno < 0) {
111 			bp->b_error = EINVAL;
112 			bp->b_flags |= B_ERROR;
113 			return(-1);
114 		}
115 		sz = maxsz - bp->b_blkno;
116 
117 		/*
118 		 * adjust count down
119 		 */
120 		if (bp->b_flags & B_RAW)
121 			bp->b_bcount = sz << DEV_BSHIFT;
122 		else bp->b_bcount = sz * lp->d_secsize;
123 	}
124 
125 	/*
126 	 * calc cylinder for disksort to order transfers with
127 	 */
128 	bp->b_cylinder = (bp->b_blkno + pp->p_offset) / lp->d_secpercyl;
129 	return(1);
130 }
131 
132 /*
133  * Attempt to read a disk label from a device using the
134  * indicated strategy routine. The label must be partly
135  * set up before this:
136  * secpercyl and anything required in the strategy routine
137  * (e.g. sector size) must be filled in before calling us.
138  * Returns NULL on success and an error string on failure.
139  */
140 char *
141 readdisklabel(dev, strat, lp, clp)
142 	dev_t			dev;
143 	void			(*strat)(struct buf *);
144 	struct disklabel	*lp;
145 	struct cpu_disklabel	*clp;
146 {
147 	int			e;
148 
149 	bzero(clp, sizeof *clp);
150 
151 	/*
152 	 * Give some guaranteed validity to the disk label.
153 	 */
154 	if (lp->d_secsize == 0)
155 		lp->d_secsize = DEV_BSIZE;
156 	if (lp->d_secperunit == 0)
157 		lp->d_secperunit = 0x1fffffff;
158 	if (lp->d_secpercyl == 0)
159 		return("Zero secpercyl");
160 	bzero(lp->d_partitions, sizeof lp->d_partitions);
161 	lp->d_partitions[RAW_PART].p_size = lp->d_secperunit;
162 	lp->d_npartitions                 = RAW_PART + 1;
163 	lp->d_bbsize                      = BBSIZE;
164 	lp->d_sbsize                      = SBSIZE;
165 
166 #ifdef DISKLABEL_NBDA
167 	/* Try the native NetBSD/Atari format first. */
168 	e = bsd_label(dev, strat, lp, 0, &clp->cd_label);
169 #endif
170 #if 0
171 	/* Other label formats go here. */
172 	if (e > 0)
173 		e = foo_label(dev, strat, lp, ...);
174 #endif
175 #ifdef DISKLABEL_AHDI
176 	/* The unprotected AHDI format comes last. */
177 	if (e > 0)
178 		e = ahdi_label(dev, strat, lp, clp);
179 #endif
180 	if (e < 0)
181 		return("I/O error");
182 
183 	/* Unknown format or unitialised volume? */
184 	if (e > 0)
185 		uprintf("Warning: unknown disklabel format"
186 			"- assuming empty disk\n");
187 
188 	/* Calulate new checksum. */
189 	lp->d_magic = lp->d_magic2 = DISKMAGIC;
190 	lp->d_checksum = 0;
191 	lp->d_checksum = dkcksum(lp);
192 
193 	return(NULL);
194 }
195 
196 /*
197  * Check new disk label for sensibility before setting it.
198  */
199 int
200 setdisklabel(olp, nlp, openmask, clp)
201 	struct disklabel	*olp, *nlp;
202 	u_long			openmask;
203 	struct cpu_disklabel	*clp;
204 {
205 	/* special case to allow disklabel to be invalidated */
206 	if (nlp->d_magic == 0xffffffff) {
207 		*olp = *nlp;
208 		return(0);
209 	}
210 
211 	/* sanity clause */
212 	if (nlp->d_secpercyl == 0 || nlp->d_npartitions > MAXPARTITIONS
213 	  || nlp->d_secsize  == 0 || (nlp->d_secsize % DEV_BSIZE) != 0
214 	  || nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC
215 	  || dkcksum(nlp) != 0)
216 		return(EINVAL);
217 
218 #ifdef DISKLABEL_AHDI
219 	if (clp->cd_bblock)
220 		ck_label(nlp, clp);
221 #endif
222 	while (openmask) {
223 		struct partition *op, *np;
224 		int i = ffs(openmask) - 1;
225 		openmask &= ~(1 << i);
226 		if (i >= nlp->d_npartitions)
227 			return(EBUSY);
228 		op = &olp->d_partitions[i];
229 		np = &nlp->d_partitions[i];
230 		if (np->p_offset != op->p_offset || np->p_size < op->p_size)
231 			return(EBUSY);
232 		/*
233 		 * Copy internally-set partition information
234 		 * if new label doesn't include it.		XXX
235 		 */
236 		if (np->p_fstype == FS_UNUSED && op->p_fstype != FS_UNUSED) {
237 			np->p_fstype = op->p_fstype;
238 			np->p_fsize  = op->p_fsize;
239 			np->p_frag   = op->p_frag;
240 			np->p_cpg    = op->p_cpg;
241 		}
242 	}
243  	nlp->d_checksum = 0;
244  	nlp->d_checksum = dkcksum(nlp);
245 	*olp = *nlp;
246 	return(0);
247 }
248 
249 /*
250  * Write disk label back to device after modification.
251  */
252 int
253 writedisklabel(dev, strat, lp, clp)
254 	dev_t			dev;
255 	void			(*strat)(struct buf *);
256 	struct disklabel	*lp;
257 	struct cpu_disklabel	*clp;
258 {
259 	struct buf		*bp;
260 	u_int			blk;
261 	int			rv;
262 
263 	blk = clp->cd_bblock;
264 	if (blk == NO_BOOT_BLOCK)
265 		return(ENXIO);
266 
267 	bp = geteblk(BBMINSIZE);
268 	bp->b_dev      = MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART);
269 	bp->b_flags    = B_BUSY | B_READ;
270 	bp->b_bcount   = BBMINSIZE;
271 	bp->b_blkno    = blk;
272 	bp->b_cylinder = blk / lp->d_secpercyl;
273 	(*strat)(bp);
274 	rv = biowait(bp);
275 	if (!rv) {
276 		struct bootblock *bb = (struct bootblock *)bp->b_data;
277 		/*
278 		 * Allthough the disk pack label may appear anywhere
279 		 * in the boot block while reading, it is always
280 		 * written at a fixed location.
281 		 */
282 		if (clp->cd_label != LABELOFFSET) {
283 			clp->cd_label = LABELOFFSET;
284 			bzero(bb, sizeof(*bb));
285 		}
286 		bb->bb_magic = (blk == 0) ? NBDAMAGIC : AHDIMAGIC;
287 		BBSETLABEL(bb, lp);
288 
289 		bp->b_flags    = B_BUSY | B_WRITE;
290 		bp->b_bcount   = BBMINSIZE;
291 		bp->b_blkno    = blk;
292 		bp->b_cylinder = blk / lp->d_secpercyl;
293 		(*strat)(bp);
294 		rv = biowait(bp);
295 	}
296 	bp->b_flags |= B_INVAL | B_AGE;
297 	brelse(bp);
298 	return(rv);
299 }
300 
301 /*
302  * Read bootblock at block `blkno' and check
303  * if it contains a valid NetBSD disk label.
304  *
305  * Returns:  0 if successfull,
306  *          -1 if an I/O error occured,
307  *          +1 if no valid label was found.
308  */
309 static int
310 bsd_label(dev, strat, label, blkno, offset)
311 	dev_t			dev;
312 	void			(*strat)(struct buf *);
313 	struct disklabel	*label;
314 	u_int			blkno,
315 				*offset;
316 {
317 	struct buf		*bp;
318 	int			rv;
319 
320 	bp = geteblk(BBMINSIZE);
321 	bp->b_dev      = MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART);
322 	bp->b_flags    = B_BUSY | B_READ;
323 	bp->b_bcount   = BBMINSIZE;
324 	bp->b_blkno    = blkno;
325 	bp->b_cylinder = blkno / label->d_secpercyl;
326 	(*strat)(bp);
327 
328 	rv = -1;
329 	if (!biowait(bp)) {
330 		struct bootblock *bb;
331 		u_int32_t   *p, *end;
332 
333 		rv  = 1;
334 		bb  = (struct bootblock *)bp->b_data;
335 		end = (u_int32_t *)((char *)&bb[1] - sizeof(struct disklabel));
336 		for (p = (u_int32_t *)bb; p < end; ++p) {
337 			struct disklabel *dl = (struct disklabel *)&p[1];
338 			/*
339 			 * Compatibility kludge: the boot block magic number is
340 			 * new in 1.1A, in previous versions the disklabel was
341 			 * stored at the end of the boot block (offset 7168).
342 			 */
343 			if (  (  (p[0] == NBDAMAGIC && blkno == 0)
344 			      || (p[0] == AHDIMAGIC && blkno != 0)
345 #ifdef COMPAT_11
346 			      || (char *)dl - (char *)bb == 7168
347 #endif
348 			      )
349 			   && dl->d_npartitions <= MAXPARTITIONS
350 			   && dl->d_magic2 == DISKMAGIC
351 			   && dl->d_magic  == DISKMAGIC
352 		  	   && dkcksum(dl)  == 0
353 			   )	{
354 				*offset = (char *)dl - (char *)bb;
355 				*label  = *dl;
356 				rv      = 0;
357 				break;
358 			}
359 		}
360 	}
361 
362 	bp->b_flags = B_INVAL | B_AGE | B_READ;
363 	brelse(bp);
364 	return(rv);
365 }
366 
367 #ifdef DISKLABEL_AHDI
368 /*
369  * Check for consistency between the NetBSD partition table
370  * and the AHDI auxilary root sectors. There's no good reason
371  * to force such consistency, but issueing a warning may help
372  * an inexperienced sysadmin to prevent corruption of AHDI
373  * partitions.
374  */
375 static void
376 ck_label(dl, cdl)
377 	struct disklabel	*dl;
378 	struct cpu_disklabel	*cdl;
379 {
380 	u_int			*rp, i;
381 
382 	for (i = 0; i < dl->d_npartitions; ++i) {
383 		struct partition *p = &dl->d_partitions[i];
384 		if (i == RAW_PART || p->p_size == 0)
385 			continue;
386 		if ( (p->p_offset >= cdl->cd_bslst
387 		   && p->p_offset <= cdl->cd_bslend)
388 		  || (cdl->cd_bslst >= p->p_offset
389 		   && cdl->cd_bslst <  p->p_offset + p->p_size)) {
390 			uprintf("Warning: NetBSD partition %c includes"
391 				" AHDI bad sector list\n", 'a'+i);
392 		}
393 		for (rp = &cdl->cd_roots[0]; *rp; ++rp) {
394 			if (*rp >= p->p_offset
395 			  && *rp < p->p_offset + p->p_size) {
396 				uprintf("Warning: NetBSD partition %c"
397 				" includes AHDI auxilary root\n", 'a'+i);
398 			}
399 		}
400 	}
401 }
402 
403 /*
404  * Check volume for the existance of an AHDI label. Fetch
405  * NetBSD label from NBD or RAW partition, or otherwise
406  * create a fake NetBSD label based on the AHDI label.
407  *
408  * Returns:  0 if successful,
409  *          -1 if an I/O error occured,
410  *          +1 if no valid AHDI label was found.
411  */
412 int
413 ahdi_label(dev, strat, dl, cdl)
414 	dev_t			dev;
415 	void			(*strat)(struct buf *);
416 	struct disklabel	*dl;
417 	struct cpu_disklabel	*cdl;
418 {
419 	struct ahdi_ptbl	apt;
420 	u_int			i;
421 	int			j;
422 
423 	/*
424 	 * The AHDI format requires a specific block size.
425 	 */
426 	if (dl->d_secsize != AHDI_BSIZE)
427 		return(1);
428 
429 	/*
430 	 * Fetch the AHDI partition descriptors.
431 	 */
432 	apt.at_cdl    = cdl;
433 	apt.at_nroots = apt.at_nparts = 0;
434 	i = ahdi_getparts(dev, strat, dl->d_secpercyl,
435 			  AHDI_BBLOCK, AHDI_BBLOCK, &apt);
436 	if (i) {
437 		if (i < dl->d_secperunit)
438 			return(-1);	/* disk read error		*/
439 		else return(1);		/* reading past end of medium	*/
440 	}
441 
442 	/*
443 	 * Perform sanity checks.
444 	 */
445 	if (apt.at_bslst == 0 || apt.at_bslend == 0) {
446 		/*
447 		 * Illegal according to Atari, however some hd-utils
448 		 * use it - notably ICD *sigh*
449 		 * Work around it.....
450 		 */
451 		apt.at_bslst = apt.at_bslend = 0;
452 		uprintf("Warning: Illegal 'bad sector list' format"
453 			"- assuming non exists\n");
454 	}
455 	if (apt.at_hdsize == 0 || apt.at_nparts == 0)	/* unlikely */
456 		return(1);
457 	if (apt.at_nparts > AHDI_MAXPARTS)		/* XXX kludge */
458 		return(-1);
459 	for (i = 0; i < apt.at_nparts; ++i) {
460 		struct ahdi_part *p1 = &apt.at_parts[i];
461 
462 		for (j = 0; j < apt.at_nroots; ++j) {
463 			u_int	aux = apt.at_roots[j];
464 			if (aux >= p1->ap_st && aux <= p1->ap_end)
465 				return(1);
466 		}
467 		for (j = i + 1; j < apt.at_nparts; ++j) {
468 			struct ahdi_part *p2 = &apt.at_parts[j];
469 			if (p1->ap_st >= p2->ap_st && p1->ap_st <= p2->ap_end)
470 				return(1);
471 			if (p2->ap_st >= p1->ap_st && p2->ap_st <= p1->ap_end)
472 				return(1);
473 		}
474 		if (p1->ap_st >= apt.at_bslst && p1->ap_st <= apt.at_bslend)
475 			return(1);
476 		if (apt.at_bslst >= p1->ap_st && apt.at_bslst <= p1->ap_end)
477 			return(1);
478 	}
479 
480 	/*
481 	 * Search for a NetBSD disk label
482 	 */
483 	apt.at_bblock = NO_BOOT_BLOCK;
484 	for (i = 0; i < apt.at_nparts; ++i) {
485 		struct ahdi_part *pd = &apt.at_parts[i];
486 		u_int		 id  = *((u_int32_t *)&pd->ap_flg);
487 		if (id == AHDI_PID_NBD || id == AHDI_PID_RAW) {
488 			u_int	blkno = pd->ap_st;
489 			j = bsd_label(dev, strat, dl, blkno, &apt.at_label);
490 			if (j < 0) {
491 				return(j);		/* I/O error */
492 			}
493 			if (!j) {
494 				apt.at_bblock = blkno;	/* got it */
495 				ck_label(dl, cdl);
496 				return(0);
497 			}
498 			/*
499 			 * Not yet, but if this is the first NBD partition
500 			 * on this volume, we'll mark it anyway as a possible
501 			 * destination for future writedisklabel() calls, just
502 			 * in case there is no valid disk label on any of the
503 			 * other AHDI partitions.
504 			 */
505 			if (id == AHDI_PID_NBD
506 			    && apt.at_bblock == NO_BOOT_BLOCK)
507 				apt.at_bblock = blkno;
508 		}
509 	}
510 
511 	/*
512 	 * No NetBSD disk label on this volume, use the AHDI
513 	 * label to create a fake BSD label. If there is no
514 	 * NBD partition on this volume either, subsequent
515 	 * writedisklabel() calls will fail.
516 	 */
517 	ahdi_to_bsd(dl, &apt);
518 	return(0);
519 }
520 
521 /*
522  * Map the AHDI partition table to the NetBSD table.
523  *
524  * This means:
525  *  Part 0   : Root
526  *  Part 1   : Swap
527  *  Part 2   : Whole disk
528  *  Part 3.. : User partitions
529  *
530  * When more than one root partition is found, only the first one will
531  * be recognized as such. The others are mapped as user partitions.
532  */
533 static void
534 ahdi_to_bsd(dl, apt)
535 	struct disklabel	*dl;
536 	struct ahdi_ptbl	*apt;
537 {
538 	int		i, have_root, user_part;
539 
540 	user_part = RAW_PART;
541 	have_root = (apt->at_bblock != NO_BOOT_BLOCK);
542 
543 	for (i = 0; i < apt->at_nparts; ++i) {
544 		struct ahdi_part *pd = &apt->at_parts[i];
545 		int		 fst, pno = -1;
546 
547 		switch (*((u_int32_t *)&pd->ap_flg)) {
548 			case AHDI_PID_NBD:
549 				/*
550 				 * If this partition has been marked as the
551 				 * first NBD partition, it will be the root
552 				 * partition.
553 				 */
554 				if (pd->ap_st == apt->at_bblock)
555 					pno = 0;
556 				/* FALL THROUGH */
557 			case AHDI_PID_NBR:
558 				/*
559 				 * If there is no NBD partition and this is
560 				 * the first NBR partition, it will be the
561 				 * root partition.
562 				 */
563 				if (!have_root) {
564 					have_root = 1;
565 					pno = 0;
566 				}
567 				/* FALL THROUGH */
568 			case AHDI_PID_NBU:
569 				fst = FS_BSDFFS;
570 				break;
571 			case AHDI_PID_NBS:
572 			case AHDI_PID_SWP:
573 				if (dl->d_partitions[1].p_size == 0)
574 					pno = 1;
575 				fst = FS_SWAP;
576 				break;
577 			case AHDI_PID_BGM:
578 			case AHDI_PID_GEM:
579 				fst = FS_MSDOS;
580 				break;
581 			default:
582 				fst = FS_OTHER;
583 				break;
584 		}
585 		if (pno < 0) {
586 			if((pno = user_part + 1) >= MAXPARTITIONS)
587 				continue;
588 			user_part = pno;
589 		}
590 		dl->d_partitions[pno].p_size   = pd->ap_end - pd->ap_st + 1;
591 		dl->d_partitions[pno].p_offset = pd->ap_st;
592 		dl->d_partitions[pno].p_fstype = fst;
593 	}
594 	dl->d_npartitions = user_part + 1;
595 }
596 
597 /*
598  * Fetch the AHDI partitions and auxilary roots.
599  *
600  * Returns:  0 if successful,
601  *           otherwise an I/O error occurred, and the
602  *           number of the offending block is returned.
603  */
604 static u_int
605 ahdi_getparts(dev, strat, secpercyl, rsec, esec, apt)
606 	dev_t			dev;
607 	void			(*strat)(struct buf *);
608 	u_int			secpercyl,
609 				rsec, esec;
610 	struct ahdi_ptbl	*apt;
611 {
612 	struct ahdi_part	*part, *end;
613 	struct ahdi_root	*root;
614 	struct buf		*bp;
615 	u_int			rv;
616 
617 	bp = geteblk(AHDI_BSIZE);
618 	bp->b_dev      = MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART);
619 	bp->b_flags    = B_BUSY | B_READ;
620 	bp->b_bcount   = AHDI_BSIZE;
621 	bp->b_blkno    = rsec;
622 	bp->b_cylinder = rsec / secpercyl;
623 	(*strat)(bp);
624 	if (biowait(bp)) {
625 		rv = rsec + (rsec == 0);
626 		goto done;
627 	}
628 	root = (struct ahdi_root *)bp->b_data;
629 
630 	if (rsec == AHDI_BBLOCK)
631 		end = &root->ar_parts[AHDI_MAXRPD];
632 	else end = &root->ar_parts[AHDI_MAXARPD];
633 	for (part = root->ar_parts; part < end; ++part) {
634 		u_int	id = *((u_int32_t *)&part->ap_flg);
635 		if (!(id & 0x01000000))
636 			continue;
637 		if ((id &= 0x00ffffff) == AHDI_PID_XGM) {
638 			u_int	offs = part->ap_st + esec;
639 			if (apt->at_nroots < AHDI_MAXROOTS)
640 				apt->at_roots[apt->at_nroots] = offs;
641 			apt->at_nroots += 1;
642 			rv = ahdi_getparts(dev, strat, secpercyl, offs,
643 				(esec == AHDI_BBLOCK) ? offs : esec, apt);
644 			if (rv)
645 				goto done;
646 			continue;
647 		}
648 		else if (apt->at_nparts < AHDI_MAXPARTS) {
649 			struct ahdi_part *p = &apt->at_parts[apt->at_nparts];
650 			*((u_int32_t *)&p->ap_flg) = id;
651 			p->ap_st  = part->ap_st + rsec;
652 			p->ap_end = p->ap_st + part->ap_size - 1;
653 		}
654 		apt->at_nparts += 1;
655 	}
656 	apt->at_hdsize = root->ar_hdsize;
657 	apt->at_bslst  = root->ar_bslst;
658 	apt->at_bslend = root->ar_bslst + root->ar_bslsize - 1;
659 	rv = 0;
660 done:
661 	bp->b_flags = B_INVAL | B_AGE | B_READ;
662 	brelse(bp);
663 	return(rv);
664 }
665 #endif /* DISKLABEL_AHDI */
666