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