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