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