xref: /netbsd/sys/arch/macppc/macppc/disksubr.c (revision bf9ec67e)
1 /*	$NetBSD: disksubr.c,v 1.20 2002/03/27 20:23:11 wrstuden 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  * Copyright (C) 1993	Allen K. Briggs, Chris P. Caputo,
39  *			Michael L. Finch, Bradley A. Grantham, and
40  *			Lawrence A. Kesteloot
41  * All rights reserved.
42  *
43  * Redistribution and use in source and binary forms, with or without
44  * modification, are permitted provided that the following conditions
45  * are met:
46  * 1. Redistributions of source code must retain the above copyright
47  *    notice, this list of conditions and the following disclaimer.
48  * 2. Redistributions in binary form must reproduce the above copyright
49  *    notice, this list of conditions and the following disclaimer in the
50  *    documentation and/or other materials provided with the distribution.
51  * 3. All advertising materials mentioning features or use of this software
52  *    must display the following acknowledgement:
53  *	This product includes software developed by the Alice Group.
54  * 4. The names of the Alice Group or any of its members may not be used
55  *    to endorse or promote products derived from this software without
56  *    specific prior written permission.
57  *
58  * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``AS IS'' AND ANY EXPRESS OR
59  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
60  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
61  * IN NO EVENT SHALL THE ALICE GROUP BE LIABLE FOR ANY DIRECT, INDIRECT,
62  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
63  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
64  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
65  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
66  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
67  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
68  *
69  */
70 /*
71  * Copyright (C) 1996 Wolfgang Solfrank.
72  * Copyright (C) 1996 TooLs GmbH.
73  * All rights reserved.
74  *
75  * Redistribution and use in source and binary forms, with or without
76  * modification, are permitted provided that the following conditions
77  * are met:
78  * 1. Redistributions of source code must retain the above copyright
79  *    notice, this list of conditions and the following disclaimer.
80  * 2. Redistributions in binary form must reproduce the above copyright
81  *    notice, this list of conditions and the following disclaimer in the
82  *    documentation and/or other materials provided with the distribution.
83  * 3. All advertising materials mentioning features or use of this software
84  *    must display the following acknowledgement:
85  *	This product includes software developed by TooLs GmbH.
86  * 4. The name of TooLs GmbH may not be used to endorse or promote products
87  *    derived from this software without specific prior written permission.
88  *
89  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
90  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
91  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
92  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
93  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
94  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
95  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
96  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
97  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
98  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
99  */
100 
101 /* rewritten, 2-5-93 MLF */
102 /* its alot cleaner now, and adding support for new partition types
103  * isn't a bitch anymore
104  * known bugs:
105  * 1) when only an HFS_PART part exists on a drive it gets assigned to "B"
106  * this is because of line 623 of sd.c, I think this line should go.
107  * 2) /sbin/disklabel expects the whole disk to be in "D", we put it in
108  * "C" (I think) and we don't set that position in the disklabel structure
109  * as used.  Again, not my fault.
110  */
111 #include <sys/param.h>
112 #include <sys/systm.h>
113 #include <sys/buf.h>
114 #include <sys/conf.h>
115 #include <sys/disk.h>
116 #include <sys/disklabel.h>
117 #include <sys/disklabel_mbr.h>
118 #include <sys/syslog.h>
119 
120 #include <machine/bswap.h>
121 
122 #define NUM_PARTS 32
123 
124 #define ROOT_PART 1
125 #define UFS_PART 2
126 #define SWAP_PART 3
127 #define HFS_PART 4
128 #define SCRATCH_PART 5
129 
130 int fat_types[] = { MBR_PTYPE_FAT12, MBR_PTYPE_FAT16S,
131 		    MBR_PTYPE_FAT16B, MBR_PTYPE_FAT32,
132 		    MBR_PTYPE_FAT32L, MBR_PTYPE_FAT16L,
133 		    -1 };
134 
135 static int getFreeLabelEntry __P((struct disklabel *));
136 static int whichType __P((struct part_map_entry *, u_int8_t *, int *));
137 static void setpartition __P((struct part_map_entry *,
138 		struct partition *, int));
139 static int getNamedType __P((struct part_map_entry *, int,
140 		struct disklabel *, int, int, int *));
141 static char *read_mac_label __P((dev_t, void (*)(struct buf *),
142 		struct disklabel *, struct cpu_disklabel *));
143 static char *read_dos_label __P((dev_t, void (*)(struct buf *),
144 		struct disklabel *, struct cpu_disklabel *));
145 static int get_netbsd_label __P((dev_t dev, void (*strat)(struct buf *),
146 		struct disklabel *lp, daddr_t bno));
147 
148 /*
149  * Find an entry in the disk label that is unused and return it
150  * or -1 if no entry
151  */
152 static int
153 getFreeLabelEntry(lp)
154 	struct disklabel *lp;
155 {
156 	int i = 0;
157 
158 	for (i = 0; i < MAXPARTITIONS; i++) {
159 		if ((i != RAW_PART)
160 		    && (lp->d_partitions[i].p_fstype == FS_UNUSED))
161 			return i;
162 	}
163 
164 	return -1;
165 }
166 
167 /*
168  * figure out what the type of the given part is and return it
169  */
170 static int
171 whichType(struct part_map_entry *part, u_int8_t *fstype, int *clust)
172 {
173 	struct blockzeroblock *bzb;
174 	char typestr[32], *s;
175 	int type;
176 
177 	/* Set default unix partition type. Certain partition types can
178 	 * specify a different partition type. */
179 	*fstype = FS_BSDFFS;
180 	*clust = 0;	/* only A/UX partitions not in cluster 0 */
181 
182 	if (part->pmSig != PART_ENTRY_MAGIC || part->pmPartType[0] == '\0')
183 		return 0;
184 
185 	strncpy(typestr, (char *)part->pmPartType, sizeof(typestr));
186 	typestr[sizeof(typestr) - 1] = '\0';
187 	for (s = typestr; *s; s++)
188 		if ((*s >= 'a') && (*s <= 'z'))
189 			*s = (*s - 'a' + 'A');
190 
191 	if (strncmp(PART_TYPE_DRIVER, typestr, strlen(PART_TYPE_DRIVER)) == 0 ||
192 	    strcmp(PART_TYPE_DRIVER43, typestr) == 0 ||
193 	    strcmp(PART_TYPE_DRIVERATA, typestr) == 0 ||
194 	    strcmp(PART_TYPE_DRIVERIOKIT, typestr) == 0 ||
195 	    strcmp(PART_TYPE_FWDRIVER, typestr) == 0 ||
196 	    strcmp(PART_TYPE_FWB_COMPONENT, typestr) == 0 ||
197 	    strcmp(PART_TYPE_PARTMAP, typestr) == 0 ||
198 	    strcmp(PART_TYPE_PATCHES, typestr) == 0)
199 		type = 0;
200 	else if (strcmp(PART_TYPE_NBSD_PPCBOOT, typestr) == 0) {
201 		type = ROOT_PART;
202 		bzb = (struct blockzeroblock *)(&part->pmBootArgs);
203 		if ((bzb->bzbMagic == BZB_MAGIC) &&
204 		    (bzb->bzbType < FSMAXTYPES))
205 			*fstype = bzb->bzbType;
206 	} else if (strcmp(PART_TYPE_NETBSD, typestr) == 0 ||
207 		 strcmp(PART_TYPE_NBSD_68KBOOT, typestr) == 0) {
208 		type = UFS_PART;
209 		bzb = (struct blockzeroblock *)(&part->pmBootArgs);
210 		if ((bzb->bzbMagic == BZB_MAGIC) &&
211 		    (bzb->bzbType < FSMAXTYPES))
212 			*fstype = bzb->bzbType;
213 	} else if (strcmp(PART_TYPE_UNIX, typestr) == 0) {
214 		/* unix part, swap, root, usr */
215 		bzb = (struct blockzeroblock *)(&part->pmBootArgs);
216 		*clust = bzb->bzbCluster;
217 		if (bzb->bzbMagic != BZB_MAGIC)
218 			type = 0;
219 		else if (bzb->bzbFlags & BZB_ROOTFS)
220 			type = ROOT_PART;
221 		else if (bzb->bzbFlags & (BZB_USRFS | BZB_USRFS_NEW))
222 			type = UFS_PART;
223 		else if (bzb->bzbType == BZB_TYPESWAP)
224 			type = SWAP_PART;
225 		else
226 			type = SCRATCH_PART;
227 	} else if (strcmp(PART_TYPE_MAC, typestr) == 0)
228 		type = HFS_PART;
229 	else
230 		type = SCRATCH_PART;	/* no known type */
231 
232 	return type;
233 }
234 
235 static void
236 setpartition(struct part_map_entry *part, struct partition *pp, int fstype)
237 {
238 	pp->p_size = part->pmPartBlkCnt;
239 	pp->p_offset = part->pmPyPartStart;
240 	pp->p_fstype = fstype;
241 
242 	part->pmPartType[0] = '\0';
243 }
244 
245 static int
246 getNamedType(part, num_parts, lp, type, alt, maxslot)
247 	struct part_map_entry *part;
248 	int num_parts;
249 	struct disklabel *lp;
250 	int type, alt;
251 	int *maxslot;
252 {
253 	struct blockzeroblock *bzb;
254 	int i = 0, clust;
255 	u_int8_t realtype;
256 
257 	for (i = 0; i < num_parts; i++) {
258 		if (whichType(part + i, &realtype, &clust) != type)
259 			continue;
260 
261 		if (type == ROOT_PART) {
262 			bzb = (struct blockzeroblock *)
263 			    (&(part + i)->pmBootArgs);
264 			if (alt >= 0 && alt != clust)
265 				continue;
266 			setpartition(part + i, &lp->d_partitions[0], realtype);
267 		} else if (type == UFS_PART) {
268 			bzb = (struct blockzeroblock *)
269 			    (&(part + i)->pmBootArgs);
270 			if (alt >= 0 && alt != clust)
271 				continue;
272 			setpartition(part + i, &lp->d_partitions[6], realtype);
273 			if (*maxslot < 6)
274 				*maxslot = 6;
275 		} else if (type == SWAP_PART) {
276 			setpartition(part + i, &lp->d_partitions[1], FS_SWAP);
277 			if (*maxslot < 1)
278 				*maxslot = 1;
279 		} else if (type == HFS_PART) {
280 			setpartition(part + i, &lp->d_partitions[3], FS_HFS);
281 			if (*maxslot < 3)
282 				*maxslot = 3;
283 		} else
284 			printf("disksubr.c: can't do type %d\n", type);
285 
286 		return 0;
287 	}
288 
289 	return -1;
290 }
291 
292 /*
293  * MF --
294  * here's what i'm gonna do:
295  * read in the entire diskpartition table, it may be bigger or smaller
296  * than NUM_PARTS but read that many entries.  Each entry has a magic
297  * number so we'll know if an entry is crap.
298  * next fill in the disklabel with info like this
299  * next fill in the root, usr, and swap parts.
300  * then look for anything else and fit it in.
301  *	A: root
302  *	B: Swap
303  *	C: Whole disk
304  *	G: Usr
305  *
306  *
307  * I'm not entirely sure what netbsd386 wants in c & d
308  * 386bsd wants other stuff, so i'll leave them alone
309  *
310  * AKB -- I added to Mike's original algorithm by searching for a bzbCluster
311  *	of zero for root, first.  This allows A/UX to live on cluster 1 and
312  *	NetBSD to live on cluster 0--regardless of the actual order on the
313  *	disk.  This whole algorithm should probably be changed in the future.
314  */
315 static char *
316 read_mac_label(dev, strat, lp, osdep)
317 	dev_t dev;
318 	void (*strat)(struct buf *);
319 	struct disklabel *lp;
320 	struct cpu_disklabel *osdep;
321 {
322 	struct part_map_entry *part;
323 	struct partition *pp;
324 	struct buf *bp;
325 	char *msg = NULL;
326 	int i, slot, maxslot = 0, clust;
327 	u_int8_t realtype;
328 
329 	/* get buffer and initialize it */
330 	bp = geteblk((int)lp->d_secsize * NUM_PARTS);
331 	bp->b_dev = dev;
332 
333 	/* read partition map */
334 	bp->b_blkno = 1;	/* partition map starts at blk 1 */
335 	bp->b_bcount = lp->d_secsize * NUM_PARTS;
336 	bp->b_flags |= B_READ;
337 	bp->b_cylinder = 1 / lp->d_secpercyl;
338 	(*strat)(bp);
339 
340 	if (biowait(bp)) {
341 		msg = "Macintosh partition map I/O error";
342 		goto done;
343 	}
344 
345 	part = (struct part_map_entry *)bp->b_data;
346 
347 	/* Fill in standard partitions */
348 	lp->d_npartitions = RAW_PART + 1;
349 	if (getNamedType(part, NUM_PARTS, lp, ROOT_PART, 0, &maxslot))
350 		getNamedType(part, NUM_PARTS, lp, ROOT_PART, -1, &maxslot);
351 	if (getNamedType(part, NUM_PARTS, lp, UFS_PART, 0, &maxslot))
352 		getNamedType(part, NUM_PARTS, lp, UFS_PART, -1, &maxslot);
353 	getNamedType(part, NUM_PARTS, lp, SWAP_PART, -1, &maxslot);
354 	getNamedType(part, NUM_PARTS, lp, HFS_PART, -1, &maxslot);
355 
356 	/* Now get as many of the rest of the partitions as we can */
357 	for (i = 0; i < NUM_PARTS; i++) {
358 		slot = getFreeLabelEntry(lp);
359 		if (slot < 0)
360 			break;
361 
362 		pp = &lp->d_partitions[slot];
363 
364 		switch (whichType(part + i, &realtype, &clust)) {
365 		case ROOT_PART:
366 		/*
367 		 * another root part will turn into a plain old
368 		 * UFS_PART partition, live with it.
369 		 */
370 		case UFS_PART:
371 			setpartition(part + i, pp, realtype);
372 			break;
373 		case SWAP_PART:
374 			setpartition(part + i, pp, FS_SWAP);
375 			break;
376 		case HFS_PART:
377 			setpartition(part + i, pp, FS_HFS);
378 			break;
379 		case SCRATCH_PART:
380 			setpartition(part + i, pp, FS_OTHER);
381 			break;
382 		default:
383 			slot = 0;
384 			break;
385 		}
386 		if (slot > maxslot)
387 			maxslot = slot;
388 	}
389 	lp->d_npartitions = ((maxslot >= RAW_PART) ? maxslot : RAW_PART) + 1;
390 
391 done:
392 	brelse(bp);
393 	return msg;
394 }
395 
396 /* Read MS-DOS partition table.
397  *
398  * XXX -
399  * Since FFS is endian sensitive, we pay no effort in attempting to
400  * dig up *BSD/i386 disk labels that may be present on the disk.
401  * Hence anything but DOS partitions is treated as unknown FS type, but
402  * this should suffice to mount_msdos Zip and other removable media.
403  */
404 static char *
405 read_dos_label(dev, strat, lp, osdep)
406 	dev_t dev;
407 	void (*strat)(struct buf *);
408 	struct disklabel *lp;
409 	struct cpu_disklabel *osdep;
410 {
411 	struct mbr_partition *dp;
412 	struct partition *pp;
413 	struct buf *bp;
414 	char *msg = NULL;
415 	int i, *ip, slot, maxslot = 0;
416 
417 	/* get a buffer and initialize it */
418 	bp = geteblk((int)lp->d_secsize);
419 	bp->b_dev = dev;
420 
421 	/* read master boot record */
422 	bp->b_blkno = MBR_BBSECTOR;
423 	bp->b_bcount = lp->d_secsize;
424 	bp->b_flags |= B_READ;
425 	bp->b_cylinder = MBR_BBSECTOR / lp->d_secpercyl;
426 	(*strat)(bp);
427 
428 	/* if successful, wander through dos partition table */
429 	if (biowait(bp)) {
430 		msg = "dos partition I/O error";
431 		goto done;
432 	} else {
433 		/* XXX */
434 		dp = (struct mbr_partition *)(bp->b_data + MBR_PARTOFF);
435 		for (i = 0; i < NMBRPART; i++, dp++) {
436 			if (dp->mbrp_typ != 0) {
437 				slot = getFreeLabelEntry(lp);
438 				if (slot > maxslot)
439 					maxslot = slot;
440 
441 				pp = &lp->d_partitions[slot];
442 				pp->p_fstype = FS_OTHER;
443 				pp->p_offset = bswap32(dp->mbrp_start);
444 				pp->p_size = bswap32(dp->mbrp_size);
445 
446 				for (ip = fat_types; *ip != -1; ip++) {
447 					if (dp->mbrp_typ == *ip) {
448 						pp->p_fstype = FS_MSDOS;
449 						break;
450 					}
451 				}
452 			}
453 		}
454 	}
455 	lp->d_npartitions = ((maxslot >= RAW_PART) ? maxslot : RAW_PART) + 1;
456 
457  done:
458 	brelse(bp);
459 	return (msg);
460 }
461 
462 /*
463  * Get real NetBSD disk label
464  */
465 static int
466 get_netbsd_label(dev, strat, lp, bno)
467 	dev_t dev;
468 	void (*strat)(struct buf *);
469 	struct disklabel *lp;
470 	daddr_t bno;
471 {
472 	struct buf *bp;
473 	struct disklabel *dlp;
474 
475 	/* get a buffer and initialize it */
476 	bp = geteblk((int)lp->d_secsize);
477 	bp->b_dev = dev;
478 
479 	/* Now get the label block */
480 	bp->b_blkno = bno + LABELSECTOR;
481 	bp->b_bcount = lp->d_secsize;
482 	bp->b_flags |= B_READ;
483 	bp->b_cylinder = bp->b_blkno / (lp->d_secsize / DEV_BSIZE) / lp->d_secpercyl;
484 	(*strat)(bp);
485 
486 	if (biowait(bp))
487 		goto done;
488 
489 	for (dlp = (struct disklabel *)(bp->b_data + LABELOFFSET);
490 	     dlp <= (struct disklabel *)(bp->b_data + lp->d_secsize - sizeof (*dlp));
491 	     dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
492 		if (dlp->d_magic == DISKMAGIC
493 		    && dlp->d_magic2 == DISKMAGIC
494 		    && dlp->d_npartitions <= MAXPARTITIONS
495 		    && dkcksum(dlp) == 0) {
496 			*lp = *dlp;
497 			brelse(bp);
498 			return 1;
499 		}
500 	}
501 done:
502 	brelse(bp);
503 	return 0;
504 }
505 
506 /*
507  * Attempt to read a disk label from a device using the indicated strategy
508  * routine.  The label must be partly set up before this: secpercyl and
509  * anything required in the strategy routine (e.g., sector size) must be
510  * filled in before calling us.  Returns null on success and an error
511  * string on failure.
512  *
513  * This will read sector zero.  If this contains what looks like a valid
514  * Macintosh boot sector, we attempt to fill in the disklabel structure.
515  * If the first longword of the disk is a NetBSD disk label magic number,
516  * then we assume that it's a real disklabel and return it.
517  */
518 char *
519 readdisklabel(dev, strat, lp, osdep)
520 	dev_t dev;
521 	void (*strat)(struct buf *);
522 	struct disklabel *lp;
523 	struct cpu_disklabel *osdep;
524 {
525 	struct buf *bp;
526 	char *msg = NULL;
527 
528 	if (lp->d_secperunit == 0)
529 		lp->d_secperunit = 0x1fffffff;
530 
531 	if (lp->d_secpercyl == 0) {
532 		return msg = "Zero secpercyl";
533 	}
534 	bp = geteblk((int)lp->d_secsize);
535 
536 	bp->b_dev = dev;
537 	bp->b_blkno = 0;
538 	bp->b_resid = 0;
539 	bp->b_bcount = lp->d_secsize;
540 	bp->b_flags |= B_READ;
541 	bp->b_cylinder = 1 / lp->d_secpercyl;
542 	(*strat)(bp);
543 
544 	osdep->cd_start = -1;
545 
546 	if (biowait(bp))
547 		msg = "I/O error reading block zero";
548 	else if (get_netbsd_label(dev, strat, lp, 0))
549 		osdep->cd_start = 0;
550 	else {
551 		u_int16_t *sbSigp;
552 
553 		sbSigp = (u_int16_t *)bp->b_data;
554 		if (*sbSigp == 0x4552) {
555 			msg = read_mac_label(dev, strat, lp, osdep);
556 		} else if (bswap16(*(u_int16_t *)(bp->b_data + MBR_MAGICOFF))
557 			   == MBR_MAGIC) {
558 			msg = read_dos_label(dev, strat, lp, osdep);
559 		} else {
560 			msg = "no disk label -- NetBSD or Macintosh";
561 			osdep->cd_start = 0;	/* XXX for now */
562 		}
563 	}
564 
565 	brelse(bp);
566 	return (msg);
567 }
568 
569 /*
570  * Check new disk label for sensibility before setting it.
571  */
572 int
573 setdisklabel(olp, nlp, openmask, osdep)
574 	struct disklabel *olp, *nlp;
575 	u_long openmask;
576 	struct cpu_disklabel *osdep;
577 {
578 	/* sanity clause */
579 	if (nlp->d_secpercyl == 0 || nlp->d_secsize == 0
580 	    || (nlp->d_secsize % DEV_BSIZE) != 0)
581 		return EINVAL;
582 
583 	/* special case to allow disklabel to be invalidated */
584 	if (nlp->d_magic == 0xffffffff) {
585 		*olp = *nlp;
586 		return 0;
587 	}
588 
589 	if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC
590 	    || dkcksum(nlp) != 0)
591 		return EINVAL;
592 
593 	/* openmask parameter ignored */
594 
595 	*olp = *nlp;
596 	return 0;
597 }
598 
599 /*
600  * Write disk label back to device after modification.
601  */
602 int
603 writedisklabel(dev, strat, lp, osdep)
604 	dev_t dev;
605 	void (*strat)(struct buf *);
606 	struct disklabel *lp;
607 	struct cpu_disklabel *osdep;
608 {
609 	struct buf *bp;
610 	int error;
611 	struct disklabel label;
612 
613 	/*
614 	 * Try to re-read a disklabel, in case he changed the MBR.
615 	 */
616 	label = *lp;
617 	readdisklabel(dev, strat, &label, osdep);
618 	if (osdep->cd_start < 0)
619 		return EINVAL;
620 
621 	/* get a buffer and initialize it */
622 	bp = geteblk(lp->d_secsize);
623 	bp->b_dev = dev;
624 
625 	bp->b_blkno = osdep->cd_start + LABELSECTOR;
626 	bp->b_cylinder = bp->b_blkno / (lp->d_secsize / DEV_BSIZE) / lp->d_secpercyl;
627 	bp->b_bcount = lp->d_secsize;
628 
629 	bp->b_flags |= B_READ;
630 	(*strat)(bp);
631 	error = biowait(bp);
632 	if (error != 0)
633 		goto done;
634 
635 	bp->b_flags &= ~(B_READ|B_DONE);
636 	bp->b_flags |= B_WRITE;
637 
638 	memcpy((caddr_t)bp->b_data + LABELOFFSET, (caddr_t)lp, sizeof *lp);
639 
640 	(*strat)(bp);
641 	error = biowait(bp);
642 
643 done:
644 	brelse(bp);
645 
646 	return error;
647 }
648 
649 /*
650  * Determine the size of the transfer, and make sure it is
651  * within the boundaris of the partition.  Adjust transfer
652  * if needed, and signal errors or early completion.
653  */
654 int
655 bounds_check_with_label(bp, lp, wlabel)
656 	struct buf *bp;
657 	struct disklabel *lp;
658 	int wlabel;
659 {
660 	struct partition *p = lp->d_partitions + DISKPART(bp->b_dev);
661 	int sz;
662 
663 	sz = howmany(bp->b_bcount, lp->d_secsize);
664 
665 	if (bp->b_blkno + sz > p->p_size) {
666 		sz = p->p_size - bp->b_blkno;
667 		if (sz == 0) {
668 			/* If axactly at end of disk, return EOF. */
669 			bp->b_resid = bp->b_bcount;
670 			goto done;
671 		}
672 		if (sz < 0) {
673 			/* If past end of disk, return EINVAL. */
674 			bp->b_error = EINVAL;
675 			goto bad;
676 		}
677 		/* Otherwise truncate request. */
678 		bp->b_bcount = sz * lp->d_secsize;
679 	}
680 
681 	/* calculate cylinder for disksort to order transfers with */
682 	bp->b_cylinder = (bp->b_blkno + p->p_offset)
683 			 / (lp->d_secsize / DEV_BSIZE) / lp->d_secpercyl;
684 
685 	return 1;
686 
687 bad:
688 	bp->b_flags |= B_ERROR;
689 done:
690 	return 0;
691 }
692