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