Home | History | Annotate | Line # | Download | only in sh3
      1 /*	$NetBSD: disksubr.c,v 1.32 2024/06/02 19:20:09 andvar Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
      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. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  *
     31  *	@(#)ufs_disksubr.c	7.16 (Berkeley) 5/4/91
     32  */
     33 
     34 #include <sys/cdefs.h>
     35 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.32 2024/06/02 19:20:09 andvar Exp $");
     36 
     37 #include "opt_mbr.h"
     38 
     39 #include <sys/param.h>
     40 #include <sys/systm.h>
     41 #include <sys/buf.h>
     42 #include <sys/disklabel.h>
     43 #include <sys/disk.h>
     44 #include <sys/syslog.h>
     45 
     46 #include <sys/bswap.h>
     47 
     48 int fat_types[] = { MBR_PTYPE_FAT12, MBR_PTYPE_FAT16S,
     49 		    MBR_PTYPE_FAT16B, MBR_PTYPE_FAT32,
     50 		    MBR_PTYPE_FAT32L, MBR_PTYPE_FAT16L,
     51 		    -1 };
     52 
     53 #define	NO_MBR_SIGNATURE ((struct mbr_partition *) -1)
     54 
     55 #ifdef BSDDISKLABEL_EI
     56 void swap_endian_disklabel(struct disklabel *, struct disklabel *);
     57 uint16_t dkcksum_re(struct disklabel *);
     58 #endif
     59 #ifdef COMPAT_MMEYE_OLDLABEL
     60 void swap_mmeye_disklabel(struct disklabel *, struct disklabel *);
     61 uint16_t dkcksum_mmeye(struct disklabel *);
     62 #endif
     63 
     64 static struct mbr_partition *mbr_findslice(struct mbr_partition *,
     65     struct buf *);
     66 
     67 #ifdef BSDDISKLABEL_EI
     68 void
     69 swap_endian_disklabel(struct disklabel *nlp, struct disklabel *olp)
     70 {
     71 	int i;
     72 #define	SW16(X) nlp->X = bswap16(olp->X)
     73 #define	SW32(X) nlp->X = bswap32(olp->X)
     74 
     75 	SW32(d_magic);
     76 	SW16(d_type);
     77 	SW16(d_subtype);
     78 
     79 	/* no need to swap char strings */
     80 	memcpy(nlp->d_typename, olp->d_typename, sizeof(nlp->d_typename));
     81 
     82 	/* XXX What should we do for d_un (an union of char and pointers) ? */
     83 	memcpy(nlp->d_packname, olp->d_packname, sizeof(nlp->d_packname));
     84 
     85 	SW32(d_secsize);
     86 	SW32(d_nsectors);
     87 	SW32(d_ntracks);
     88 	SW32(d_ncylinders);
     89 	SW32(d_secpercyl);
     90 	SW32(d_secperunit);
     91 
     92 	SW16(d_sparespertrack);
     93 	SW16(d_sparespercyl);
     94 
     95 	SW32(d_acylinders);
     96 
     97 	SW16(d_rpm);
     98 	SW16(d_interleave);
     99 	SW16(d_trackskew);		/* sector 0 skew, per track */
    100 	SW16(d_cylskew);		/* sector 0 skew, per cylinder */
    101 	SW32(d_headswitch);		/* head switch time, usec */
    102 	SW32(d_trkseek);		/* track-to-track seek, usec */
    103 	SW32(d_flags);			/* generic flags */
    104 
    105 	for (i = 0; i < NDDATA; i++)
    106 		SW32(d_drivedata[i]);	/* drive-type specific information */
    107 
    108 	for (i = 0; i < NSPARE; i++)
    109 		SW32(d_spare[i]);	/* reserved for future use */
    110 
    111 	SW32(d_magic2);			/* the magic number (again) */
    112 	SW16(d_checksum);		/* xor of data incl. partitions */
    113 
    114 	/* filesystem and partition information: */
    115 	SW16(d_npartitions);	/* number of partitions in following */
    116 	SW32(d_bbsize);		/* size of boot area at sn0, bytes */
    117 	SW32(d_sbsize);		/* max size of fs superblock, bytes */
    118 
    119 	for (i = 0; i < MAXPARTITIONS; i++) {
    120 		SW32(d_partitions[i].p_size);
    121 		SW32(d_partitions[i].p_offset);
    122 		SW32(d_partitions[i].p_fsize);
    123 		/* p_fstype and p_frag is uint8_t, so no need to swap */
    124 		nlp->d_partitions[i].p_fstype = olp->d_partitions[i].p_fstype;
    125 		nlp->d_partitions[i].p_frag = olp->d_partitions[i].p_frag;
    126 		SW16(d_partitions[i].p_cpg);
    127 	}
    128 #undef SW32
    129 #undef SW16
    130 }
    131 
    132 uint16_t
    133 dkcksum_re(struct disklabel *lp)
    134 {
    135 	uint16_t *start, *end;
    136 	uint16_t sum = 0;
    137 
    138 	start = (uint16_t *)lp;
    139 	end = (uint16_t *)&lp->d_partitions[bswap16(lp->d_npartitions)];
    140 	while (start < end)
    141 		sum ^= *start++;
    142 	return (sum);
    143 }
    144 #endif
    145 
    146 #ifdef COMPAT_MMEYE_OLDLABEL
    147 void
    148 swap_mmeye_disklabel(struct disklabel *nlp, struct disklabel *olp)
    149 {
    150 	int i;
    151 	uint16_t *np, *op;
    152 
    153 #if BYTE_ORDER == BIG_ENDIAN
    154 #define	SW16(X) nlp->X = bswap16(olp->X)
    155 #define	SW32(X) nlp->X = bswap32(olp->X)
    156 #else
    157 #define	SW16(X) nlp->X = olp->X
    158 #define	SW32(X) nlp->X = olp->X
    159 #endif
    160 
    161 	SW32(d_magic);
    162 	SW16(d_type);
    163 	SW16(d_subtype);
    164 
    165 	op = (uint16_t *)&olp->d_typename[0];
    166 	np = (uint16_t *)&nlp->d_typename[0];
    167 	for (i = 0; i < sizeof(olp->d_typename) / sizeof(uint16_t); i++)
    168 		*np++ = bswap16(*op++);
    169 
    170 	op = (uint16_t *)&olp->d_un.un_d_packname[0];
    171 	np = (uint16_t *)&nlp->d_un.un_d_packname[0];
    172 	for (i = 0; i < sizeof(olp->d_un) / sizeof(uint16_t); i++)
    173 		*np++ = bswap16(*op++);
    174 
    175 	SW32(d_secsize);
    176 	SW32(d_nsectors);
    177 	SW32(d_ntracks);
    178 	SW32(d_ncylinders);
    179 	SW32(d_secpercyl);
    180 	SW32(d_secperunit);
    181 
    182 	SW16(d_sparespertrack);
    183 	SW16(d_sparespercyl);
    184 
    185 	SW32(d_acylinders);
    186 
    187 	SW16(d_rpm);
    188 	SW16(d_interleave);
    189 	SW16(d_trackskew);		/* sector 0 skew, per track */
    190 	SW16(d_cylskew);		/* sector 0 skew, per cylinder */
    191 	SW32(d_headswitch);		/* head switch time, usec */
    192 	SW32(d_trkseek);		/* track-to-track seek, usec */
    193 	SW32(d_flags);			/* generic flags */
    194 
    195 	for (i = 0; i < NDDATA; i++)
    196 		SW32(d_drivedata[i]);	/* drive-type specific information */
    197 
    198 	for (i = 0; i < NSPARE; i++)
    199 		SW32(d_spare[i]);	/* reserved for future use */
    200 
    201 	SW32(d_magic2);			/* the magic number (again) */
    202 	SW16(d_checksum);		/* xor of data incl. partitions */
    203 
    204 	/* filesystem and partition information: */
    205 	SW16(d_npartitions);	/* number of partitions in following */
    206 	SW32(d_bbsize);		/* size of boot area at sn0, bytes */
    207 	SW32(d_sbsize);		/* max size of fs superblock, bytes */
    208 
    209 	for (i = 0; i < MAXPARTITIONS; i++) {
    210 		SW32(d_partitions[i].p_size);
    211 		SW32(d_partitions[i].p_offset);
    212 		SW32(d_partitions[i].p_fsize);
    213 		nlp->d_partitions[i].p_fstype = olp->d_partitions[i].p_fstype;
    214 		nlp->d_partitions[i].p_frag = olp->d_partitions[i].p_frag;
    215 		SW16(d_partitions[i].p_cpg);
    216 	}
    217 #undef SW32
    218 #undef SW16
    219 }
    220 
    221 uint16_t
    222 dkcksum_mmeye(struct disklabel *lp)
    223 {
    224 	struct disklabel tdl;
    225 	int i, offset;
    226 	uint16_t *start, *end, *fstype;
    227 	uint16_t sum = 0;
    228 
    229 	tdl = *lp;
    230 
    231 	for (i = 0; i < MAXPARTITIONS; i++) {
    232 		fstype = (uint16_t *)&tdl.d_partitions[i].p_fstype;
    233 		*fstype = bswap16(*fstype);
    234 	}
    235 
    236 	offset = offsetof(struct disklabel,
    237 	    d_partitions[le16toh(lp->d_npartitions)]);
    238 	start = (uint16_t *)&tdl;
    239 	end = start + offset;
    240 
    241 	while (start < end)
    242 		sum ^= *start++;
    243 
    244 #ifdef COMPAT_MMEYE_OLDLABEL_BROKEN
    245 	if (sum != 0 &&
    246 	    tdl.d_checksum == 0) {
    247 		printf("disklabel: mmeye oldlabel broken found\n");
    248 		sum = 0;	/* XXXX */
    249 	}
    250 #endif
    251 
    252 	return (sum);
    253 }
    254 #endif
    255 
    256 /*
    257  * Scan MBR for  NetBSD partition.  Return NO_MBR_SIGNATURE if no MBR found
    258  * Otherwise, copy valid MBR partition-table into dp, and if a NetBSD
    259  * partition is found, return a pointer to it; else return  NULL.
    260  */
    261 static struct mbr_partition *
    262 mbr_findslice(struct mbr_partition *dp, struct buf *bp)
    263 {
    264 	struct mbr_partition *ourdp = NULL;
    265 	uint16_t *mbrmagicp;
    266 	int i;
    267 
    268 	/* Note: Magic number is little-endian. */
    269 	mbrmagicp = (uint16_t *)((char *)bp->b_data + MBR_MAGIC_OFFSET);
    270 	if (le16toh(*mbrmagicp) != MBR_MAGIC)
    271 		return (NO_MBR_SIGNATURE);
    272 
    273 	/* XXX how do we check veracity/bounds of this? */
    274 	memcpy(dp, (char *)bp->b_data + MBR_PART_OFFSET,
    275 		MBR_PART_COUNT * sizeof(*dp));
    276 
    277 	/* look for NetBSD partition */
    278 	for (i = 0; i < MBR_PART_COUNT; i++) {
    279 		if (dp[i].mbrp_type == MBR_PTYPE_NETBSD) {
    280 			ourdp = &dp[i];
    281 			break;
    282 		}
    283 	}
    284 
    285 	return (ourdp);
    286 }
    287 
    288 
    289 /*
    290  * Attempt to read a disk label from a device
    291  * using the indicated strategy routine.
    292  * The label must be partly set up before this:
    293  * secpercyl, secsize and anything required for a block i/o read
    294  * operation in the driver's strategy/start routines
    295  * must be filled in before calling us.
    296  *
    297  * If dos partition table requested, attempt to load it and
    298  * find disklabel inside a DOS partition. Also, if bad block
    299  * table needed, attempt to extract it as well. Return buffer
    300  * for use in signalling errors if requested.
    301  *
    302  * Returns null on success and an error string on failure.
    303  */
    304 const char *
    305 readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
    306     struct cpu_disklabel *osdep)
    307 {
    308 	struct mbr_partition *dp;
    309 	struct partition *pp;
    310 	struct dkbad *bdp;
    311 	struct buf *bp;
    312 	struct disklabel *dlp;
    313 	const char *msg = NULL;
    314 	int dospartoff, cyl, i, *ip;
    315 
    316 	/* minimal requirements for archtypal disk label */
    317 	if (lp->d_secsize == 0)
    318 		lp->d_secsize = DEV_BSIZE;
    319 	if (lp->d_secperunit == 0)
    320 		lp->d_secperunit = 0x1fffffff;
    321 #if 0
    322 	if (lp->d_ncylinders == 16383) {
    323 		printf("disklabel: Disk > 8G ... readjusting chs %d/%d/%d to ",
    324 		    lp->d_ncylinders, lp->d_ntracks, lp->d_nsectors);
    325 		lp->d_ncylinders = lp->d_secperunit /  lp->d_ntracks / lp->d_nsectors;
    326 		printf("%d/%d/%d\n",
    327 		    lp->d_ncylinders, lp->d_ntracks, lp->d_nsectors);
    328 	}
    329 #endif
    330 	lp->d_npartitions = RAW_PART + 1;
    331 	for (i = 0; i < RAW_PART; i++) {
    332 		lp->d_partitions[i].p_size = 0;
    333 		lp->d_partitions[i].p_offset = 0;
    334 	}
    335 	if (lp->d_partitions[i].p_size == 0)
    336 		lp->d_partitions[i].p_size = 0x1fffffff;
    337 	lp->d_partitions[i].p_offset = 0;
    338 
    339 	/* get a buffer and initialize it */
    340 	bp = geteblk((int)lp->d_secsize);
    341 	bp->b_dev = dev;
    342 
    343 	/* do dos partitions in the process of getting disklabel? */
    344 	dospartoff = 0;
    345 	cyl = LABELSECTOR / lp->d_secpercyl;
    346 	if (!osdep)
    347 		goto nombrpart;
    348 	dp = osdep->mbrparts;
    349 
    350 	/* read master boot record */
    351 	bp->b_blkno = MBR_BBSECTOR;
    352 	bp->b_bcount = lp->d_secsize;
    353 	bp->b_flags |= B_READ;
    354 	bp->b_cylinder = MBR_BBSECTOR / lp->d_secpercyl;
    355 	(*strat)(bp);
    356 
    357 	/* if successful, wander through dos partition table */
    358 	if (biowait(bp)) {
    359 		msg = "dos partition I/O error";
    360 		goto done;
    361 	} else {
    362 		struct mbr_partition *ourdp = NULL;
    363 
    364 		ourdp = mbr_findslice(dp, bp);
    365 		if (ourdp == NO_MBR_SIGNATURE)
    366 			goto nombrpart;
    367 
    368 		for (i = 0; i < MBR_PART_COUNT; i++, dp++) {
    369 			/* Install in partition e, f, g, or h. */
    370 			pp = &lp->d_partitions[RAW_PART + 1 + i];
    371 			pp->p_offset = le32toh(dp->mbrp_start);
    372 			pp->p_size = le32toh(dp->mbrp_size);
    373 			for (ip = fat_types; *ip != -1; ip++) {
    374 				if (dp->mbrp_type == *ip)
    375 					pp->p_fstype = FS_MSDOS;
    376 			}
    377 			if (dp->mbrp_type == MBR_PTYPE_LNXEXT2)
    378 				pp->p_fstype = FS_EX2FS;
    379 
    380 			if (dp->mbrp_type == MBR_PTYPE_NTFS)
    381 				pp->p_fstype = FS_NTFS;
    382 
    383 			/* is this ours? */
    384 			if (dp == ourdp) {
    385 				/* need sector address for SCSI/IDE,
    386 				   cylinder for ESDI/ST506/RLL */
    387 				dospartoff = le32toh(dp->mbrp_start);
    388 				cyl = MBR_PCYL(dp->mbrp_scyl, dp->mbrp_ssect);
    389 
    390 				/* update disklabel with details */
    391 				lp->d_partitions[2].p_size =
    392 				    le32toh(dp->mbrp_size);
    393 				lp->d_partitions[2].p_offset =
    394 				    le32toh(dp->mbrp_start);
    395 #if 0
    396 				if (lp->d_ntracks != dp->mbrp_ehd + 1 ||
    397 				    lp->d_nsectors != MBR_PSECT(dp->mbrp_esect)) {
    398 					printf("disklabel: BIOS sees chs %d/%d/%d as ",
    399 					    lp->d_ncylinders, lp->d_ntracks,
    400 					    lp->d_nsectors);
    401 					lp->d_ntracks = dp->mbrp_ehd + 1;
    402 					lp->d_nsectors = MBR_PSECT(dp->mbrp_esect);
    403 					lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
    404 					lp->d_ncylinders = lp->d_secperunit / lp->d_secpercyl;
    405 					if (! lp->d_ncylinders)
    406 						lp->d_ncylinders = 1;
    407 					printf("%d/%d/%d\n",
    408 					    lp->d_ncylinders, lp->d_ntracks,
    409 					    lp->d_nsectors);
    410 				}
    411 #endif
    412 			}
    413 		}
    414 		lp->d_npartitions = RAW_PART + 1 + i;
    415 	}
    416 
    417  nombrpart:
    418 	/* next, dig out disk label */
    419 	bp->b_blkno = dospartoff + LABELSECTOR;
    420 	bp->b_cylinder = cyl;
    421 	bp->b_bcount = lp->d_secsize;
    422 	bp->b_oflags &= ~(BO_DONE);
    423 	bp->b_flags |= B_READ;
    424 	(*strat)(bp);
    425 
    426 	/* if successful, locate disk label within block and validate */
    427 	if (biowait(bp)) {
    428 		msg = "disk label I/O error";
    429 		goto done;
    430 	}
    431 	for (dlp = (struct disklabel *)bp->b_data;
    432 	    dlp <= (struct disklabel *)((char *)bp->b_data + lp->d_secsize -
    433 		sizeof(*dlp));
    434 	    dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
    435 		if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC) {
    436 			/* disklabel is written in host's endian */
    437 			if (dlp->d_npartitions > MAXPARTITIONS ||
    438 			    dkcksum(dlp) != 0)
    439 				msg = "disk label corrupted";
    440 			else {
    441 				*lp = *dlp;
    442 				msg = NULL;
    443 				break;
    444 			}
    445 		}
    446 #ifdef BSDDISKLABEL_EI
    447 		if (bswap32(dlp->d_magic) == DISKMAGIC &&
    448 		    bswap32(dlp->d_magic2) == DISKMAGIC) {
    449 			/* disklabel is written in reversed endian */
    450 			if (bswap16(dlp->d_npartitions) > MAXPARTITIONS ||
    451 			    dkcksum_re(dlp) != 0)
    452 				msg = "disk label corrupted";
    453 			else {
    454 				swap_endian_disklabel(lp, dlp);
    455 				/* recalculate cksum in host's endian */
    456 				lp->d_checksum = 0;
    457 				lp->d_checksum = dkcksum(lp);
    458 
    459 				msg = NULL;
    460 				break;
    461 			}
    462 		}
    463 #endif
    464 #ifdef COMPAT_MMEYE_OLDLABEL
    465 		if (le32toh(dlp->d_magic) == DISKMAGIC &&
    466 		    le32toh(dlp->d_magic2) == DISKMAGIC) {
    467 			if (le16toh(dlp->d_npartitions) > MAXPARTITIONS ||
    468 			    dkcksum_mmeye(dlp) != 0)
    469 				msg = "disk label corrupted";
    470 			else {
    471 				/* disklabel is written in old mmeye's way */
    472 				swap_mmeye_disklabel(lp, dlp);
    473 				/* recalculate cksum in host's endian */
    474 				lp->d_checksum = 0;
    475 				lp->d_checksum = dkcksum(lp);
    476 
    477 				msg = NULL;
    478 				break;
    479 			}
    480 		}
    481 #endif
    482 		if (msg == NULL)
    483 			msg = "no disk label";
    484 	}
    485 
    486 	if (msg)
    487 		goto done;
    488 
    489 	/* obtain bad sector table if requested and present */
    490 	if (osdep && (lp->d_flags & D_BADSECT)) {
    491 		struct dkbad *db;
    492 
    493 		bdp = &osdep->bad;
    494 		i = 0;
    495 		do {
    496 			/* read a bad sector table */
    497 			bp->b_oflags &= ~(BO_DONE);
    498 			bp->b_flags |= B_READ;
    499 			bp->b_blkno = lp->d_secperunit - lp->d_nsectors + i;
    500 			if (lp->d_secsize > DEV_BSIZE)
    501 				bp->b_blkno *= lp->d_secsize / DEV_BSIZE;
    502 			else
    503 				bp->b_blkno /= DEV_BSIZE / lp->d_secsize;
    504 			bp->b_bcount = lp->d_secsize;
    505 			bp->b_cylinder = lp->d_ncylinders - 1;
    506 			(*strat)(bp);
    507 
    508 			/* if successful, validate, otherwise try another */
    509 			if (biowait(bp)) {
    510 				msg = "bad sector table I/O error";
    511 			} else {
    512 				db = (struct dkbad *)(bp->b_data);
    513 #define	DKBAD_MAGIC 0x4321
    514 				if (db->bt_mbz == 0
    515 				    && db->bt_flag == DKBAD_MAGIC) {
    516 					msg = NULL;
    517 					*bdp = *db;
    518 					break;
    519 				} else
    520 					msg = "bad sector table corrupted";
    521 			}
    522 		} while (bp->b_error != 0 && (i += 2) < 10 &&
    523 		    i < lp->d_nsectors);
    524 	}
    525 
    526  done:
    527 	brelse(bp, 0);
    528 	return (msg);
    529 }
    530 
    531 /*
    532  * Write disk label back to device after modification.
    533  */
    534 int
    535 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
    536     struct cpu_disklabel *osdep)
    537 {
    538 	struct mbr_partition *dp;
    539 	struct buf *bp;
    540 	struct disklabel *dlp;
    541 	int error, dospartoff, cyl;
    542 
    543 	/* get a buffer and initialize it */
    544 	bp = geteblk((int)lp->d_secsize);
    545 	bp->b_dev = dev;
    546 
    547 	/* do dos partitions in the process of getting disklabel? */
    548 	dospartoff = 0;
    549 	cyl = LABELSECTOR / lp->d_secpercyl;
    550 	if (!osdep)
    551 		goto nombrpart;
    552 	dp = osdep->mbrparts;
    553 
    554 	/* read master boot record */
    555 	bp->b_blkno = MBR_BBSECTOR;
    556 	bp->b_bcount = lp->d_secsize;
    557 	bp->b_flags |= B_READ;
    558 	bp->b_cylinder = MBR_BBSECTOR / lp->d_secpercyl;
    559 	(*strat)(bp);
    560 
    561 	if ((error = biowait(bp)) == 0) {
    562 		struct mbr_partition *ourdp = NULL;
    563 
    564 		ourdp = mbr_findslice(dp, bp);
    565 		if (ourdp ==  NO_MBR_SIGNATURE)
    566 			goto nombrpart;
    567 
    568 		if (ourdp) {
    569 			/* need sector address for SCSI/IDE,
    570 			   cylinder for ESDI/ST506/RLL */
    571 			dospartoff = le32toh(ourdp->mbrp_start);
    572 			cyl = MBR_PCYL(ourdp->mbrp_scyl, ourdp->mbrp_ssect);
    573 		}
    574 	}
    575 
    576  nombrpart:
    577 #ifdef maybe
    578 	/* disklabel in appropriate location? */
    579 	if (lp->d_partitions[2].p_offset != 0
    580 	    && lp->d_partitions[2].p_offset != dospartoff) {
    581 		error = EXDEV;
    582 		goto done;
    583 	}
    584 #endif
    585 
    586 	/* next, dig out disk label */
    587 	bp->b_blkno = dospartoff + LABELSECTOR;
    588 	bp->b_cylinder = cyl;
    589 	bp->b_bcount = lp->d_secsize;
    590 	bp->b_oflags &= ~(BO_DONE);
    591 	bp->b_flags |= B_READ;
    592 	(*strat)(bp);
    593 
    594 	/* if successful, locate disk label within block and validate */
    595 	if ((error = biowait(bp)) != 0)
    596 		goto done;
    597 	for (dlp = (struct disklabel *)bp->b_data;
    598 	    dlp <= (struct disklabel *)((char *)bp->b_data + lp->d_secsize -
    599 		sizeof(*dlp));
    600 	    dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
    601 		if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC &&
    602 		    dlp->d_npartitions <= MAXPARTITIONS &&
    603 		    dkcksum(dlp) == 0) {
    604 			/* found disklabel in host's endian */
    605 			*dlp = *lp;
    606 			goto found;
    607 #ifdef BSDDISKLABEL_EI
    608 		} else if (bswap32(dlp->d_magic) == DISKMAGIC &&
    609 		    bswap32(dlp->d_magic2) == DISKMAGIC &&
    610 		    bswap16(dlp->d_npartitions) <= MAXPARTITIONS &&
    611 		    dkcksum_re(dlp) == 0) {
    612 			/* found disklabel in the opposite endian */
    613 			swap_endian_disklabel(dlp, lp);
    614 			/* recalculate cksum in reversed endian */
    615 			dlp->d_checksum = 0;
    616 			dlp->d_checksum = dkcksum_re(dlp);
    617 			goto found;
    618 #endif
    619 #ifdef COMPAT_MMEYE_OLDLABEL
    620 		} else if (le32toh(dlp->d_magic) == DISKMAGIC &&
    621 		    le32toh(dlp->d_magic2) == DISKMAGIC &&
    622 		    le16toh(dlp->d_npartitions) <= MAXPARTITIONS &&
    623 		    dkcksum_mmeye(dlp) == 0) {
    624 			/* found disklabel by old mmeye's rule */
    625 			swap_mmeye_disklabel(dlp, lp);
    626 			/* recalculate cksum for it */
    627 			dlp->d_checksum = 0;
    628 			dlp->d_checksum = dkcksum_mmeye(dlp);
    629 			goto found;
    630 #endif
    631 		}
    632 	}
    633 	/* No valid disklabel found on disk */
    634 	error = ESRCH;
    635 	goto done;
    636 
    637  found:
    638 	bp->b_oflags &= ~(BO_DONE);
    639 	bp->b_flags &= ~(B_READ);
    640 	bp->b_flags |= B_WRITE;
    641 	(*strat)(bp);
    642 	error = biowait(bp);
    643 
    644  done:
    645 	brelse(bp, 0);
    646 	return (error);
    647 }
    648