Home | History | Annotate | Line # | Download | only in ofppc
      1 /*	$NetBSD: disksubr.c,v 1.31 2022/07/05 19:31:04 andvar Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2010 Frank Wille.
      5  * All rights reserved.
      6  *
      7  * Written by Frank Wille for The NetBSD Project.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     20  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     21  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     22  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     28  * POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 /*
     32  * Copyright (c) 1994 Christian E. Hopps
     33  *
     34  * Redistribution and use in source and binary forms, with or without
     35  * modification, are permitted provided that the following conditions
     36  * are met:
     37  * 1. Redistributions of source code must retain the above copyright
     38  *    notice, this list of conditions and the following disclaimer.
     39  * 2. Redistributions in binary form must reproduce the above copyright
     40  *    notice, this list of conditions and the following disclaimer in the
     41  *    documentation and/or other materials provided with the distribution.
     42  * 3. All advertising materials mentioning features or use of this software
     43  *    must display the following acknowledgement:
     44  *	This product includes software developed by the University of
     45  *	California, Berkeley and its contributors.
     46  * 4. Neither the name of the University nor the names of its contributors
     47  *    may be used to endorse or promote products derived from this software
     48  *    without specific prior written permission.
     49  *
     50  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     51  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     52  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     53  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     54  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     55  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     56  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     57  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     58  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     59  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     60  * SUCH DAMAGE.
     61  *
     62  *	@(#)ufs_disksubr.c	7.16 (Berkeley) 5/4/91
     63  */
     64 
     65 #include <sys/cdefs.h>
     66 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.31 2022/07/05 19:31:04 andvar Exp $");
     67 
     68 #include "opt_disksubr.h"
     69 
     70 #include <sys/buf.h>
     71 #include <sys/disklabel.h>
     72 #include <sys/bswap.h>
     73 
     74 /*
     75  * In /usr/src/sys/dev/scsipi/sd.c, routine sdstart() adjusts the
     76  * block numbers, it changes from DEV_BSIZE units to physical units:
     77  * blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE);
     78  * As long as media with sector sizes of 512 bytes are used, this
     79  * doesn't matter (divide by 1), but for successful usage of media with
     80  * greater sector sizes (e.g. 640MB MO-media with 2048 bytes/sector)
     81  * we must multiply block numbers with (lp->d_secsize / DEV_BSIZE)
     82  * to keep "unchanged" physical block numbers.
     83  */
     84 #define SD_C_ADJUSTS_NR
     85 
     86 #define baddr(bp) (void *)((bp)->b_data)
     87 
     88 static const char *read_dos_label(dev_t, void (*)(struct buf *),
     89     struct disklabel *, struct cpu_disklabel *);
     90 static int getFreeLabelEntry(struct disklabel *);
     91 static int read_netbsd_label(dev_t, void (*)(struct buf *), struct disklabel *,
     92     struct cpu_disklabel *);
     93 #ifdef RDB_PART
     94 static const char *read_rdb_label(dev_t, void (*)(struct buf *),
     95     struct disklabel *, struct cpu_disklabel *);
     96 static u_long rdbchksum(void *);
     97 static struct adostype getadostype(u_long);
     98 #endif
     99 
    100 /*
    101  * Read MBR partition table.
    102  *
    103  * XXX -
    104  * Since FFS is endian sensitive, we pay no effort in attempting to
    105  * dig up *BSD/i386 disk labels that may be present on the disk.
    106  * Hence anything but DOS partitions is treated as unknown FS type, but
    107  * this should suffice to mount_msdos Zip and other removable media.
    108  */
    109 static const char *
    110 read_dos_label(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
    111     struct cpu_disklabel *osdep)
    112 {
    113 	struct buf *bp;
    114 	struct mbr_partition *bsdp, *dp;
    115 	const char *msg = NULL;
    116 	int i, slot, maxslot = 0;
    117 	u_int32_t bsdpartoff;
    118 
    119 	/* get a buffer and initialize it */
    120 	bp = geteblk((int)lp->d_secsize);
    121 	bp->b_dev = dev;
    122 
    123 	/* read master boot record */
    124 	bp->b_blkno = MBR_BBSECTOR;
    125 	bp->b_bcount = lp->d_secsize;
    126 	bp->b_flags |= B_READ;
    127 	bp->b_cylinder = MBR_BBSECTOR / lp->d_secpercyl;
    128 	(*strat)(bp);
    129 
    130 	bsdpartoff = 0;
    131 
    132 	/* if successful, wander through dos partition table */
    133 	if (biowait(bp)) {
    134 		msg = "dos partition I/O error";
    135 		goto done;
    136 	}
    137 	/* XXX */
    138 	dp = (struct mbr_partition *)((char *)bp->b_data + MBR_PART_OFFSET);
    139 	bsdp = NULL;
    140 	for (i = 0; i < MBR_PART_COUNT; i++, dp++) {
    141 		switch (dp->mbrp_type) {
    142 		case MBR_PTYPE_NETBSD:
    143 			bsdp = dp;
    144 			break;
    145 		case MBR_PTYPE_OPENBSD:
    146 		case MBR_PTYPE_386BSD:
    147 			if (!bsdp)
    148 				bsdp = dp;
    149 			break;
    150 		}
    151 	}
    152 	if (!bsdp) {
    153 		/* generate fake disklabel */
    154 		dp = (struct mbr_partition *)((char *)bp->b_data +
    155 		    MBR_PART_OFFSET);
    156 		for (i = 0; i < MBR_PART_COUNT; i++, dp++) {
    157 			if (!dp->mbrp_type)
    158 				continue;
    159 			slot = getFreeLabelEntry(lp);
    160 			if (slot < 0)
    161 				break;
    162 			if (slot > maxslot)
    163 				maxslot = slot;
    164 
    165 			lp->d_partitions[slot].p_offset =
    166 			    bswap32(dp->mbrp_start);
    167 			lp->d_partitions[slot].p_size = bswap32(dp->mbrp_size);
    168 
    169 			switch (dp->mbrp_type) {
    170 			case MBR_PTYPE_FAT12:
    171 			case MBR_PTYPE_FAT16S:
    172 			case MBR_PTYPE_FAT16B:
    173 			case MBR_PTYPE_FAT32:
    174 			case MBR_PTYPE_FAT32L:
    175 			case MBR_PTYPE_FAT16L:
    176 				lp->d_partitions[slot].p_fstype = FS_MSDOS;
    177 				break;
    178 			default:
    179 				lp->d_partitions[slot].p_fstype = FS_OTHER;
    180 				break;
    181 			}
    182 		}
    183 		msg = "no NetBSD disk label";
    184 	} else {
    185 		/* NetBSD partition on MBR */
    186 		bsdpartoff = bswap32(bsdp->mbrp_start);
    187 
    188 		lp->d_partitions[2].p_size = bswap32(bsdp->mbrp_size);
    189 		lp->d_partitions[2].p_offset = bswap32(bsdp->mbrp_start);
    190 		if (2 > maxslot)
    191 			maxslot = 2;
    192 		/* read in disklabel, blkno + 1 for DOS disklabel offset */
    193 		osdep->cd_labelsector = bsdpartoff + LABELSECTOR;
    194 		osdep->cd_labeloffset = LABELOFFSET;
    195 		if (read_netbsd_label(dev, strat, lp, osdep))
    196 			goto done;
    197 		msg = "no NetBSD disk label";
    198 	}
    199 
    200 	lp->d_npartitions = ((maxslot >= RAW_PART) ? maxslot : RAW_PART) + 1;
    201 
    202 done:
    203 	brelse(bp, 0);
    204 	return msg;
    205 }
    206 
    207 /*
    208  * Find an entry in the disk label that is unused and return it
    209  * or -1 if no entry
    210  */
    211 static int
    212 getFreeLabelEntry(struct disklabel *lp)
    213 {
    214 	int i;
    215 
    216 	for (i = 0; i < MAXPARTITIONS; i++) {
    217 		if ((i != RAW_PART)
    218 		    && (lp->d_partitions[i].p_fstype == FS_UNUSED))
    219 			return i;
    220 	}
    221 	return -1;
    222 }
    223 
    224 #ifdef RDB_PART
    225 /*
    226  * Read an Amiga RDB partition table.
    227  */
    228 static const char *
    229 read_rdb_label(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
    230     struct cpu_disklabel *osdep)
    231 {
    232 	struct adostype adt;
    233 	struct buf *bp;
    234 	struct partition *pp = NULL;
    235 	struct partblock *pbp;
    236 	struct rdblock *rbp;
    237 	const char *msg;
    238 	char *bcpls, *s, bcpli;
    239 	int cindex, i, nopname;
    240 	u_long nextb;
    241 
    242 	osdep->rdblock = RDBNULL;
    243 	lp->d_npartitions = RAW_PART + 1;
    244 
    245 	if (lp->d_partitions[RAW_PART].p_size == 0)
    246 		lp->d_partitions[RAW_PART].p_size = 0x1fffffff;
    247 	lp->d_partitions[RAW_PART].p_offset = 0;
    248 	/* if no 'a' partition, default is to copy from 'c' as BSDFFS */
    249 	if (lp->d_partitions[0].p_size == 0) {
    250 		lp->d_partitions[0].p_size = lp->d_partitions[RAW_PART].p_size;
    251 		lp->d_partitions[0].p_offset = 0;
    252 		lp->d_partitions[0].p_fstype = FS_BSDFFS;
    253 		lp->d_partitions[0].p_fsize = 1024;
    254 		lp->d_partitions[0].p_frag = 8;
    255 		lp->d_partitions[0].p_cpg = 0;
    256 	}
    257 
    258 	/* obtain buffer to probe drive with */
    259 	bp = geteblk((int)lp->d_secsize);
    260 
    261 	/*
    262 	 * request no partition relocation by driver on I/O operations
    263 	 */
    264 #ifdef _KERNEL
    265 	bp->b_dev = MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART);
    266 #else
    267 	bp->b_dev = dev;
    268 #endif
    269 	msg = NULL;
    270 
    271 	/*
    272 	 * find the RDB block
    273 	 */
    274 	for (nextb = 0; nextb < RDB_MAXBLOCKS; nextb++) {
    275 		bp->b_blkno = nextb;
    276 		bp->b_cylinder = bp->b_blkno / lp->d_secpercyl;
    277 		bp->b_bcount = lp->d_secsize;
    278 		bp->b_oflags &= ~(BO_DONE);
    279 		bp->b_flags |= B_READ;
    280 #ifdef SD_C_ADJUSTS_NR
    281 		bp->b_blkno *= (lp->d_secsize / DEV_BSIZE);
    282 #endif
    283 		(*strat)(bp);
    284 
    285 		if (biowait(bp)) {
    286 			msg = "rdb scan I/O error";
    287 			goto done;
    288 		}
    289 		rbp = baddr(bp);
    290 		if (rbp->id == RDBLOCK_ID) {
    291 			if (rdbchksum(rbp) == 0)
    292 				break;
    293 			else
    294 				msg = "rdb bad checksum";
    295 		}
    296 	}
    297 
    298 	if (nextb == RDB_MAXBLOCKS) {
    299 		if (msg == NULL)
    300 			msg = "no disk label";
    301 		goto done;
    302 	} else if (msg != NULL)
    303 		/*
    304 		 * maybe we found an invalid one before a valid.
    305 		 * clear err.
    306 		 */
    307 		msg = NULL;
    308 
    309 	osdep->rdblock = nextb;
    310 
    311 	/* RDB present, clear disklabel partition table before doing PART blks */
    312 	for (i = 0; i < MAXPARTITIONS; i++) {
    313 		osdep->pbindex[i] = -1;
    314 		osdep->pblist[i] = RDBNULL;
    315 		if (i == RAW_PART)
    316 			continue;
    317 		lp->d_partitions[i].p_size = 0;
    318 		lp->d_partitions[i].p_offset = 0;
    319 	}
    320 
    321 	lp->d_secsize = rbp->nbytes;
    322 	lp->d_nsectors = rbp->nsectors;
    323 	lp->d_ntracks = rbp->nheads;
    324 	/*
    325 	 * should be rdb->ncylinders however this is a bogus value
    326 	 * sometimes it seems
    327 	 */
    328 	if (rbp->highcyl == 0)
    329 		lp->d_ncylinders = rbp->ncylinders;
    330 	else
    331 		lp->d_ncylinders = rbp->highcyl + 1;
    332 	/*
    333 	 * I also don't trust rdb->secpercyl
    334 	 */
    335 	lp->d_secpercyl = uimin(rbp->secpercyl, lp->d_nsectors * lp->d_ntracks);
    336 	if (lp->d_secpercyl == 0)
    337 		lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
    338 #ifdef DIAGNOSTIC
    339 	if (lp->d_ncylinders != rbp->ncylinders)
    340 		printf("warning found rdb->ncylinders(%u) != "
    341 		    "rdb->highcyl(%u) + 1\n", rbp->ncylinders,
    342 		    rbp->highcyl);
    343 	if (lp->d_nsectors * lp->d_ntracks != rbp->secpercyl)
    344 		printf("warning found rdb->secpercyl(%u) != "
    345 		    "rdb->nsectors(%u) * rdb->nheads(%u)\n", rbp->secpercyl,
    346 		    rbp->nsectors, rbp->nheads);
    347 #endif
    348 	lp->d_sparespercyl =
    349 	    uimax(rbp->secpercyl, lp->d_nsectors * lp->d_ntracks)
    350 	    - lp->d_secpercyl;
    351 	if (lp->d_sparespercyl == 0)
    352 		lp->d_sparespertrack = 0;
    353 	else {
    354 		lp->d_sparespertrack = lp->d_sparespercyl / lp->d_ntracks;
    355 #ifdef DIAGNOSTIC
    356 		if (lp->d_sparespercyl % lp->d_ntracks)
    357 			printf("warning lp->d_sparespercyl(%u) not multiple "
    358 			    "of lp->d_ntracks(%u)\n", lp->d_sparespercyl,
    359 			    lp->d_ntracks);
    360 #endif
    361 	}
    362 
    363 	lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
    364 	lp->d_acylinders = rbp->ncylinders - (rbp->highcyl - rbp->lowcyl + 1);
    365 	lp->d_rpm = 3600; 		/* good guess I suppose. */
    366 	lp->d_interleave = rbp->interleave;
    367 	lp->d_headswitch = lp->d_flags = lp->d_trackskew = lp->d_cylskew = 0;
    368 	lp->d_trkseek = /* rbp->steprate */ 0;
    369 
    370 	/*
    371 	 * raw partition gets the entire disk
    372 	 */
    373 	lp->d_partitions[RAW_PART].p_size = rbp->ncylinders * lp->d_secpercyl;
    374 
    375 	/*
    376 	 * scan for partition blocks
    377 	 */
    378 	nopname = 1;
    379 	cindex = 0;
    380 	for (nextb = rbp->partbhead; nextb != RDBNULL; nextb = pbp->next) {
    381 		bp->b_blkno = nextb;
    382 		bp->b_cylinder = bp->b_blkno / lp->d_secpercyl;
    383 		bp->b_bcount = lp->d_secsize;
    384 		bp->b_oflags &= ~(BO_DONE);
    385 		bp->b_flags |= B_READ;
    386 #ifdef SD_C_ADJUSTS_NR
    387 		bp->b_blkno *= (lp->d_secsize / DEV_BSIZE);
    388 #endif
    389 		strat(bp);
    390 
    391 		if (biowait(bp)) {
    392 			msg = "partition scan I/O error";
    393 			goto done;
    394 		}
    395 		pbp = baddr(bp);
    396 
    397 		if (pbp->id != PARTBLOCK_ID) {
    398 			msg = "partition block with bad id";
    399 			goto done;
    400 		}
    401 		if (rdbchksum(pbp)) {
    402 			msg = "partition block bad checksum";
    403 			goto done;
    404 		}
    405 
    406 		if (pbp->e.tabsize < 11) {
    407 			/*
    408 			 * not enough info, too funky for us.
    409 			 * I don't want to skip I want it fixed.
    410 			 */
    411 			msg = "bad partition info (environ < 11)";
    412 			goto done;
    413 		}
    414 
    415 		/*
    416 		 * XXXX should be ">" however some vendors don't know
    417 		 * what a table size is so, we hack for them.
    418 		 * the other checks can fail for all I care but this
    419 		 * is a very common value. *sigh*.
    420 		 */
    421 		if (pbp->e.tabsize >= 16)
    422 			adt = getadostype(pbp->e.dostype);
    423 		else {
    424 			adt.archtype = ADT_UNKNOWN;
    425 			adt.fstype = FS_UNUSED;
    426 		}
    427 
    428 		switch (adt.archtype) {
    429 		case ADT_NETBSDROOT:
    430 			pp = &lp->d_partitions[0];
    431 			if (pp->p_size) {
    432 #ifdef DIAGNOSTIC
    433 				printf("more than one root, ignoring\n");
    434 #endif
    435 				osdep->rdblock = RDBNULL; /* invalidate cpulab */
    436 				continue;
    437 			}
    438 			break;
    439 		case ADT_NETBSDSWAP:
    440 			pp = &lp->d_partitions[1];
    441 			if (pp->p_size) {
    442 #ifdef DIAGNOSTIC
    443 				printf("more than one swap, ignoring\n");
    444 #endif
    445 				osdep->rdblock = RDBNULL; /* invalidate cpulab */
    446 				continue;
    447 			}
    448 			break;
    449 		case ADT_NETBSDUSER:
    450 		case ADT_AMIGADOS:
    451 		case ADT_AMIX:
    452 		case ADT_EXT2:
    453 		case ADT_RAID:
    454 		case ADT_MSD:
    455 		case ADT_UNKNOWN:
    456 			pp = &lp->d_partitions[lp->d_npartitions];
    457 			break;
    458 		}
    459 		if (lp->d_npartitions <= (pp - lp->d_partitions))
    460 			lp->d_npartitions = (pp - lp->d_partitions) + 1;
    461 
    462 #ifdef DIAGNOSTIC
    463 		if (lp->d_secpercyl * lp->d_secsize !=
    464 		    (pbp->e.secpertrk * pbp->e.numheads * pbp->e.sizeblock<<2)) {
    465 			if (pbp->partname[0] < sizeof(pbp->partname))
    466 				pbp->partname[pbp->partname[0] + 1] = 0;
    467 			else
    468 				pbp->partname[sizeof(pbp->partname) - 1] = 0;
    469 			printf("Partition '%s' geometry %u/%u differs",
    470 			    pbp->partname + 1, pbp->e.numheads,
    471 			    pbp->e.secpertrk);
    472 			printf(" from RDB %u/%u=%u\n", lp->d_ntracks,
    473 			    lp->d_nsectors, lp->d_secpercyl);
    474 		}
    475 #endif
    476 		/*
    477 		 * insert sort in increasing offset order
    478 		 */
    479 		while ((pp - lp->d_partitions) > RAW_PART + 1) {
    480 			daddr_t boff;
    481 
    482 			boff = pbp->e.lowcyl * pbp->e.secpertrk
    483 			    * pbp->e.numheads;
    484 			if (boff > (pp - 1)->p_offset)
    485 				break;
    486 			*pp = *(pp - 1);	/* struct copy */
    487 			pp--;
    488 		}
    489 		i = (pp - lp->d_partitions);
    490 		if (nopname || i == 1) {
    491 			/*
    492 			 * either we have no packname yet or we found
    493 			 * the swap partition. copy BCPL string into packname
    494 			 * [the reason we use the swap partition: the user
    495 			 *  can supply a decent packname without worry
    496 			 *  of having to access an oddly named partition
    497 			 *  under AmigaDos]
    498 			 */
    499 			s = lp->d_packname;
    500 			bcpls = &pbp->partname[1];
    501 			bcpli = pbp->partname[0];
    502 			if (sizeof(lp->d_packname) <= bcpli)
    503 				bcpli = sizeof(lp->d_packname) - 1;
    504 			while (bcpli--)
    505 				*s++ = *bcpls++;
    506 			*s = 0;
    507 			nopname = 0;
    508 		}
    509 
    510 		pp->p_size = (pbp->e.highcyl - pbp->e.lowcyl + 1)
    511 		    * pbp->e.secpertrk * pbp->e.numheads
    512 		    * ((pbp->e.sizeblock << 2) / lp->d_secsize);
    513 		pp->p_offset = pbp->e.lowcyl * pbp->e.secpertrk
    514 		    * pbp->e.numheads
    515 		    * ((pbp->e.sizeblock << 2) / lp->d_secsize);
    516 		pp->p_fstype = adt.fstype;
    517 		if (adt.archtype == ADT_AMIGADOS) {
    518 			/*
    519 			 * Save reserved blocks at begin in cpg and
    520 			 *  adjust size by reserved blocks at end
    521 			 */
    522 			int bsize, secperblk, minbsize, prefac;
    523 
    524 			minbsize = uimax(512, lp->d_secsize);
    525 
    526 			bsize	  = pbp->e.sizeblock << 2;
    527 			secperblk = pbp->e.secperblk;
    528 			prefac	  = pbp->e.prefac;
    529 
    530 			while (bsize > minbsize) {
    531 				bsize >>= 1;
    532 				secperblk <<= 1;
    533 				prefac <<= 1;
    534 			}
    535 
    536 			if (bsize == minbsize) {
    537 				pp->p_fsize = bsize;
    538 				pp->p_frag = secperblk;
    539 				pp->p_cpg = pbp->e.resvblocks;
    540 				pp->p_size -= prefac;
    541 			} else {
    542 				adt.archtype = ADT_UNKNOWN;
    543 				adt.fstype = FS_UNUSED;
    544 			}
    545 		} else if (pbp->e.tabsize > 22 && ISFSARCH_NETBSD(adt)) {
    546 			pp->p_fsize = pbp->e.fsize;
    547 			pp->p_frag = pbp->e.frag;
    548 			pp->p_cpg = pbp->e.cpg;
    549 		} else {
    550 			pp->p_fsize = 1024;
    551 			pp->p_frag = 8;
    552 			pp->p_cpg = 0;
    553 		}
    554 
    555 		/*
    556 		 * store this partitions block number
    557 		 */
    558 		osdep->pblist[osdep->pbindex[i] = cindex++] = nextb;
    559 	}
    560 	/*
    561 	 * calculate new checksum.
    562 	 */
    563 	lp->d_magic = lp->d_magic2 = DISKMAGIC;
    564 	lp->d_checksum = 0;
    565 	lp->d_checksum = dkcksum(lp);
    566 	if (osdep->rdblock != RDBNULL)
    567 		osdep->valid = 1;
    568 done:
    569 	if (osdep->valid == 0)
    570 		osdep->rdblock = RDBNULL;
    571 	brelse(bp, 0);
    572 	return msg;
    573 }
    574 
    575 static u_long
    576 rdbchksum(void *bdata)
    577 {
    578 	u_long *blp, cnt, val;
    579 
    580 	blp = bdata;
    581 	cnt = blp[1];
    582 	val = 0;
    583 
    584 	while (cnt--)
    585 		val += *blp++;
    586 	return val;
    587 }
    588 
    589 static struct adostype
    590 getadostype(u_long dostype)
    591 {
    592 	struct adostype adt;
    593 	u_long b1, t3;
    594 
    595 	t3 = dostype & 0xffffff00;
    596 	b1 = dostype & 0x000000ff;
    597 
    598 	adt.fstype = b1;
    599 
    600 	switch (t3) {
    601 	case DOST_NBR:
    602 		adt.archtype = ADT_NETBSDROOT;
    603 		return adt;
    604 	case DOST_NBS:
    605 		adt.archtype = ADT_NETBSDSWAP;
    606 		return adt;
    607 	case DOST_NBU:
    608 		adt.archtype = ADT_NETBSDUSER;
    609 		return adt;
    610 	case DOST_MUFS:
    611 		/* check for 'muFS'? */
    612 		adt.archtype = ADT_AMIGADOS;
    613 		adt.fstype = FS_ADOS;
    614 		return adt;
    615 	case DOST_DOS:
    616 		adt.archtype = ADT_AMIGADOS;
    617                 if (b1 > 5)
    618 			adt.fstype = FS_UNUSED;
    619 		else
    620 			adt.fstype = FS_ADOS;
    621 		return adt;
    622 	case DOST_AMIX:
    623 		adt.archtype = ADT_AMIX;
    624 		if (b1 == 2)
    625 			adt.fstype = FS_BSDFFS;
    626 		else
    627 			adt.fstype = FS_UNUSED;
    628 		return adt;
    629 	case DOST_XXXBSD:
    630 #ifdef DIAGNOSTIC
    631 		printf("found dostype: 0x%lx which is deprecated", dostype);
    632 #endif
    633 		if (b1 == 'S') {
    634 			dostype = DOST_NBS;
    635 			dostype |= FS_SWAP;
    636 		} else {
    637 			if (b1 == 'R')
    638 				dostype = DOST_NBR;
    639 			else
    640 				dostype = DOST_NBU;
    641 			dostype |= FS_BSDFFS;
    642 		}
    643 #ifdef DIAGNOSTIC
    644 		printf(" using: 0x%lx instead\n", dostype);
    645 #endif
    646 		return(getadostype(dostype));
    647 	case DOST_EXT2:
    648 		adt.archtype = ADT_EXT2;
    649 		adt.fstype = FS_EX2FS;
    650 		return adt;
    651 	case DOST_RAID:
    652 		adt.archtype = ADT_RAID;
    653 		adt.fstype = FS_RAID;
    654 		return adt;
    655 	case DOST_MSD:
    656 		adt.archtype = ADT_MSD;
    657 		adt.fstype = FS_MSDOS;
    658 		return adt;
    659 	default:
    660 #ifdef DIAGNOSTIC
    661 		printf("warning unknown dostype: 0x%lx marking unused\n",
    662 		    dostype);
    663 #endif
    664 		adt.archtype = ADT_UNKNOWN;
    665 		adt.fstype = FS_UNUSED;
    666 		return adt;
    667 	}
    668 }
    669 #endif /* RDB_PART */
    670 
    671 /*
    672  * Get raw NetBSD disk label
    673  */
    674 static int
    675 read_netbsd_label(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
    676     struct cpu_disklabel *osdep)
    677 {
    678 	struct buf *bp;
    679 	struct disklabel *dlp;
    680 
    681 	/* get a buffer and initialize it */
    682 	bp = geteblk((int)lp->d_secsize);
    683 	bp->b_dev = dev;
    684 
    685 	/* Now get the label block */
    686 	bp->b_blkno = osdep->cd_labelsector;
    687 	bp->b_bcount = lp->d_secsize;
    688 	bp->b_flags |= B_READ;
    689 	bp->b_cylinder = bp->b_blkno / (lp->d_secsize / DEV_BSIZE) / lp->d_secpercyl;
    690 	(*strat)(bp);
    691 
    692 	if (biowait(bp))
    693 		goto done;
    694 
    695 	for (dlp = (struct disklabel *)((char *)bp->b_data +
    696 		 osdep->cd_labeloffset);
    697 	     dlp <= (struct disklabel *)((char *)bp->b_data + lp->d_secsize -
    698 	         sizeof (*dlp));
    699 	     dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
    700 		if (dlp->d_magic == DISKMAGIC
    701 		    && dlp->d_magic2 == DISKMAGIC
    702 		    && dlp->d_npartitions <= MAXPARTITIONS
    703 		    && dkcksum(dlp) == 0) {
    704 			*lp = *dlp;
    705 			osdep->cd_labeloffset = (char *)dlp -
    706 			    (char *)bp->b_data;
    707 			brelse(bp, 0);
    708 			return 1;
    709 		}
    710 	}
    711 done:
    712 	brelse(bp, 0);
    713 	return 0;
    714 }
    715 
    716 /*
    717  * Attempt to read a disk label from a device using the indicated strategy
    718  * routine.  The label must be partly set up before this: secpercyl and
    719  * anything required in the strategy routine (e.g., sector size) must be
    720  * filled in before calling us.  Returns null on success and an error
    721  * string on failure.
    722  */
    723 const char *
    724 readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
    725     struct cpu_disklabel *osdep)
    726 {
    727 	struct buf *bp;
    728 	const char *msg = NULL;
    729 
    730 	if (lp->d_secperunit == 0)
    731 		lp->d_secperunit = 0x1fffffff;
    732 
    733 	if (lp->d_secpercyl == 0) {
    734 		return msg = "Zero secpercyl";
    735 	}
    736 
    737 	/* no valid RDB found */
    738 	osdep->rdblock = RDBNULL;
    739 
    740 	/* XXX cd_start is abused as a flag for fictitious disklabel */
    741 	osdep->cd_start = -1;
    742 
    743 	osdep->cd_labelsector = LABELSECTOR;
    744 	osdep->cd_labeloffset = LABELOFFSET;
    745 
    746 	bp = geteblk((int)lp->d_secsize);
    747 
    748 	bp->b_dev = dev;
    749 	bp->b_blkno = MBR_BBSECTOR;
    750 	bp->b_resid = 0;
    751 	bp->b_bcount = lp->d_secsize;
    752 	bp->b_flags |= B_READ;
    753 	bp->b_cylinder = MBR_BBSECTOR / lp->d_secpercyl;
    754 	(*strat)(bp);
    755 
    756 	if (biowait(bp)) {
    757 		msg = "I/O error reading block zero";
    758 		goto done;
    759 	}
    760 
    761 	if (bswap16(*(u_int16_t *)((char *)bp->b_data + MBR_MAGIC_OFFSET))
    762 	    == MBR_MAGIC) {
    763 		/*
    764 		 * We've got an MBR partitioned disk.
    765 		 * read_dos_label figures out labelsector/offset itself
    766 		 */
    767 		msg = read_dos_label(dev, strat, lp, osdep);
    768 	} else {
    769 #ifdef RDB_PART
    770 		/* scan for RDB partitions */
    771 		msg = read_rdb_label(dev, strat, lp, osdep);
    772 #else
    773 		msg = "no NetBSD disk label";
    774 #endif
    775 		if (msg != NULL) {
    776 			/* try reading a raw NetBSD disklabel at last */
    777 			if (read_netbsd_label(dev, strat, lp, osdep))
    778 				msg = NULL;
    779 		}
    780 	}
    781 	if (msg == NULL)
    782 		osdep->cd_start = 0;
    783 
    784     done:
    785 	brelse(bp, 0);
    786 	return msg;
    787 }
    788 
    789 /*
    790  * Write disk label back to device after modification.
    791  */
    792 int
    793 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
    794     struct cpu_disklabel *osdep)
    795 {
    796 	struct buf *bp;
    797 	int error;
    798 	struct disklabel label;
    799 
    800 	/*
    801 	 * Try to re-read a disklabel, in case the MBR was modified.
    802 	 */
    803 	label = *lp;
    804 	readdisklabel(dev, strat, &label, osdep);
    805 
    806 	/* If an RDB was present, we don't support writing it yet. */
    807 	if (osdep->rdblock != RDBNULL)
    808 		return EINVAL;
    809 
    810 	/* get a buffer and initialize it */
    811 	bp = geteblk(lp->d_secsize);
    812 	bp->b_dev = dev;
    813 
    814 	bp->b_blkno = osdep->cd_labelsector;
    815 	bp->b_cylinder = bp->b_blkno / (lp->d_secsize / DEV_BSIZE) /
    816 	    lp->d_secpercyl;
    817 	bp->b_bcount = lp->d_secsize;
    818 
    819 	bp->b_flags |= B_READ;
    820 	(*strat)(bp);
    821 	error = biowait(bp);
    822 	if (error != 0)
    823 		goto done;
    824 
    825 	bp->b_flags &= ~B_READ;
    826 	bp->b_flags |= B_WRITE;
    827 	bp->b_oflags &= ~BO_DONE;
    828 
    829 	memcpy((char *)bp->b_data + osdep->cd_labeloffset, (void *)lp,
    830 	    sizeof *lp);
    831 
    832 	(*strat)(bp);
    833 	error = biowait(bp);
    834 
    835     done:
    836 	brelse(bp, 0);
    837 
    838 	return error;
    839 }
    840