xref: /netbsd/sys/arch/macppc/macppc/disksubr.c (revision c4a72b64)
1 /*	$NetBSD: disksubr.c,v 1.25 2002/09/28 01:17:10 dbj 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 static int getFreeLabelEntry __P((struct disklabel *));
131 static int whichType __P((struct part_map_entry *, u_int8_t *, int *));
132 static void setpartition __P((struct part_map_entry *,
133 		struct partition *, int));
134 static int getNamedType __P((struct part_map_entry *, int,
135 		struct disklabel *, int, int, int *));
136 static char *read_mac_label __P((dev_t, void (*)(struct buf *),
137 		struct disklabel *, struct cpu_disklabel *));
138 static char *read_dos_label __P((dev_t, void (*)(struct buf *),
139 		struct disklabel *, struct cpu_disklabel *));
140 static int get_netbsd_label __P((dev_t, void (*)(struct buf *),
141 		struct disklabel *, struct cpu_disklabel *));
142 
143 /*
144  * Find an entry in the disk label that is unused and return it
145  * or -1 if no entry
146  */
147 static int
148 getFreeLabelEntry(lp)
149 	struct disklabel *lp;
150 {
151 	int i = 0;
152 
153 	for (i = 0; i < MAXPARTITIONS; i++) {
154 		if ((i != RAW_PART)
155 		    && (lp->d_partitions[i].p_fstype == FS_UNUSED))
156 			return i;
157 	}
158 
159 	return -1;
160 }
161 
162 /*
163  * figure out what the type of the given part is and return it
164  */
165 static int
166 whichType(struct part_map_entry *part, u_int8_t *fstype, int *clust)
167 {
168 	struct blockzeroblock *bzb;
169 	char typestr[32], *s;
170 	int type;
171 
172 	/* Set default unix partition type. Certain partition types can
173 	 * specify a different partition type. */
174 	*fstype = FS_OTHER;
175 	*clust = 0;	/* only A/UX partitions not in cluster 0 */
176 
177 	if (part->pmSig != PART_ENTRY_MAGIC || part->pmPartType[0] == '\0')
178 		return 0;
179 
180 	strncpy(typestr, (char *)part->pmPartType, sizeof(typestr));
181 	typestr[sizeof(typestr) - 1] = '\0';
182 	for (s = typestr; *s; s++)
183 		if ((*s >= 'a') && (*s <= 'z'))
184 			*s = (*s - 'a' + 'A');
185 
186 	if (strncmp(PART_TYPE_DRIVER, typestr, strlen(PART_TYPE_DRIVER)) == 0 ||
187 	    strcmp(PART_TYPE_DRIVER43, typestr) == 0 ||
188 	    strcmp(PART_TYPE_DRIVERATA, typestr) == 0 ||
189 	    strcmp(PART_TYPE_DRIVERIOKIT, typestr) == 0 ||
190 	    strcmp(PART_TYPE_FWDRIVER, typestr) == 0 ||
191 	    strcmp(PART_TYPE_FWB_COMPONENT, typestr) == 0 ||
192 	    strcmp(PART_TYPE_PARTMAP, typestr) == 0 ||
193 	    strcmp(PART_TYPE_PATCHES, typestr) == 0)
194 		type = 0;
195 	else if (strcmp(PART_TYPE_NBSD_PPCBOOT, typestr) == 0) {
196 		type = ROOT_PART;
197 		bzb = (struct blockzeroblock *)(&part->pmBootArgs);
198 		if ((bzb->bzbMagic == BZB_MAGIC) &&
199 		    (bzb->bzbType < FSMAXTYPES))
200 			*fstype = bzb->bzbType;
201 		else
202 			*fstype = FS_BSDFFS;
203 	} else if (strcmp(PART_TYPE_NETBSD, typestr) == 0 ||
204 		 strcmp(PART_TYPE_NBSD_68KBOOT, typestr) == 0) {
205 		type = UFS_PART;
206 		bzb = (struct blockzeroblock *)(&part->pmBootArgs);
207 		if ((bzb->bzbMagic == BZB_MAGIC) &&
208 		    (bzb->bzbType < FSMAXTYPES))
209 			*fstype = bzb->bzbType;
210 		else
211 			*fstype = FS_BSDFFS;
212 	} else if (strcmp(PART_TYPE_UNIX, typestr) == 0) {
213 		/* unix part, swap, root, usr */
214 		bzb = (struct blockzeroblock *)(&part->pmBootArgs);
215 		*clust = bzb->bzbCluster;
216 		if (bzb->bzbMagic != BZB_MAGIC) {
217 			type = 0;
218 		} else if (bzb->bzbFlags & BZB_ROOTFS) {
219 			type = ROOT_PART;
220 			*fstype = FS_BSDFFS;
221 		} else if (bzb->bzbFlags & (BZB_USRFS | BZB_USRFS_NEW)) {
222 			type = UFS_PART;
223 			*fstype = FS_BSDFFS;
224 		} else if (bzb->bzbType == BZB_TYPESWAP) {
225 			type = SWAP_PART;
226 			*fstype = FS_SWAP;
227 		} else {
228 			type = SCRATCH_PART;
229 			*fstype = FS_OTHER;
230 		}
231 	} else if (strcmp(PART_TYPE_MAC, typestr) == 0) {
232 		type = HFS_PART;
233 		*fstype = FS_HFS;
234 	} else if (strcmp(PART_TYPE_APPLEUFS, typestr) == 0) {
235 		type = SCRATCH_PART;
236 		*fstype = FS_APPLEUFS;
237 	} else if (strcmp(PART_TYPE_LINUX, typestr) == 0) {
238 		type = SCRATCH_PART;
239 		*fstype = FS_OTHER;
240 	} else if (strcmp(PART_TYPE_LINUX_SWAP, typestr) == 0) {
241 		type = SCRATCH_PART;
242 		*fstype = FS_OTHER;
243 	} else {
244 		type = SCRATCH_PART;	/* no known type */
245 		*fstype = FS_OTHER;
246 	}
247 
248 	return type;
249 }
250 
251 static void
252 setpartition(struct part_map_entry *part, struct partition *pp, int fstype)
253 {
254 	pp->p_size = part->pmPartBlkCnt;
255 	pp->p_offset = part->pmPyPartStart;
256 	pp->p_fstype = fstype;
257 
258 	part->pmPartType[0] = '\0';
259 }
260 
261 static int
262 getNamedType(part, num_parts, lp, type, alt, maxslot)
263 	struct part_map_entry *part;
264 	int num_parts;
265 	struct disklabel *lp;
266 	int type, alt;
267 	int *maxslot;
268 {
269 	struct blockzeroblock *bzb;
270 	int i = 0, clust;
271 	u_int8_t realtype;
272 
273 	for (i = 0; i < num_parts; i++) {
274 		if (whichType(part + i, &realtype, &clust) != type)
275 			continue;
276 
277 		if (type == ROOT_PART) {
278 			bzb = (struct blockzeroblock *)
279 			    (&(part + i)->pmBootArgs);
280 			if (alt >= 0 && alt != clust)
281 				continue;
282 			setpartition(part + i, &lp->d_partitions[0], realtype);
283 		} else if (type == UFS_PART) {
284 			bzb = (struct blockzeroblock *)
285 			    (&(part + i)->pmBootArgs);
286 			if (alt >= 0 && alt != clust)
287 				continue;
288 			setpartition(part + i, &lp->d_partitions[6], realtype);
289 			if (*maxslot < 6)
290 				*maxslot = 6;
291 		} else if (type == SWAP_PART) {
292 			setpartition(part + i, &lp->d_partitions[1], realtype);
293 			if (*maxslot < 1)
294 				*maxslot = 1;
295 		} else if (type == HFS_PART) {
296 			setpartition(part + i, &lp->d_partitions[3], realtype);
297 			if (*maxslot < 3)
298 				*maxslot = 3;
299 		} else
300 			printf("disksubr.c: can't do type %d\n", type);
301 
302 		return 0;
303 	}
304 
305 	return -1;
306 }
307 
308 /*
309  * MF --
310  * here's what i'm gonna do:
311  * read in the entire diskpartition table, it may be bigger or smaller
312  * than NUM_PARTS but read that many entries.  Each entry has a magic
313  * number so we'll know if an entry is crap.
314  * next fill in the disklabel with info like this
315  * next fill in the root, usr, and swap parts.
316  * then look for anything else and fit it in.
317  *	A: root
318  *	B: Swap
319  *	C: Whole disk
320  *	G: Usr
321  *
322  *
323  * I'm not entirely sure what netbsd386 wants in c & d
324  * 386bsd wants other stuff, so i'll leave them alone
325  *
326  * AKB -- I added to Mike's original algorithm by searching for a bzbCluster
327  *	of zero for root, first.  This allows A/UX to live on cluster 1 and
328  *	NetBSD to live on cluster 0--regardless of the actual order on the
329  *	disk.  This whole algorithm should probably be changed in the future.
330  */
331 static char *
332 read_mac_label(dev, strat, lp, osdep)
333 	dev_t dev;
334 	void (*strat)(struct buf *);
335 	struct disklabel *lp;
336 	struct cpu_disklabel *osdep;
337 {
338 	struct part_map_entry *part;
339 	struct partition *pp;
340 	struct buf *bp;
341 	char *msg = NULL;
342 	int i, slot, maxslot = 0, clust;
343 	u_int8_t realtype;
344 
345 	/* get buffer and initialize it */
346 	bp = geteblk((int)lp->d_secsize * NUM_PARTS);
347 	bp->b_dev = dev;
348 
349 	/* read partition map */
350 	bp->b_blkno = 1;	/* partition map starts at blk 1 */
351 	bp->b_bcount = lp->d_secsize * NUM_PARTS;
352 	bp->b_flags |= B_READ;
353 	bp->b_cylinder = 1 / lp->d_secpercyl;
354 	(*strat)(bp);
355 
356 	if (biowait(bp)) {
357 		msg = "Macintosh partition map I/O error";
358 		goto done;
359 	}
360 
361 	part = (struct part_map_entry *)bp->b_data;
362 
363 	/* Fill in standard partitions */
364 	lp->d_npartitions = RAW_PART + 1;
365 	if (getNamedType(part, NUM_PARTS, lp, ROOT_PART, 0, &maxslot))
366 		getNamedType(part, NUM_PARTS, lp, ROOT_PART, -1, &maxslot);
367 	if (getNamedType(part, NUM_PARTS, lp, UFS_PART, 0, &maxslot))
368 		getNamedType(part, NUM_PARTS, lp, UFS_PART, -1, &maxslot);
369 	getNamedType(part, NUM_PARTS, lp, SWAP_PART, -1, &maxslot);
370 	getNamedType(part, NUM_PARTS, lp, HFS_PART, -1, &maxslot);
371 
372 	/* Now get as many of the rest of the partitions as we can */
373 	for (i = 0; i < NUM_PARTS; i++) {
374 		slot = getFreeLabelEntry(lp);
375 		if (slot < 0)
376 			break;
377 
378 		pp = &lp->d_partitions[slot];
379 
380 		/*
381 		 * Additional ROOT_PART will turn into a plain old
382 		 * UFS_PART partition, live with it.
383 		 */
384 
385 		if (whichType(part + i, &realtype, &clust)) {
386 			setpartition(part + i, pp, realtype);
387 		} else {
388 			slot = 0;
389 		}
390 		if (slot > maxslot)
391 			maxslot = slot;
392 	}
393 	lp->d_npartitions = ((maxslot >= RAW_PART) ? maxslot : RAW_PART) + 1;
394 
395 done:
396 	brelse(bp);
397 	return msg;
398 }
399 
400 /* Read MS-DOS partition table.
401  *
402  * XXX -
403  * Since FFS is endian sensitive, we pay no effort in attempting to
404  * dig up *BSD/i386 disk labels that may be present on the disk.
405  * Hence anything but DOS partitions is treated as unknown FS type, but
406  * this should suffice to mount_msdos Zip and other removable media.
407  */
408 static char *
409 read_dos_label(dev, strat, lp, osdep)
410 	dev_t dev;
411 	void (*strat)(struct buf *);
412 	struct disklabel *lp;
413 	struct cpu_disklabel *osdep;
414 {
415 	struct mbr_partition *dp;
416 	struct buf *bp;
417 	char *msg = NULL;
418 	int i, slot, maxslot = 0;
419 	u_int32_t bsdpartoff;
420 	struct mbr_partition *bsdp;
421 
422 	/* get a buffer and initialize it */
423 	bp = geteblk((int)lp->d_secsize);
424 	bp->b_dev = dev;
425 
426 	/* read master boot record */
427 	bp->b_blkno = MBR_BBSECTOR;
428 	bp->b_bcount = lp->d_secsize;
429 	bp->b_flags |= B_READ;
430 	bp->b_cylinder = MBR_BBSECTOR / lp->d_secpercyl;
431 	(*strat)(bp);
432 
433 	bsdpartoff = 0;
434 
435 	/* if successful, wander through dos partition table */
436 	if (biowait(bp)) {
437 		msg = "dos partition I/O error";
438 		goto done;
439 	}
440 	/* XXX */
441 	dp = (struct mbr_partition *)(bp->b_data + MBR_PARTOFF);
442 	bsdp = NULL;
443 	for (i = 0; i < NMBRPART; i++, dp++) {
444 		switch (dp->mbrp_typ) {
445 		case MBR_PTYPE_NETBSD:
446 			bsdp = dp;
447 			break;
448 		case MBR_PTYPE_OPENBSD:
449 		case MBR_PTYPE_386BSD:
450 			if (!bsdp)
451 				bsdp = dp;
452 			break;
453 		}
454 	}
455 	if (!bsdp) {
456 		/* generate fake disklabel */
457 		dp = (struct mbr_partition *)(bp->b_data + MBR_PARTOFF);
458 		for (i = 0; i < NMBRPART; i++, dp++) {
459 			if (!dp->mbrp_typ)
460 				continue;
461 			slot = getFreeLabelEntry(lp);
462 			if (slot < 0)
463 				break;
464 			if (slot > maxslot)
465 				maxslot = slot;
466 
467 			lp->d_partitions[slot].p_offset = bswap32(dp->mbrp_start);
468 			lp->d_partitions[slot].p_size = bswap32(dp->mbrp_size);
469 
470 			switch (dp->mbrp_typ) {
471 			case MBR_PTYPE_FAT12:
472 			case MBR_PTYPE_FAT16S:
473 			case MBR_PTYPE_FAT16B:
474 			case MBR_PTYPE_FAT32:
475 			case MBR_PTYPE_FAT32L:
476 			case MBR_PTYPE_FAT16L:
477 				lp->d_partitions[slot].p_fstype = FS_MSDOS;
478 				break;
479 			default:
480 				lp->d_partitions[slot].p_fstype = FS_OTHER;
481 				break;
482 			}
483 		}
484 		msg = "no NetBSD disk label";
485 	} else {
486 		/* NetBSD partition on MBR */
487 		bsdpartoff = bswap32(bsdp->mbrp_start);
488 
489 		lp->d_partitions[2].p_size = bswap32(bsdp->mbrp_size);
490 		lp->d_partitions[2].p_offset = bswap32(bsdp->mbrp_start);
491 		if (2 > maxslot)
492 			maxslot = 2;
493 		/* read in disklabel, blkno + 1 for DOS disklabel offset */
494 		osdep->cd_labelsector = bsdpartoff + MBR_LABELSECTOR;
495 		osdep->cd_labeloffset = MBR_LABELOFFSET;
496 		if (get_netbsd_label(dev, strat, lp, osdep))
497 			goto done;
498 		msg = "no NetBSD disk label";
499 	}
500 
501 	lp->d_npartitions = ((maxslot >= RAW_PART) ? maxslot : RAW_PART) + 1;
502 
503  done:
504 	brelse(bp);
505 	return (msg);
506 }
507 
508 /*
509  * Get real NetBSD disk label
510  */
511 static int
512 get_netbsd_label(dev, strat, lp, osdep)
513 	dev_t dev;
514 	void (*strat)(struct buf *);
515 	struct disklabel *lp;
516 	struct cpu_disklabel *osdep;
517 {
518 	struct buf *bp;
519 	struct disklabel *dlp;
520 
521 	/* get a buffer and initialize it */
522 	bp = geteblk((int)lp->d_secsize);
523 	bp->b_dev = dev;
524 
525 	/* Now get the label block */
526 	bp->b_blkno = osdep->cd_labelsector;
527 	bp->b_bcount = lp->d_secsize;
528 	bp->b_flags |= B_READ;
529 	bp->b_cylinder = bp->b_blkno / (lp->d_secsize / DEV_BSIZE) / lp->d_secpercyl;
530 	(*strat)(bp);
531 
532 	if (biowait(bp))
533 		goto done;
534 
535 	for (dlp = (struct disklabel *)(bp->b_data + osdep->cd_labeloffset);
536 	     dlp <= (struct disklabel *)(bp->b_data + lp->d_secsize - sizeof (*dlp));
537 	     dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
538 		if (dlp->d_magic == DISKMAGIC
539 		    && dlp->d_magic2 == DISKMAGIC
540 		    && dlp->d_npartitions <= MAXPARTITIONS
541 		    && dkcksum(dlp) == 0) {
542 			*lp = *dlp;
543 			osdep->cd_labeloffset = (caddr_t)dlp - bp->b_data;
544 			brelse(bp);
545 			return 1;
546 		}
547 	}
548 done:
549 	brelse(bp);
550 	return 0;
551 }
552 
553 /*
554  * Attempt to read a disk label from a device using the indicated strategy
555  * routine.  The label must be partly set up before this: secpercyl and
556  * anything required in the strategy routine (e.g., sector size) must be
557  * filled in before calling us.  Returns null on success and an error
558  * string on failure.
559  *
560  * This will read sector zero.  If this contains what looks like a valid
561  * Macintosh boot sector, we attempt to fill in the disklabel structure.
562  * If the first longword of the disk is a NetBSD disk label magic number,
563  * then we assume that it's a real disklabel and return it.
564  */
565 char *
566 readdisklabel(dev, strat, lp, osdep)
567 	dev_t dev;
568 	void (*strat)(struct buf *);
569 	struct disklabel *lp;
570 	struct cpu_disklabel *osdep;
571 {
572 	struct buf *bp;
573 	char *msg = NULL;
574 
575 	if (lp->d_secperunit == 0)
576 		lp->d_secperunit = 0x1fffffff;
577 
578 	if (lp->d_secpercyl == 0) {
579 		return msg = "Zero secpercyl";
580 	}
581 	bp = geteblk((int)lp->d_secsize);
582 
583 	bp->b_dev = dev;
584 	bp->b_blkno = 0;
585 	bp->b_resid = 0;
586 	bp->b_bcount = lp->d_secsize;
587 	bp->b_flags |= B_READ;
588 	bp->b_cylinder = 1 / lp->d_secpercyl;
589 	(*strat)(bp);
590 
591 	osdep->cd_start = -1;
592 
593 	/* XXX cd_start is abused as a flag for fictious disklabel */
594 
595 	if (biowait(bp)) {
596 		msg = "I/O error reading block zero";
597 		goto done;
598 	}
599 	osdep->cd_labelsector = LABELSECTOR;
600 	osdep->cd_labeloffset = LABELOFFSET;
601 	if (get_netbsd_label(dev, strat, lp, osdep))
602 		osdep->cd_start = 0;
603 	else {
604 		u_int16_t *sbSigp;
605 
606 		sbSigp = (u_int16_t *)bp->b_data;
607 		if (*sbSigp == 0x4552) {
608 			/* it ignores labelsector/offset */
609 			msg = read_mac_label(dev, strat, lp, osdep);
610 			/* the disklabel is fictious */
611 		} else if (bswap16(*(u_int16_t *)(bp->b_data + MBR_MAGICOFF))
612 			   == MBR_MAGIC) {
613 			/* read_dos_label figures out labelsector/offset */
614 			msg = read_dos_label(dev, strat, lp, osdep);
615 			if (!msg)
616 				osdep->cd_start = 0;
617 		} else {
618 			msg = "no disk label -- NetBSD or Macintosh";
619 			osdep->cd_start = 0;	/* XXX for now */
620 		}
621 	}
622 
623 done:
624 	brelse(bp);
625 	return (msg);
626 }
627 
628 /*
629  * Check new disk label for sensibility before setting it.
630  */
631 int
632 setdisklabel(olp, nlp, openmask, osdep)
633 	struct disklabel *olp, *nlp;
634 	u_long openmask;
635 	struct cpu_disklabel *osdep;
636 {
637 	/* sanity clause */
638 	if (nlp->d_secpercyl == 0 || nlp->d_secsize == 0
639 	    || (nlp->d_secsize % DEV_BSIZE) != 0)
640 		return EINVAL;
641 
642 	/* special case to allow disklabel to be invalidated */
643 	if (nlp->d_magic == 0xffffffff) {
644 		*olp = *nlp;
645 		return 0;
646 	}
647 
648 	if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC
649 	    || dkcksum(nlp) != 0)
650 		return EINVAL;
651 
652 	/* openmask parameter ignored */
653 
654 	*olp = *nlp;
655 	return 0;
656 }
657 
658 /*
659  * Write disk label back to device after modification.
660  */
661 int
662 writedisklabel(dev, strat, lp, osdep)
663 	dev_t dev;
664 	void (*strat)(struct buf *);
665 	struct disklabel *lp;
666 	struct cpu_disklabel *osdep;
667 {
668 	struct buf *bp;
669 	int error;
670 	struct disklabel label;
671 
672 	/*
673 	 * Try to re-read a disklabel, in case he changed the MBR.
674 	 */
675 	label = *lp;
676 	readdisklabel(dev, strat, &label, osdep);
677 	if (osdep->cd_start < 0)
678 		return EINVAL;
679 
680 	/* get a buffer and initialize it */
681 	bp = geteblk(lp->d_secsize);
682 	bp->b_dev = dev;
683 
684 	bp->b_blkno = osdep->cd_start + osdep->cd_labelsector;
685 	bp->b_cylinder = bp->b_blkno / (lp->d_secsize / DEV_BSIZE) / lp->d_secpercyl;
686 	bp->b_bcount = lp->d_secsize;
687 
688 	bp->b_flags |= B_READ;
689 	(*strat)(bp);
690 	error = biowait(bp);
691 	if (error != 0)
692 		goto done;
693 
694 	bp->b_flags &= ~(B_READ|B_DONE);
695 	bp->b_flags |= B_WRITE;
696 
697 	memcpy((caddr_t)bp->b_data + osdep->cd_labeloffset, (caddr_t)lp,
698 	    sizeof *lp);
699 
700 	(*strat)(bp);
701 	error = biowait(bp);
702 
703 done:
704 	brelse(bp);
705 
706 	return error;
707 }
708 
709 /*
710  * Determine the size of the transfer, and make sure it is
711  * within the boundaris of the partition.  Adjust transfer
712  * if needed, and signal errors or early completion.
713  */
714 int
715 bounds_check_with_label(bp, lp, wlabel)
716 	struct buf *bp;
717 	struct disklabel *lp;
718 	int wlabel;
719 {
720 	struct partition *p = lp->d_partitions + DISKPART(bp->b_dev);
721 	int sz;
722 
723 	sz = howmany(bp->b_bcount, lp->d_secsize);
724 
725 	if (bp->b_blkno + sz > p->p_size) {
726 		sz = p->p_size - bp->b_blkno;
727 		if (sz == 0) {
728 			/* If axactly at end of disk, return EOF. */
729 			bp->b_resid = bp->b_bcount;
730 			goto done;
731 		}
732 		if (sz < 0) {
733 			/* If past end of disk, return EINVAL. */
734 			bp->b_error = EINVAL;
735 			goto bad;
736 		}
737 		/* Otherwise truncate request. */
738 		bp->b_bcount = sz * lp->d_secsize;
739 	}
740 
741 	/* calculate cylinder for disksort to order transfers with */
742 	bp->b_cylinder = (bp->b_blkno + p->p_offset)
743 			 / (lp->d_secsize / DEV_BSIZE) / lp->d_secpercyl;
744 
745 	return 1;
746 
747 bad:
748 	bp->b_flags |= B_ERROR;
749 done:
750 	return 0;
751 }
752