xref: /netbsd/sys/arch/mac68k/mac68k/disksubr.c (revision 99259f25)
1 /*	$NetBSD: disksubr.c,v 1.58 2019/04/03 22:10:50 christos 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  * Copyright (C) 1993	Allen K. Briggs, Chris P. Caputo,
35  *			Michael L. Finch, Bradley A. Grantham, and
36  *			Lawrence A. Kesteloot
37  * All rights reserved.
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions
41  * are met:
42  * 1. Redistributions of source code must retain the above copyright
43  *    notice, this list of conditions and the following disclaimer.
44  * 2. Redistributions in binary form must reproduce the above copyright
45  *    notice, this list of conditions and the following disclaimer in the
46  *    documentation and/or other materials provided with the distribution.
47  * 3. All advertising materials mentioning features or use of this software
48  *    must display the following acknowledgement:
49  *	This product includes software developed by the Alice Group.
50  * 4. The names of the Alice Group or any of its members may not be used
51  *    to endorse or promote products derived from this software without
52  *    specific prior written permission.
53  *
54  * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``AS IS'' AND ANY EXPRESS OR
55  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
56  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
57  * IN NO EVENT SHALL THE ALICE GROUP BE LIABLE FOR ANY DIRECT, INDIRECT,
58  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
59  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
60  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
61  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
62  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
63  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64  *
65  */
66 
67 #include <sys/cdefs.h>
68 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.58 2019/04/03 22:10:50 christos Exp $");
69 
70 #include <sys/param.h>
71 #include <sys/systm.h>
72 #include <sys/buf.h>
73 #include <sys/disk.h>
74 #include <sys/disklabel.h>
75 #include <sys/bootblock.h>
76 #include <sys/syslog.h>
77 
78 #include <sys/bswap.h>
79 
80 #define NUM_PARTS 32
81 
82 #define ROOT_PART 1
83 #define UFS_PART 2
84 #define SWAP_PART 3
85 #define HFS_PART 4
86 #define SCRATCH_PART 5
87 
88 int fat_types[] = {
89 	MBR_PTYPE_FAT12, MBR_PTYPE_FAT16S,
90 	MBR_PTYPE_FAT16B, MBR_PTYPE_FAT32,
91 	MBR_PTYPE_FAT32L, MBR_PTYPE_FAT16L,
92 	-1
93 };
94 
95 static int getFreeLabelEntry(struct disklabel *);
96 static int whichType(struct part_map_entry *);
97 static void setpartition(struct part_map_entry *, struct partition *, int);
98 static int getNamedType(struct part_map_entry *, int, struct disklabel *, int,
99 	    int, int *);
100 static char *read_mac_label(char *, struct disklabel *, int *);
101 static char *read_mbr_label(char *, struct disklabel *, int *);
102 static const char *read_bsd_label(char *, struct disklabel *, int *);
103 
104 
105 /*
106  * Find an entry in the disk label that is unused and return it
107  * or -1 if no entry
108  */
109 static int
getFreeLabelEntry(struct disklabel * lp)110 getFreeLabelEntry(struct disklabel *lp)
111 {
112 	int i;
113 
114 	for (i = 0; i < MAXPARTITIONS; i++) {
115 		if ((i != RAW_PART)
116 		    && (lp->d_partitions[i].p_fstype == FS_UNUSED))
117 			return i;
118 	}
119 	return -1;
120 }
121 
122 /*
123  * figure out what the type of the given part is and return it
124  */
125 static int
whichType(struct part_map_entry * part)126 whichType(struct part_map_entry *part)
127 {
128 	struct blockzeroblock *bzb;
129 	char typestr[32], *s;
130 	int type;
131 
132 	if (part->pmSig != PART_ENTRY_MAGIC || part->pmPartType[0] == '\0')
133 		return 0;
134 
135 	strncpy(typestr, (char *)part->pmPartType, sizeof(typestr));
136 	typestr[sizeof(typestr) - 1] = '\0';
137 	for (s = typestr; *s; s++)
138 		if ((*s >= 'a') && (*s <= 'z'))
139 			*s = (*s - 'a' + 'A');
140 
141 	if (strcmp(PART_TYPE_DRIVER, typestr) == 0 ||
142 	    strcmp(PART_TYPE_DRIVER43, typestr) == 0 ||
143 	    strcmp(PART_TYPE_DRIVERATA, typestr) == 0 ||
144 	    strcmp(PART_TYPE_FWB_COMPONENT, typestr) == 0 ||
145 	    strcmp(PART_TYPE_PARTMAP, typestr) == 0)
146 		type = 0;
147 	else if (strcmp(PART_TYPE_UNIX, typestr) == 0) {
148 		/* unix part, swap, root, usr */
149 		bzb = (struct blockzeroblock *)(&part->pmBootArgs);
150 		if (bzb->bzbMagic != BZB_MAGIC)
151 			type = 0;
152 		else if (bzb->bzbFlags & BZB_ROOTFS)
153 			type = ROOT_PART;
154 		else if (bzb->bzbFlags & BZB_USRFS)
155 			type = UFS_PART;
156 		else if (bzb->bzbType == BZB_TYPESWAP)
157 			type = SWAP_PART;
158 		else
159 			type = SCRATCH_PART;
160 	} else if (strcmp(PART_TYPE_MAC, typestr) == 0)
161 		type = HFS_PART;
162 	else
163 		type = SCRATCH_PART;	/* no known type */
164 
165 	return type;
166 }
167 
168 static void
setpartition(struct part_map_entry * part,struct partition * pp,int fstype)169 setpartition(struct part_map_entry *part, struct partition *pp, int fstype)
170 {
171 	pp->p_size = part->pmPartBlkCnt;
172 	pp->p_offset = part->pmPyPartStart;
173 	pp->p_fstype = fstype;
174 
175 	part->pmPartType[0] = '\0';
176 }
177 
178 static int
getNamedType(struct part_map_entry * part,int num_parts,struct disklabel * lp,int type,int alt,int * maxslot)179 getNamedType(struct part_map_entry *part, int num_parts, struct disklabel *lp,
180     int type, int alt, int *maxslot)
181 {
182 	struct blockzeroblock *bzb;
183 	int i;
184 
185 	for (i = 0; i < num_parts; i++) {
186 		if (whichType(part + i) != type)
187 			continue;
188 
189 		if (type == ROOT_PART) {
190 			bzb = (struct blockzeroblock *)
191 			    (&(part + i)->pmBootArgs);
192 			if (alt >= 0 && alt != bzb->bzbCluster)
193 				continue;
194 			setpartition(part + i, &lp->d_partitions[0], FS_BSDFFS);
195 		} else if (type == UFS_PART) {
196 			bzb = (struct blockzeroblock *)
197 			    (&(part + i)->pmBootArgs);
198 			if (alt >= 0 && alt != bzb->bzbCluster)
199 				continue;
200 			setpartition(part + i, &lp->d_partitions[6], FS_BSDFFS);
201 			if (*maxslot < 6)
202 				*maxslot = 6;
203 		} else if (type == SWAP_PART) {
204 			setpartition(part + i, &lp->d_partitions[1], FS_SWAP);
205 			if (*maxslot < 1)
206 				*maxslot = 1;
207 		} else
208 			printf("disksubr.c: can't do type %d\n", type);
209 
210 		return 0;
211 	}
212 
213 	return -1;
214 }
215 
216 /*
217  * MF --
218  * here's what i'm gonna do:
219  * read in the entire diskpartition table, it may be bigger or smaller
220  * than NUM_PARTS but read that many entries.  Each entry has a magic
221  * number so we'll know if an entry is crap.
222  * next fill in the disklabel with info like this
223  * next fill in the root, usr, and swap parts.
224  * then look for anything else and fit it in.
225  *	A: root
226  *	B: Swap
227  *	C: Whole disk
228  *	G: Usr
229  *
230  *
231  * I'm not entirely sure what netbsd386 wants in c & d
232  * 386bsd wants other stuff, so i'll leave them alone
233  *
234  * AKB -- I added to Mike's original algorithm by searching for a bzbCluster
235  *	of zero for root, first.  This allows A/UX to live on cluster 1 and
236  *	NetBSD to live on cluster 0--regardless of the actual order on the
237  *	disk.  This whole algorithm should probably be changed in the future.
238  */
239 
240 /*
241  * This uses sector zero.  If this contains what looks like a valid
242  * Macintosh boot sector, we attempt to fill in the disklabel structure
243  * with the partition data from block #1 on.
244  */
245 static char *
read_mac_label(char * dlbuf,struct disklabel * lp,int * match)246 read_mac_label(char *dlbuf, struct disklabel *lp, int *match)
247 {
248 	u_int16_t *sbSigp;
249 	struct part_map_entry *part;
250 	struct partition *pp;
251 	char *msg;
252 	int i, slot, maxslot;
253 
254 	maxslot = 0;
255 	*match = 0;
256 	msg = NULL;
257 
258 	sbSigp = (u_int16_t *)dlbuf;
259 	if (*sbSigp != DRIVER_MAP_MAGIC)
260 		return msg;
261 
262 	/* Found Macintosh partition magic number; set up disklabel */
263 	*match = (-1);
264 
265 	/* the Macintosh partition table starts at sector #1 */
266 	part = (struct part_map_entry *)(dlbuf + DEV_BSIZE);
267 
268 	/* Fill in standard partitions */
269 	lp->d_npartitions = RAW_PART + 1;
270 	if (getNamedType(part, NUM_PARTS, lp, ROOT_PART, 0, &maxslot))
271 		getNamedType(part, NUM_PARTS, lp, ROOT_PART, -1, &maxslot);
272 	if (getNamedType(part, NUM_PARTS, lp, UFS_PART, 0, &maxslot))
273 		getNamedType(part, NUM_PARTS, lp, UFS_PART, -1, &maxslot);
274 	getNamedType(part, NUM_PARTS, lp, SWAP_PART, -1, &maxslot);
275 
276 	/* Now get as many of the rest of the partitions as we can */
277 	for (i = 0; i < NUM_PARTS; i++) {
278 		slot = getFreeLabelEntry(lp);
279 		if (slot < 0)
280 			break;
281 
282 		pp = &lp->d_partitions[slot];
283 
284 		switch (whichType(part + i)) {
285 		case ROOT_PART:
286 		/*
287 		 * another root part will turn into a plain old
288 		 * UFS_PART partition, live with it.
289 		 */
290 		case UFS_PART:
291 			setpartition(part + i, pp, FS_BSDFFS);
292 			break;
293 		case SWAP_PART:
294 			setpartition(part + i, pp, FS_SWAP);
295 			break;
296 		case HFS_PART:
297 			setpartition(part + i, pp, FS_HFS);
298 			break;
299 		case SCRATCH_PART:
300 			setpartition(part + i, pp, FS_OTHER);
301 			break;
302 		default:
303 			slot = 0;
304 			break;
305 		}
306 		if (slot > maxslot)
307 			maxslot = slot;
308 	}
309 	lp->d_npartitions = ((maxslot >= RAW_PART) ? maxslot : RAW_PART) + 1;
310 	return msg;
311 }
312 
313 /*
314  * Scan the disk buffer for a DOS style master boot record.
315  * Return if no match; otherwise, set up an in-core disklabel .
316  *
317  * XXX stuff like this really should be MI
318  *
319  * Since FFS is endian sensitive, we pay no effort in attempting to
320  * dig up *BSD/i386 disk labels that may be present on the disk.
321  * Hence anything but DOS partitions is treated as unknown FS type, but
322  * this should suffice to mount_msdos Zip and other removable media.
323  */
324 static char *
read_mbr_label(char * dlbuf,struct disklabel * lp,int * match)325 read_mbr_label(char *dlbuf, struct disklabel *lp, int *match)
326 {
327 	struct mbr_partition *dp;
328 	struct partition *pp;
329 	char *msg;
330 	size_t mbr_lbl_off;
331 	int i, *ip, slot, maxslot;
332 
333 	maxslot = 0;
334 	*match = 0;
335 	msg = NULL;
336 
337 	if (MBR_MAGIC != bswap16(*(u_int16_t *)(dlbuf + MBR_MAGIC_OFFSET)))
338 		return msg;
339 
340 	/* Found MBR magic number; set up disklabel */
341 	*match = (-1);
342 	mbr_lbl_off = MBR_BBSECTOR * lp->d_secsize + MBR_PART_OFFSET;
343 
344 	dp = (struct mbr_partition *)(dlbuf + mbr_lbl_off);
345 	for (i = 0; i < MBR_PART_COUNT; i++, dp++) {
346 		if (dp->mbrp_type == 0)
347 			continue;
348 
349 		slot = getFreeLabelEntry(lp);
350 		maxslot = (slot > maxslot) ? maxslot : slot;
351 
352 		pp = &lp->d_partitions[slot];
353 		pp->p_fstype = FS_OTHER;
354 		pp->p_offset = bswap32(dp->mbrp_start);
355 		pp->p_size = bswap32(dp->mbrp_size);
356 
357 		for (ip = fat_types; *ip != -1; ip++) {
358 			if (dp->mbrp_type == *ip) {
359 				pp->p_fstype = FS_MSDOS;
360 				break;
361 			}
362 		}
363 	}
364 	lp->d_npartitions = ((maxslot >= RAW_PART) ? maxslot : RAW_PART) + 1;
365 	return msg;
366 }
367 
368 /*
369  * Scan the disk buffer in four byte steps for a native BSD disklabel
370  * (different ports have variable-sized bootcode before the label)
371  */
372 static const char *
read_bsd_label(char * dlbuf,struct disklabel * lp,int * match)373 read_bsd_label(char *dlbuf, struct disklabel *lp, int *match)
374 {
375 	struct disklabel *dlp;
376 	const char *msg;
377 	struct disklabel *blk_start, *blk_end;
378 
379 	*match = 0;
380 	msg = NULL;
381 
382 	blk_start = (struct disklabel *)dlbuf;
383 	blk_end = (struct disklabel *)(dlbuf + (NUM_PARTS << DEV_BSHIFT) -
384 	    sizeof(struct disklabel));
385 
386 	for (dlp = blk_start; dlp <= blk_end;
387 	     dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
388 		if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC) {
389 			/* Sanity check */
390 			if (dlp->d_npartitions <= MAXPARTITIONS &&
391 			    dkcksum(dlp) == 0) {
392 				*lp = *dlp;
393 				*match = (-1);
394 			} else
395 				msg = "Disk label corrupted";
396 			break;
397 		}
398 	}
399 	return msg;
400 }
401 
402 /*
403  * Attempt to read a disk label from a device using the indicated strategy
404  * routine.  The label must be partly set up before this: secpercyl and
405  * anything required in the strategy routine (e.g., sector size) must be
406  * filled in before calling us.  Returns null on success and an error
407  * string on failure.
408  */
409 const char *
readdisklabel(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * osdep)410 readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
411     struct cpu_disklabel *osdep)
412 {
413 	struct buf *bp;
414 	const char *msg;
415 	int size;
416 
417 	if (lp->d_secperunit == 0)
418 		lp->d_secperunit = 0x1fffffff;
419 
420 	if (lp->d_secpercyl == 0)
421 		return msg = "Zero secpercyl";
422 
423 	msg = NULL;
424 
425 	/*
426 	 * Read in the first #(NUM_PARTS + 1) blocks of the disk.
427 	 * The native Macintosh partition table starts at
428 	 * sector #1, but we want #0 too for the BSD label.
429 	 */
430 
431 	size = roundup((NUM_PARTS + 1) << DEV_BSHIFT, lp->d_secsize);
432 	bp = geteblk(size);
433 
434 	bp->b_dev = dev;
435 	bp->b_blkno = 0;
436 	bp->b_resid = 0;
437 	bp->b_bcount = size;
438 	bp->b_flags |= B_READ;
439 	bp->b_cylinder = 1 / lp->d_secpercyl;
440 	(*strat)(bp);
441 
442 	if (biowait(bp)) {
443 		msg = "I/O error reading block zero";
444 	} else {
445 		int match;
446 
447 		/* Add any offsets in the table handlers */
448 		msg = read_mac_label(bp->b_data, lp, &match);
449 		if (!match && msg == NULL)
450 			msg = read_mbr_label(bp->b_data, lp, &match);
451 		if (!match && msg == NULL)
452 			msg = read_bsd_label(bp->b_data, lp, &match);
453 		if (!match && msg == NULL)
454 			msg = "no disk label";
455 	}
456 
457 	brelse(bp, 0);
458 	return (msg);
459 }
460 
461 /*
462  * Check new disk label for sensibility before setting it.
463  */
464 int
setdisklabel(struct disklabel * olp,struct disklabel * nlp,u_long openmask,struct cpu_disklabel * osdep)465 setdisklabel(struct disklabel *olp, struct disklabel *nlp, u_long openmask,
466     struct cpu_disklabel *osdep)
467 {
468 	return 0;
469 }
470 
471 /*
472  * Write disk label back to device after modification.
473  *
474  *  MF - 8-14-93 This function is never called.  It is here just in case
475  *  we want to write dos disklabels some day. Really!
476  */
477 int
writedisklabel(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * osdep)478 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
479     struct cpu_disklabel *osdep)
480 {
481 #if 0
482 	struct buf *bp;
483 	struct disklabel *dlp;
484 	int labelpart;
485 	int error = 0;
486 
487 	labelpart = DISKPART(dev);
488 	if (lp->d_partitions[labelpart].p_offset != 0) {
489 		if (lp->d_partitions[0].p_offset != 0)
490 			return (EXDEV);	/* not quite right */
491 		labelpart = 0;
492 	}
493 	bp = geteblk((int)lp->d_secsize);
494 	bp->b_dev = MAKEDISKDEV(major(dev), DISKUNIT(dev), labelpart);
495 	bp->b_blkno = LABELSECTOR;
496 	bp->b_bcount = lp->d_secsize;
497 	bp->b_flags |= B_READ;
498 	(*strat)(bp);
499 	if (error = biowait(bp))
500 		goto done;
501 	for (dlp = (struct disklabel *)bp->b_data;
502 	    dlp <= (struct disklabel *)
503 	    ((char *)bp->b_data + lp->d_secsize - sizeof(*dlp));
504 	    dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
505 		if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC &&
506 		    dkcksum(dlp) == 0) {
507 			*dlp = *lp;
508 			bp->b_oflags &= ~(BO_DONE);
509 			bp->b_flags &= ~(B_READ);
510 			bp->b_flags |= B_WRITE;
511 			(*strat)(bp);
512 			error = biowait(bp);
513 			goto done;
514 		}
515 	}
516 	error = ESRCH;
517 done:
518 	brelse(bp, 0);
519 	return (error);
520 #else
521 	int i;
522 
523 	/*
524 	 * Clear and re-analyze the ondisk Apple Disk Partition Map,
525 	 * then recompute the faked incore disk label. This is necessary
526 	 * for sysinst, which may have modified the disk layout. We don't
527 	 * (yet?) support writing real BSD disk labels, so this hack
528 	 * instead causes the DIOCWDINFO ioctl invoked by sysinst to
529 	 * update the in-core disk label when it is "written" to disk.
530 	 * This code was originally developed by Bob Nestor on 9/13/99.
531 	 */
532 	lp->d_npartitions = 0;
533 	for (i = 0; i < MAXPARTITIONS; i++) {
534 		lp->d_partitions[i].p_fstype = FS_UNUSED;
535 		lp->d_partitions[i].p_offset = 0;
536 		if (i != RAW_PART)
537 			lp->d_partitions[i].p_size = 0;
538 	}
539 	return (readdisklabel(dev, strat, lp, osdep) ? EINVAL : 0);
540 #endif
541 }
542