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