xref: /netbsd-src/sys/arch/atari/atari/disksubr.c (revision 9573504567626934c7ee01c7dce0c4bb1dfe7403)
1 /*	$NetBSD: disksubr.c,v 1.5 1995/11/30 00:57:35 jtc 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 #include <sys/param.h>
34 #include <sys/buf.h>
35 #include <sys/disklabel.h>
36 #include <machine/tospart.h>
37 
38 /*
39  * This is ugly, but as long as disklabel(8) uses
40  * BBSIZE from ufs/ffs/fs.h, there's no alternative.
41  */
42 #include <ufs/ffs/fs.h>
43 #if BBSIZE < 8192
44 #error BBSIZE in /sys/ufs/ffs/fs.h must be at least 8192 bytes
45 #endif
46 
47 #if 0
48 #define MACHDSBR_DEBUG(x)	printf x
49 #else
50 #define MACHDSBR_DEBUG(x)
51 #endif
52 
53 static int  real_label __P((dev_t, void (*)(), u_int32_t, struct disklabel *));
54 static void chck_label __P((struct disklabel *, struct cpu_disklabel *));
55 static void fake_label __P((struct disklabel *, struct tos_table *));
56 static int  rd_rootparts __P((dev_t, void (*)(), u_int32_t, u_int32_t,
57                                                         struct tos_table *));
58 static int  rd_extparts  __P((dev_t, void (*)(), u_int32_t, u_int32_t,
59                                              u_int32_t, struct tos_table *));
60 static int  add_tospart  __P((struct tos_part *, struct tos_table *));
61 
62 /*
63  * XXX unknown function but needed for /sys/scsi to link
64  */
65 int
66 dk_establish()
67 {
68 	return(-1);
69 }
70 
71 /*
72  * Determine the size of the transfer, and make sure it is
73  * within the boundaries of the partition. Adjust transfer
74  * if needed, and signal errors or early completion.
75  */
76 int
77 bounds_check_with_label(bp, lp, wlabel)
78 struct buf		*bp;
79 struct disklabel	*lp;
80 int			wlabel;
81 {
82 	struct partition	*pp;
83 	u_int32_t		maxsz, sz;
84 
85 	pp = &lp->d_partitions[DISKPART(bp->b_dev)];
86 	if (bp->b_flags & B_RAW) {
87 		if (bp->b_bcount & (lp->d_secsize - 1)) {
88 			bp->b_error = EINVAL;
89 			bp->b_flags |= B_ERROR;
90 			return (-1);
91 		}
92 		maxsz = pp->p_size * (lp->d_secsize / DEV_BSIZE);
93 		sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;
94 	} else {
95 		maxsz = pp->p_size;
96 		sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize;
97 	}
98 
99 	if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) {
100 		if (bp->b_blkno == maxsz) {
101 			/*
102 			 * trying to get one block beyond return EOF.
103 			 */
104 			bp->b_resid = bp->b_bcount;
105 			return(0);
106 		}
107 		sz = maxsz - bp->b_blkno;
108 		if (sz <= 0 || bp->b_blkno < 0) {
109 			bp->b_error = EINVAL;
110 			bp->b_flags |= B_ERROR;
111 			return(-1);
112 		}
113 		/*
114 		 * adjust count down
115 		 */
116 		if (bp->b_flags & B_RAW)
117 			bp->b_bcount = sz << DEV_BSHIFT;
118 		else bp->b_bcount = sz * lp->d_secsize;
119 	}
120 
121 	/*
122 	 * calc cylinder for disksort to order transfers with
123 	 */
124 	bp->b_cylinder = (bp->b_blkno + pp->p_offset) / lp->d_secpercyl;
125 	return(1);
126 }
127 
128 /*
129  * Attempt to read a disk label from a device using the
130  * indicated strategy routine. The label must be partly
131  * set up before this:
132  * secpercyl and anything required in the strategy routine
133  * (e.g. sector size) must be filled in before calling us.
134  * Returns NULL on success and an error string on failure.
135  */
136 char *
137 readdisklabel(dev, strat, lp, clp)
138 dev_t			dev;
139 void			(*strat)();
140 struct disklabel	*lp;
141 struct cpu_disklabel	*clp;
142 {
143 	struct tos_table	tt;
144 	int			i;
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 	for (i = 0; i < MAXPARTITIONS; ++i) {
158 		lp->d_partitions[i].p_size   = 0;
159 		lp->d_partitions[i].p_offset = 0;
160 		lp->d_partitions[i].p_fstype = FS_UNUSED;
161 	}
162 	lp->d_partitions[RAW_PART].p_size = lp->d_secperunit;
163 	lp->d_npartitions                 = RAW_PART + 1;
164 	lp->d_bbsize                      = BBSIZE;
165 	lp->d_sbsize                      = SBSIZE;
166 
167 	MACHDSBR_DEBUG(("unit: %lu secsize: %lu secperunit: %lu\n",
168 	(u_long)DISKUNIT(dev), (u_long)lp->d_secsize,
169 	(u_long)lp->d_secperunit));
170 
171 	/*
172 	 * Try the simple case (boot block at sector 0) first.
173 	 */
174 	if(real_label(dev, strat, LABELSECTOR, lp)) {
175 		MACHDSBR_DEBUG(("Normal volume: boot block at sector 0\n"));
176 		return(NULL);
177 	}
178 	/*
179 	 * The vendor specific (TOS) partition layout requires a 512
180 	 * byte sector size.
181 	 */
182 	tt.tt_cdl    = clp;
183 	tt.tt_nroots = tt.tt_nparts = 0;
184 	if (lp->d_secsize != TOS_BSIZE || (i = rd_rootparts(dev, strat,
185 			lp->d_secpercyl, lp->d_secperunit, &tt)) == 2) {
186 		MACHDSBR_DEBUG(("Uninitialised volume\n"));
187 		lp->d_partitions[RAW_PART+1].p_size
188 				= lp->d_partitions[RAW_PART].p_size;
189 		lp->d_partitions[RAW_PART+1].p_offset
190 				= lp->d_partitions[RAW_PART].p_offset;
191 		lp->d_partitions[RAW_PART+1].p_fstype = FS_BSDFFS;
192 		lp->d_npartitions = RAW_PART + 2;
193 		goto done;
194 	}
195 	if (!i)
196 		return("Invalid TOS partition table");
197 	/*
198 	 * TOS format, search for a partition with id NBD or RAW, which
199 	 * contains a NetBSD boot block with a valid disk label in it.
200 	 */
201 	MACHDSBR_DEBUG(("AHDI partition table: "));
202 	clp->cd_bblock = NO_BOOT_BLOCK;
203 	for (i = 0; i < tt.tt_nparts; ++i) {
204 		struct tos_part	*tp = &tt.tt_parts[i];
205 		u_int32_t	id = *((u_int32_t *)&tp->tp_flg);
206 		if (id != PID_NBD && id != PID_RAW)
207 			continue;
208 		if (!real_label(dev, strat, tp->tp_st, lp)) {
209 			/*
210 			 * No disk label, but if this is the first NBD partition
211 			 * on this volume, we'll mark it anyway as a possible
212 			 * destination for future writedisklabel() calls, just
213 			 * in case there is no valid disk label on any of the
214 			 * other AHDI partitions.
215 			 */
216 			if (id == PID_NBD
217 			  && clp->cd_bblock == NO_BOOT_BLOCK)
218 				clp->cd_bblock = tp->tp_st;
219 			continue;
220 		}
221 		/*
222 		 * Found a valid disk label, mark this TOS partition for
223 		 * writedisklabel(), and check for possibly dangerous
224 		 * overlap between TOS and NetBSD partition layout.
225 		 */
226 		MACHDSBR_DEBUG(("found real disklabel\n"));
227 		clp->cd_bblock = tp->tp_st;
228 		chck_label(lp, clp);
229 		return(NULL);
230 	}
231 	/*
232 	 * No disk label on this volume, use the TOS partition
233 	 * layout to create a fake disk label. If there is no
234 	 * NBD partition on this volume either, subsequent
235 	 * writedisklabel() calls will fail.
236 	 */
237 	MACHDSBR_DEBUG(("creating fake disklabel\n"));
238 	fake_label(lp, &tt);
239 
240 	/*
241 	 * Calulate new checksum.
242 	 */
243 done:
244 	lp->d_magic = lp->d_magic2 = DISKMAGIC;
245 	lp->d_checksum = 0;
246 	lp->d_checksum = dkcksum(lp);
247 
248 	return(NULL);
249 }
250 
251 /*
252  * Check new disk label for sensibility before setting it.
253  */
254 int
255 setdisklabel(olp, nlp, openmask, clp)
256 struct disklabel	*olp, *nlp;
257 u_long			openmask;
258 struct cpu_disklabel	*clp;
259 {
260 	/* special case to allow disklabel to be invalidated */
261 	if (nlp->d_magic == 0xffffffff) {
262 		*olp = *nlp;
263 		return(0);
264 	}
265 
266 	/* sanity clause */
267 	if (nlp->d_secpercyl == 0 || nlp->d_secsize == 0
268 	  || (nlp->d_secsize % DEV_BSIZE) != 0 || dkcksum(nlp) != 0
269 	  || nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC)
270 		return(EINVAL);
271 
272 	if (clp->cd_bblock)
273 		chck_label(nlp, clp);
274 
275 	while (openmask) {
276 		struct partition *op, *np;
277 		int i = ffs(openmask) - 1;
278 		openmask &= ~(1 << i);
279 		if (i >= nlp->d_npartitions)
280 			return(EBUSY);
281 		op = &olp->d_partitions[i];
282 		np = &nlp->d_partitions[i];
283 		if (np->p_offset != op->p_offset || np->p_size < op->p_size)
284 			return(EBUSY);
285 		/*
286 		 * Copy internally-set partition information
287 		 * if new label doesn't include it.		XXX
288 		 */
289 		if (np->p_fstype == FS_UNUSED && op->p_fstype != FS_UNUSED) {
290 			np->p_fstype = op->p_fstype;
291 			np->p_fsize  = op->p_fsize;
292 			np->p_frag   = op->p_frag;
293 			np->p_cpg    = op->p_cpg;
294 		}
295 	}
296  	nlp->d_checksum = 0;
297  	nlp->d_checksum = dkcksum(nlp);
298 	*olp = *nlp;
299 	return(0);
300 }
301 
302 /*
303  * Write disk label back to device after modification.
304  */
305 int
306 writedisklabel(dev, strat, lp, clp)
307 dev_t			dev;
308 void			(*strat)();
309 struct disklabel	*lp;
310 struct cpu_disklabel	*clp;
311 {
312 	struct buf	*bp;
313 	u_int32_t	bbo;
314 	int		rv;
315 
316 	bbo = clp->cd_bblock;
317 	if (bbo == NO_BOOT_BLOCK)
318 		return(ENXIO);
319 
320 	bp = geteblk(BBSIZE);
321 	bp->b_dev      = MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART);
322 	bp->b_flags    = B_BUSY | B_READ;
323 	bp->b_bcount   = BBSIZE;
324 	bp->b_blkno    = bbo;
325 	bp->b_cylinder = bbo / lp->d_secpercyl;
326 	(*strat)(bp);
327 	rv = biowait(bp);
328 	if (!rv) {
329 		struct disklabel *nlp = (struct disklabel *)
330 				((char *)bp->b_data + LABELOFFSET);
331 		*nlp = *lp;
332 		bp->b_flags    = B_BUSY | B_WRITE;
333 		bp->b_bcount   = BBSIZE;
334 		bp->b_blkno    = bbo;
335 		bp->b_cylinder = bbo / lp->d_secpercyl;
336 		(*strat)(bp);
337 		rv = biowait(bp);
338 	}
339 	bp->b_flags |= B_INVAL | B_AGE;
340 	brelse(bp);
341 	return(rv);
342 }
343 
344 /*
345  * Read bootblock at block `offset' and check
346  * if it contains a valid disklabel.
347  * Returns 0 if an error occured, 1 if successfull.
348  */
349 static int
350 real_label(dev, strat, offset, lp)
351 dev_t			dev;
352 void			(*strat)();
353 u_int32_t		offset;
354 struct disklabel	*lp;
355 {
356 	struct buf		*bp;
357 	int			rv = 0;
358 
359 	bp = geteblk(BBSIZE);
360 	bp->b_dev      = MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART);
361 	bp->b_flags    = B_BUSY | B_READ;
362 	bp->b_bcount   = BBSIZE;
363 	bp->b_blkno    = offset;
364 	bp->b_cylinder = offset / lp->d_secpercyl;
365 	(*strat)(bp);
366 	if (!biowait(bp)) {
367 		struct disklabel *nlp = (struct disklabel *)
368 				((char *)bp->b_data + LABELOFFSET);
369 		if (nlp->d_magic == DISKMAGIC && nlp->d_magic2 == DISKMAGIC
370 	  	  && dkcksum(nlp) == 0 && nlp->d_npartitions <= MAXPARTITIONS) {
371 			*lp = *nlp;
372 			rv  = 1;
373 		}
374 	}
375 	bp->b_flags = B_INVAL | B_AGE | B_READ;
376 	brelse(bp);
377 	return(rv);
378 }
379 
380 /*
381  * Check for consistency between the NetBSD partition table
382  * and the TOS auxilary root sectors. There's no good reason
383  * to force such consistency, but issueing a warning may help
384  * an inexperienced sysadmin to prevent corruption of TOS
385  * partitions.
386  */
387 static void
388 chck_label(lp, clp)
389 struct disklabel	*lp;
390 struct cpu_disklabel	*clp;
391 {
392 	u_int32_t	*rp;
393 	int		i;
394 
395 	for (i = 0; i < lp->d_npartitions; ++i) {
396 		struct partition *p = &lp->d_partitions[i];
397 		if (p->p_size == 0 || i == RAW_PART)
398 			continue;
399 		if ( (p->p_offset <= clp->cd_bslst
400 		   && p->p_offset + p->p_size > clp->cd_bslst)
401 		  || (p->p_offset > clp->cd_bslst
402 		   && clp->cd_bslst + clp->cd_bslsize > p->p_offset)) {
403 			uprintf("Warning: NetBSD partition %c includes"
404 				" AHDI bad sector list\n", 'a'+i);
405 		}
406 		for (rp = &clp->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  * Map the partition table from TOS to the NetBSD table.
418  *
419  * This means:
420  *  Part 0   : Root
421  *  Part 1   : Swap
422  *  Part 2   : Whole disk
423  *  Part 3.. : User partitions
424  *
425  * When more than one root partition is found, only the first one will
426  * be recognized as such. The others are mapped as user partitions.
427  */
428 static void
429 fake_label(lp, tt)
430 struct disklabel	*lp;
431 struct tos_table	*tt;
432 {
433 	int		i, have_root, user_part;
434 
435 	user_part = RAW_PART;
436 	have_root = (tt->tt_bblock != NO_BOOT_BLOCK);
437 
438 	for (i = 0; i < tt->tt_nparts; ++i) {
439 		struct tos_part	*tp = &tt->tt_parts[i];
440 		int		fst, pno = -1;
441 
442 		switch (*((u_int32_t *)&tp->tp_flg)) {
443 			case PID_NBD:
444 				/*
445 				 * If this partition has been marked as the
446 				 * first NBD partition, it will be the root
447 				 * partition.
448 				 */
449 				if (tp->tp_st == tt->tt_bblock)
450 					pno = 0;
451 				/* FALL THROUGH */
452 			case PID_NBR:
453 				/*
454 				 * If there is no NBD partition and this is
455 				 * the first NBR partition, it will be the
456 				 * root partition.
457 				 */
458 				if (!have_root) {
459 					have_root = 1;
460 					pno = 0;
461 				}
462 				/* FALL THROUGH */
463 			case PID_NBU:
464 				fst = FS_BSDFFS;
465 				break;
466 			case PID_NBS:
467 			case PID_SWP:
468 				if (lp->d_partitions[1].p_size == 0)
469 					pno = 1;
470 				fst = FS_SWAP;
471 				break;
472 			case PID_BGM:
473 			case PID_GEM:
474 				fst = FS_MSDOS;
475 				break;
476 			default:
477 				fst = FS_OTHER;
478 				break;
479 		}
480 		if (pno < 0) {
481 			if((pno = user_part + 1) >= MAXPARTITIONS)
482 				continue;
483 			user_part = pno;
484 		}
485 		lp->d_partitions[pno].p_size   = tp->tp_size;
486 		lp->d_partitions[pno].p_offset = tp->tp_st;
487 		lp->d_partitions[pno].p_fstype = fst;
488 	}
489 	lp->d_npartitions = user_part + 1;
490 }
491 
492 /*
493  * Create a list of TOS partitions in tos_table `tt'.
494  * Returns 0 if an error occured, 1 if successfull,
495  * or 2 if no TOS partition table exists.
496  */
497 static int
498 rd_rootparts(dev, strat, spc, spu, tt)
499 dev_t			dev;
500 void			(*strat)();
501 u_int32_t		spc, spu;
502 struct tos_table	*tt;
503 {
504 	struct tos_root	*root;
505 	struct buf	*bp;
506 	int		i, j, rv = 0;
507 
508 	bp = geteblk(TOS_BSIZE);
509 	bp->b_dev      = MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART);
510 	bp->b_flags    = B_BUSY | B_READ;
511 	bp->b_bcount   = TOS_BSIZE;
512 	bp->b_blkno    = TOS_BBLOCK;
513 	bp->b_cylinder = TOS_BBLOCK / spc;
514 	(*strat)(bp);
515 	if (biowait(bp))
516 		goto done;
517 	root = (struct tos_root *)bp->b_data;
518 
519 	MACHDSBR_DEBUG(("hdsize: %lu bsl-start: %lu bsl-size: %lu\n",
520 	(u_long)root->tr_hdsize, (u_long)root->tr_bslst,
521 	(u_long)root->tr_bslsize));
522 
523 	if (!root->tr_hdsize || (!root->tr_bslsize && root->tr_bslst)) {
524 		rv = 2; goto done;
525 	}
526 	for (i = 0; i < NTOS_PARTS; ++i) {
527 		struct tos_part	*part = &root->tr_parts[i];
528 		if (!(part->tp_flg & 1)) /* skip invalid entries */
529 			continue;
530 		MACHDSBR_DEBUG(("  %c%c%c %9lu %9lu\n",
531 		  part->tp_id[0], part->tp_id[1], part->tp_id[2],
532 		    (u_long)part->tp_st, (u_long)part->tp_size));
533 		if (part->tp_st == 0 || part->tp_st >= spu
534 		  || part->tp_size == 0 || part->tp_size >= spu
535 		  || part->tp_st + part->tp_size > spu)
536 			goto done;
537 		if ( (part->tp_st <= root->tr_bslst
538 		   && part->tp_st + part->tp_size > root->tr_bslst)
539 		  || (part->tp_st >  root->tr_bslst
540 		   && root->tr_bslst + root->tr_bslsize > part->tp_st))
541 			goto done;
542 		if (add_tospart(part, tt) && !rd_extparts(dev, strat,
543 					spc, part->tp_st, part->tp_size, tt))
544 			goto done;
545 	}
546 	if (tt->tt_nparts > MAX_TOS_PARTS)
547 		goto done;	/* too many partitions for us */
548 	/*
549 	 * Allthough the AHDI 3.0 specifications do not prohibit
550 	 * a root sector with only invalid partition entries in
551 	 * it, this situation would be most unlikely.
552 	 */
553 	if (!tt->tt_nparts) {
554 		rv = 2; goto done;
555 	}
556 	for (i = 0; i < tt->tt_nparts; ++i) {
557 		struct tos_part	*p1 = &tt->tt_parts[i];
558 		for (j = 0; j < i; ++j) {
559 			struct tos_part	*p2 = &tt->tt_parts[j];
560 			if ( (p1->tp_st <= p2->tp_st
561 			   && p1->tp_st + p1->tp_size > p2->tp_st)
562 			  || (p1->tp_st >  p2->tp_st
563 			   && p2->tp_st + p2->tp_size > p1->tp_st))
564 				goto done;
565 		}
566 	}
567 	tt->tt_bslsize = root->tr_bslsize;
568 	tt->tt_bslst   = root->tr_bslst;
569 	rv = 1;
570 done:
571 	bp->b_flags = B_INVAL | B_AGE | B_READ;
572 	brelse(bp);
573 	return(rv);
574 }
575 
576 /*
577  * Add all subpartitions within an extended
578  * partition to tos_table `tt'.
579  * Returns 0 if an error occured, 1 if successfull.
580  */
581 static int
582 rd_extparts(dev, strat, spc, extst, extsize, tt)
583 dev_t			dev;
584 void			(*strat)();
585 u_int32_t		spc, extst, extsize;
586 struct tos_table	*tt;
587 {
588 	struct buf	*bp;
589 	u_int32_t	subst = extst, subsize = extsize;
590 	int		rv = 0;
591 
592 	bp = geteblk(TOS_BSIZE);
593 	bp->b_dev = MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART);
594 
595 	for (;;) {
596 		struct tos_root	*root = (struct tos_root *)bp->b_data;
597 		struct tos_part	*part = root->tr_parts;
598 
599 		MACHDSBR_DEBUG(("auxilary root at sector %lu\n",(u_long)subst));
600 		bp->b_flags    = B_BUSY | B_READ;
601 		bp->b_bcount   = TOS_BSIZE;
602 		bp->b_blkno    = subst;
603 		bp->b_cylinder = subst / spc;
604 		(*strat)(bp);
605 		if (biowait(bp))
606 			goto done;
607 		/*
608 		 * The first entry in an auxilary root sector must be
609 		 * marked as valid. The entry must describe a normal
610 		 * partition. The partition must not extend beyond
611 		 * the boundaries of the subpartition that it's
612 		 * part of.
613 		 */
614 		MACHDSBR_DEBUG(("  %c%c%c %9lu %9lu\n",
615 		  part->tp_id[0], part->tp_id[1], part->tp_id[2],
616 		    (u_long)part->tp_st, (u_long)part->tp_size));
617 		if (!(part->tp_flg & 1)
618 #if 0 /* LWP: Temporary hack */
619 		  || part->tp_st == 0 || part->tp_st >= subsize
620 		  || part->tp_size == 0 || part->tp_size >= subsize
621 		  || part->tp_st + part->tp_size > subsize) {
622 #else
623 		  || part->tp_st == 0
624 		  || part->tp_size == 0
625 		  || part->tp_size >= extsize) {
626 #endif
627 			MACHDSBR_DEBUG(("first entry exceeds parent\n"));
628 			goto done;
629 		}
630 		part->tp_st += subst;
631 		if (add_tospart(part++, tt)) {
632 			MACHDSBR_DEBUG(("first entry is XGM\n"));
633 			goto done;
634 		}
635 		/*
636 		 * If the second entry in an auxilary rootsector is
637 		 * marked as invalid, we've reached the end of the
638 		 * linked list of subpartitions.
639 		 */
640 		if (!(part->tp_flg & 1)) {
641 			rv = 1;
642 			goto done;
643 		}
644 		/*
645 		 * If marked valid, the second entry in an auxilary
646 		 * rootsector must describe a subpartition (id XGM).
647 		 * The subpartition must not extend beyond the
648 		 * boundaries of the extended partition that
649 		 * it's part of.
650 		 */
651 		MACHDSBR_DEBUG(("  %c%c%c %9lu %9lu\n",
652 		  part->tp_id[0], part->tp_id[1], part->tp_id[2],
653 		    (u_long)part->tp_st, (u_long)part->tp_size));
654 #if 0 /* LWP: Temporary hack */
655 		if (part->tp_st == 0 || part->tp_st >= extsize
656 		  || part->tp_size == 0 || part->tp_size >= extsize
657 		  || part->tp_st + part->tp_size > extsize) {
658 #else
659 		if (part->tp_st == 0
660 		  || part->tp_st >= extsize
661 		  || part->tp_size == 0) {
662 #endif
663 			MACHDSBR_DEBUG(("second entry exceeds parent\n"));
664 			goto done;
665 		}
666 		part->tp_st += extst;
667 		if (!add_tospart(part, tt)) {
668 			MACHDSBR_DEBUG(("second entry is not XGM\n"));
669 			goto done;
670 		}
671 		subst   = part->tp_st;
672 		subsize = part->tp_size;
673 	}
674 done:
675 	bp->b_flags = B_INVAL | B_AGE | B_READ;
676 	brelse(bp);
677 	return(rv);
678 }
679 
680 /*
681  * Add a TOS partition or an auxilary root sector
682  * to the appropriate list in tos_table `tt'.
683  * Returns 1 if `tp' is an XGM partition, otherwise 0.
684  */
685 static int
686 add_tospart (tp, tt)
687 struct tos_part		*tp;
688 struct tos_table	*tt;
689 {
690 	u_int32_t	i;
691 
692 	tp->tp_flg = 0;
693 	i = *((u_int32_t *)&tp->tp_flg);
694 	if (i == PID_XGM) {
695 		i = tt->tt_nroots++;
696 		if (i < MAX_TOS_ROOTS)
697 			tt->tt_roots[i] = tp->tp_st;
698 		return 1;
699 	}
700 	i = tt->tt_nparts++;
701 	if (i < MAX_TOS_PARTS)
702 		tt->tt_parts[i] = *tp;
703 	return 0;
704 }
705