xref: /netbsd-src/sys/arch/ofppc/ofppc/disksubr.c (revision cbf785431228562e0b36e84e31ded0290d8b3831)
1 /*	$NetBSD: disksubr.c,v 1.31 2022/07/05 19:31:04 andvar Exp $	*/
2 
3 /*-
4  * Copyright (c) 2010 Frank Wille.
5  * All rights reserved.
6  *
7  * Written by Frank Wille for The NetBSD Project.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 /*
32  * Copyright (c) 1994 Christian E. Hopps
33  *
34  * Redistribution and use in source and binary forms, with or without
35  * modification, are permitted provided that the following conditions
36  * are met:
37  * 1. Redistributions of source code must retain the above copyright
38  *    notice, this list of conditions and the following disclaimer.
39  * 2. Redistributions in binary form must reproduce the above copyright
40  *    notice, this list of conditions and the following disclaimer in the
41  *    documentation and/or other materials provided with the distribution.
42  * 3. All advertising materials mentioning features or use of this software
43  *    must display the following acknowledgement:
44  *	This product includes software developed by the University of
45  *	California, Berkeley and its contributors.
46  * 4. Neither the name of the University nor the names of its contributors
47  *    may be used to endorse or promote products derived from this software
48  *    without specific prior written permission.
49  *
50  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60  * SUCH DAMAGE.
61  *
62  *	@(#)ufs_disksubr.c	7.16 (Berkeley) 5/4/91
63  */
64 
65 #include <sys/cdefs.h>
66 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.31 2022/07/05 19:31:04 andvar Exp $");
67 
68 #include "opt_disksubr.h"
69 
70 #include <sys/buf.h>
71 #include <sys/disklabel.h>
72 #include <sys/bswap.h>
73 
74 /*
75  * In /usr/src/sys/dev/scsipi/sd.c, routine sdstart() adjusts the
76  * block numbers, it changes from DEV_BSIZE units to physical units:
77  * blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE);
78  * As long as media with sector sizes of 512 bytes are used, this
79  * doesn't matter (divide by 1), but for successful usage of media with
80  * greater sector sizes (e.g. 640MB MO-media with 2048 bytes/sector)
81  * we must multiply block numbers with (lp->d_secsize / DEV_BSIZE)
82  * to keep "unchanged" physical block numbers.
83  */
84 #define SD_C_ADJUSTS_NR
85 
86 #define baddr(bp) (void *)((bp)->b_data)
87 
88 static const char *read_dos_label(dev_t, void (*)(struct buf *),
89     struct disklabel *, struct cpu_disklabel *);
90 static int getFreeLabelEntry(struct disklabel *);
91 static int read_netbsd_label(dev_t, void (*)(struct buf *), struct disklabel *,
92     struct cpu_disklabel *);
93 #ifdef RDB_PART
94 static const char *read_rdb_label(dev_t, void (*)(struct buf *),
95     struct disklabel *, struct cpu_disklabel *);
96 static u_long rdbchksum(void *);
97 static struct adostype getadostype(u_long);
98 #endif
99 
100 /*
101  * Read MBR partition table.
102  *
103  * XXX -
104  * Since FFS is endian sensitive, we pay no effort in attempting to
105  * dig up *BSD/i386 disk labels that may be present on the disk.
106  * Hence anything but DOS partitions is treated as unknown FS type, but
107  * this should suffice to mount_msdos Zip and other removable media.
108  */
109 static const char *
read_dos_label(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * osdep)110 read_dos_label(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
111     struct cpu_disklabel *osdep)
112 {
113 	struct buf *bp;
114 	struct mbr_partition *bsdp, *dp;
115 	const char *msg = NULL;
116 	int i, slot, maxslot = 0;
117 	u_int32_t bsdpartoff;
118 
119 	/* get a buffer and initialize it */
120 	bp = geteblk((int)lp->d_secsize);
121 	bp->b_dev = dev;
122 
123 	/* read master boot record */
124 	bp->b_blkno = MBR_BBSECTOR;
125 	bp->b_bcount = lp->d_secsize;
126 	bp->b_flags |= B_READ;
127 	bp->b_cylinder = MBR_BBSECTOR / lp->d_secpercyl;
128 	(*strat)(bp);
129 
130 	bsdpartoff = 0;
131 
132 	/* if successful, wander through dos partition table */
133 	if (biowait(bp)) {
134 		msg = "dos partition I/O error";
135 		goto done;
136 	}
137 	/* XXX */
138 	dp = (struct mbr_partition *)((char *)bp->b_data + MBR_PART_OFFSET);
139 	bsdp = NULL;
140 	for (i = 0; i < MBR_PART_COUNT; i++, dp++) {
141 		switch (dp->mbrp_type) {
142 		case MBR_PTYPE_NETBSD:
143 			bsdp = dp;
144 			break;
145 		case MBR_PTYPE_OPENBSD:
146 		case MBR_PTYPE_386BSD:
147 			if (!bsdp)
148 				bsdp = dp;
149 			break;
150 		}
151 	}
152 	if (!bsdp) {
153 		/* generate fake disklabel */
154 		dp = (struct mbr_partition *)((char *)bp->b_data +
155 		    MBR_PART_OFFSET);
156 		for (i = 0; i < MBR_PART_COUNT; i++, dp++) {
157 			if (!dp->mbrp_type)
158 				continue;
159 			slot = getFreeLabelEntry(lp);
160 			if (slot < 0)
161 				break;
162 			if (slot > maxslot)
163 				maxslot = slot;
164 
165 			lp->d_partitions[slot].p_offset =
166 			    bswap32(dp->mbrp_start);
167 			lp->d_partitions[slot].p_size = bswap32(dp->mbrp_size);
168 
169 			switch (dp->mbrp_type) {
170 			case MBR_PTYPE_FAT12:
171 			case MBR_PTYPE_FAT16S:
172 			case MBR_PTYPE_FAT16B:
173 			case MBR_PTYPE_FAT32:
174 			case MBR_PTYPE_FAT32L:
175 			case MBR_PTYPE_FAT16L:
176 				lp->d_partitions[slot].p_fstype = FS_MSDOS;
177 				break;
178 			default:
179 				lp->d_partitions[slot].p_fstype = FS_OTHER;
180 				break;
181 			}
182 		}
183 		msg = "no NetBSD disk label";
184 	} else {
185 		/* NetBSD partition on MBR */
186 		bsdpartoff = bswap32(bsdp->mbrp_start);
187 
188 		lp->d_partitions[2].p_size = bswap32(bsdp->mbrp_size);
189 		lp->d_partitions[2].p_offset = bswap32(bsdp->mbrp_start);
190 		if (2 > maxslot)
191 			maxslot = 2;
192 		/* read in disklabel, blkno + 1 for DOS disklabel offset */
193 		osdep->cd_labelsector = bsdpartoff + LABELSECTOR;
194 		osdep->cd_labeloffset = LABELOFFSET;
195 		if (read_netbsd_label(dev, strat, lp, osdep))
196 			goto done;
197 		msg = "no NetBSD disk label";
198 	}
199 
200 	lp->d_npartitions = ((maxslot >= RAW_PART) ? maxslot : RAW_PART) + 1;
201 
202 done:
203 	brelse(bp, 0);
204 	return msg;
205 }
206 
207 /*
208  * Find an entry in the disk label that is unused and return it
209  * or -1 if no entry
210  */
211 static int
getFreeLabelEntry(struct disklabel * lp)212 getFreeLabelEntry(struct disklabel *lp)
213 {
214 	int i;
215 
216 	for (i = 0; i < MAXPARTITIONS; i++) {
217 		if ((i != RAW_PART)
218 		    && (lp->d_partitions[i].p_fstype == FS_UNUSED))
219 			return i;
220 	}
221 	return -1;
222 }
223 
224 #ifdef RDB_PART
225 /*
226  * Read an Amiga RDB partition table.
227  */
228 static const char *
read_rdb_label(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * osdep)229 read_rdb_label(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
230     struct cpu_disklabel *osdep)
231 {
232 	struct adostype adt;
233 	struct buf *bp;
234 	struct partition *pp = NULL;
235 	struct partblock *pbp;
236 	struct rdblock *rbp;
237 	const char *msg;
238 	char *bcpls, *s, bcpli;
239 	int cindex, i, nopname;
240 	u_long nextb;
241 
242 	osdep->rdblock = RDBNULL;
243 	lp->d_npartitions = RAW_PART + 1;
244 
245 	if (lp->d_partitions[RAW_PART].p_size == 0)
246 		lp->d_partitions[RAW_PART].p_size = 0x1fffffff;
247 	lp->d_partitions[RAW_PART].p_offset = 0;
248 	/* if no 'a' partition, default is to copy from 'c' as BSDFFS */
249 	if (lp->d_partitions[0].p_size == 0) {
250 		lp->d_partitions[0].p_size = lp->d_partitions[RAW_PART].p_size;
251 		lp->d_partitions[0].p_offset = 0;
252 		lp->d_partitions[0].p_fstype = FS_BSDFFS;
253 		lp->d_partitions[0].p_fsize = 1024;
254 		lp->d_partitions[0].p_frag = 8;
255 		lp->d_partitions[0].p_cpg = 0;
256 	}
257 
258 	/* obtain buffer to probe drive with */
259 	bp = geteblk((int)lp->d_secsize);
260 
261 	/*
262 	 * request no partition relocation by driver on I/O operations
263 	 */
264 #ifdef _KERNEL
265 	bp->b_dev = MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART);
266 #else
267 	bp->b_dev = dev;
268 #endif
269 	msg = NULL;
270 
271 	/*
272 	 * find the RDB block
273 	 */
274 	for (nextb = 0; nextb < RDB_MAXBLOCKS; nextb++) {
275 		bp->b_blkno = nextb;
276 		bp->b_cylinder = bp->b_blkno / lp->d_secpercyl;
277 		bp->b_bcount = lp->d_secsize;
278 		bp->b_oflags &= ~(BO_DONE);
279 		bp->b_flags |= B_READ;
280 #ifdef SD_C_ADJUSTS_NR
281 		bp->b_blkno *= (lp->d_secsize / DEV_BSIZE);
282 #endif
283 		(*strat)(bp);
284 
285 		if (biowait(bp)) {
286 			msg = "rdb scan I/O error";
287 			goto done;
288 		}
289 		rbp = baddr(bp);
290 		if (rbp->id == RDBLOCK_ID) {
291 			if (rdbchksum(rbp) == 0)
292 				break;
293 			else
294 				msg = "rdb bad checksum";
295 		}
296 	}
297 
298 	if (nextb == RDB_MAXBLOCKS) {
299 		if (msg == NULL)
300 			msg = "no disk label";
301 		goto done;
302 	} else if (msg != NULL)
303 		/*
304 		 * maybe we found an invalid one before a valid.
305 		 * clear err.
306 		 */
307 		msg = NULL;
308 
309 	osdep->rdblock = nextb;
310 
311 	/* RDB present, clear disklabel partition table before doing PART blks */
312 	for (i = 0; i < MAXPARTITIONS; i++) {
313 		osdep->pbindex[i] = -1;
314 		osdep->pblist[i] = RDBNULL;
315 		if (i == RAW_PART)
316 			continue;
317 		lp->d_partitions[i].p_size = 0;
318 		lp->d_partitions[i].p_offset = 0;
319 	}
320 
321 	lp->d_secsize = rbp->nbytes;
322 	lp->d_nsectors = rbp->nsectors;
323 	lp->d_ntracks = rbp->nheads;
324 	/*
325 	 * should be rdb->ncylinders however this is a bogus value
326 	 * sometimes it seems
327 	 */
328 	if (rbp->highcyl == 0)
329 		lp->d_ncylinders = rbp->ncylinders;
330 	else
331 		lp->d_ncylinders = rbp->highcyl + 1;
332 	/*
333 	 * I also don't trust rdb->secpercyl
334 	 */
335 	lp->d_secpercyl = uimin(rbp->secpercyl, lp->d_nsectors * lp->d_ntracks);
336 	if (lp->d_secpercyl == 0)
337 		lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
338 #ifdef DIAGNOSTIC
339 	if (lp->d_ncylinders != rbp->ncylinders)
340 		printf("warning found rdb->ncylinders(%u) != "
341 		    "rdb->highcyl(%u) + 1\n", rbp->ncylinders,
342 		    rbp->highcyl);
343 	if (lp->d_nsectors * lp->d_ntracks != rbp->secpercyl)
344 		printf("warning found rdb->secpercyl(%u) != "
345 		    "rdb->nsectors(%u) * rdb->nheads(%u)\n", rbp->secpercyl,
346 		    rbp->nsectors, rbp->nheads);
347 #endif
348 	lp->d_sparespercyl =
349 	    uimax(rbp->secpercyl, lp->d_nsectors * lp->d_ntracks)
350 	    - lp->d_secpercyl;
351 	if (lp->d_sparespercyl == 0)
352 		lp->d_sparespertrack = 0;
353 	else {
354 		lp->d_sparespertrack = lp->d_sparespercyl / lp->d_ntracks;
355 #ifdef DIAGNOSTIC
356 		if (lp->d_sparespercyl % lp->d_ntracks)
357 			printf("warning lp->d_sparespercyl(%u) not multiple "
358 			    "of lp->d_ntracks(%u)\n", lp->d_sparespercyl,
359 			    lp->d_ntracks);
360 #endif
361 	}
362 
363 	lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
364 	lp->d_acylinders = rbp->ncylinders - (rbp->highcyl - rbp->lowcyl + 1);
365 	lp->d_rpm = 3600; 		/* good guess I suppose. */
366 	lp->d_interleave = rbp->interleave;
367 	lp->d_headswitch = lp->d_flags = lp->d_trackskew = lp->d_cylskew = 0;
368 	lp->d_trkseek = /* rbp->steprate */ 0;
369 
370 	/*
371 	 * raw partition gets the entire disk
372 	 */
373 	lp->d_partitions[RAW_PART].p_size = rbp->ncylinders * lp->d_secpercyl;
374 
375 	/*
376 	 * scan for partition blocks
377 	 */
378 	nopname = 1;
379 	cindex = 0;
380 	for (nextb = rbp->partbhead; nextb != RDBNULL; nextb = pbp->next) {
381 		bp->b_blkno = nextb;
382 		bp->b_cylinder = bp->b_blkno / lp->d_secpercyl;
383 		bp->b_bcount = lp->d_secsize;
384 		bp->b_oflags &= ~(BO_DONE);
385 		bp->b_flags |= B_READ;
386 #ifdef SD_C_ADJUSTS_NR
387 		bp->b_blkno *= (lp->d_secsize / DEV_BSIZE);
388 #endif
389 		strat(bp);
390 
391 		if (biowait(bp)) {
392 			msg = "partition scan I/O error";
393 			goto done;
394 		}
395 		pbp = baddr(bp);
396 
397 		if (pbp->id != PARTBLOCK_ID) {
398 			msg = "partition block with bad id";
399 			goto done;
400 		}
401 		if (rdbchksum(pbp)) {
402 			msg = "partition block bad checksum";
403 			goto done;
404 		}
405 
406 		if (pbp->e.tabsize < 11) {
407 			/*
408 			 * not enough info, too funky for us.
409 			 * I don't want to skip I want it fixed.
410 			 */
411 			msg = "bad partition info (environ < 11)";
412 			goto done;
413 		}
414 
415 		/*
416 		 * XXXX should be ">" however some vendors don't know
417 		 * what a table size is so, we hack for them.
418 		 * the other checks can fail for all I care but this
419 		 * is a very common value. *sigh*.
420 		 */
421 		if (pbp->e.tabsize >= 16)
422 			adt = getadostype(pbp->e.dostype);
423 		else {
424 			adt.archtype = ADT_UNKNOWN;
425 			adt.fstype = FS_UNUSED;
426 		}
427 
428 		switch (adt.archtype) {
429 		case ADT_NETBSDROOT:
430 			pp = &lp->d_partitions[0];
431 			if (pp->p_size) {
432 #ifdef DIAGNOSTIC
433 				printf("more than one root, ignoring\n");
434 #endif
435 				osdep->rdblock = RDBNULL; /* invalidate cpulab */
436 				continue;
437 			}
438 			break;
439 		case ADT_NETBSDSWAP:
440 			pp = &lp->d_partitions[1];
441 			if (pp->p_size) {
442 #ifdef DIAGNOSTIC
443 				printf("more than one swap, ignoring\n");
444 #endif
445 				osdep->rdblock = RDBNULL; /* invalidate cpulab */
446 				continue;
447 			}
448 			break;
449 		case ADT_NETBSDUSER:
450 		case ADT_AMIGADOS:
451 		case ADT_AMIX:
452 		case ADT_EXT2:
453 		case ADT_RAID:
454 		case ADT_MSD:
455 		case ADT_UNKNOWN:
456 			pp = &lp->d_partitions[lp->d_npartitions];
457 			break;
458 		}
459 		if (lp->d_npartitions <= (pp - lp->d_partitions))
460 			lp->d_npartitions = (pp - lp->d_partitions) + 1;
461 
462 #ifdef DIAGNOSTIC
463 		if (lp->d_secpercyl * lp->d_secsize !=
464 		    (pbp->e.secpertrk * pbp->e.numheads * pbp->e.sizeblock<<2)) {
465 			if (pbp->partname[0] < sizeof(pbp->partname))
466 				pbp->partname[pbp->partname[0] + 1] = 0;
467 			else
468 				pbp->partname[sizeof(pbp->partname) - 1] = 0;
469 			printf("Partition '%s' geometry %u/%u differs",
470 			    pbp->partname + 1, pbp->e.numheads,
471 			    pbp->e.secpertrk);
472 			printf(" from RDB %u/%u=%u\n", lp->d_ntracks,
473 			    lp->d_nsectors, lp->d_secpercyl);
474 		}
475 #endif
476 		/*
477 		 * insert sort in increasing offset order
478 		 */
479 		while ((pp - lp->d_partitions) > RAW_PART + 1) {
480 			daddr_t boff;
481 
482 			boff = pbp->e.lowcyl * pbp->e.secpertrk
483 			    * pbp->e.numheads;
484 			if (boff > (pp - 1)->p_offset)
485 				break;
486 			*pp = *(pp - 1);	/* struct copy */
487 			pp--;
488 		}
489 		i = (pp - lp->d_partitions);
490 		if (nopname || i == 1) {
491 			/*
492 			 * either we have no packname yet or we found
493 			 * the swap partition. copy BCPL string into packname
494 			 * [the reason we use the swap partition: the user
495 			 *  can supply a decent packname without worry
496 			 *  of having to access an oddly named partition
497 			 *  under AmigaDos]
498 			 */
499 			s = lp->d_packname;
500 			bcpls = &pbp->partname[1];
501 			bcpli = pbp->partname[0];
502 			if (sizeof(lp->d_packname) <= bcpli)
503 				bcpli = sizeof(lp->d_packname) - 1;
504 			while (bcpli--)
505 				*s++ = *bcpls++;
506 			*s = 0;
507 			nopname = 0;
508 		}
509 
510 		pp->p_size = (pbp->e.highcyl - pbp->e.lowcyl + 1)
511 		    * pbp->e.secpertrk * pbp->e.numheads
512 		    * ((pbp->e.sizeblock << 2) / lp->d_secsize);
513 		pp->p_offset = pbp->e.lowcyl * pbp->e.secpertrk
514 		    * pbp->e.numheads
515 		    * ((pbp->e.sizeblock << 2) / lp->d_secsize);
516 		pp->p_fstype = adt.fstype;
517 		if (adt.archtype == ADT_AMIGADOS) {
518 			/*
519 			 * Save reserved blocks at begin in cpg and
520 			 *  adjust size by reserved blocks at end
521 			 */
522 			int bsize, secperblk, minbsize, prefac;
523 
524 			minbsize = uimax(512, lp->d_secsize);
525 
526 			bsize	  = pbp->e.sizeblock << 2;
527 			secperblk = pbp->e.secperblk;
528 			prefac	  = pbp->e.prefac;
529 
530 			while (bsize > minbsize) {
531 				bsize >>= 1;
532 				secperblk <<= 1;
533 				prefac <<= 1;
534 			}
535 
536 			if (bsize == minbsize) {
537 				pp->p_fsize = bsize;
538 				pp->p_frag = secperblk;
539 				pp->p_cpg = pbp->e.resvblocks;
540 				pp->p_size -= prefac;
541 			} else {
542 				adt.archtype = ADT_UNKNOWN;
543 				adt.fstype = FS_UNUSED;
544 			}
545 		} else if (pbp->e.tabsize > 22 && ISFSARCH_NETBSD(adt)) {
546 			pp->p_fsize = pbp->e.fsize;
547 			pp->p_frag = pbp->e.frag;
548 			pp->p_cpg = pbp->e.cpg;
549 		} else {
550 			pp->p_fsize = 1024;
551 			pp->p_frag = 8;
552 			pp->p_cpg = 0;
553 		}
554 
555 		/*
556 		 * store this partitions block number
557 		 */
558 		osdep->pblist[osdep->pbindex[i] = cindex++] = nextb;
559 	}
560 	/*
561 	 * calculate new checksum.
562 	 */
563 	lp->d_magic = lp->d_magic2 = DISKMAGIC;
564 	lp->d_checksum = 0;
565 	lp->d_checksum = dkcksum(lp);
566 	if (osdep->rdblock != RDBNULL)
567 		osdep->valid = 1;
568 done:
569 	if (osdep->valid == 0)
570 		osdep->rdblock = RDBNULL;
571 	brelse(bp, 0);
572 	return msg;
573 }
574 
575 static u_long
rdbchksum(void * bdata)576 rdbchksum(void *bdata)
577 {
578 	u_long *blp, cnt, val;
579 
580 	blp = bdata;
581 	cnt = blp[1];
582 	val = 0;
583 
584 	while (cnt--)
585 		val += *blp++;
586 	return val;
587 }
588 
589 static struct adostype
getadostype(u_long dostype)590 getadostype(u_long dostype)
591 {
592 	struct adostype adt;
593 	u_long b1, t3;
594 
595 	t3 = dostype & 0xffffff00;
596 	b1 = dostype & 0x000000ff;
597 
598 	adt.fstype = b1;
599 
600 	switch (t3) {
601 	case DOST_NBR:
602 		adt.archtype = ADT_NETBSDROOT;
603 		return adt;
604 	case DOST_NBS:
605 		adt.archtype = ADT_NETBSDSWAP;
606 		return adt;
607 	case DOST_NBU:
608 		adt.archtype = ADT_NETBSDUSER;
609 		return adt;
610 	case DOST_MUFS:
611 		/* check for 'muFS'? */
612 		adt.archtype = ADT_AMIGADOS;
613 		adt.fstype = FS_ADOS;
614 		return adt;
615 	case DOST_DOS:
616 		adt.archtype = ADT_AMIGADOS;
617                 if (b1 > 5)
618 			adt.fstype = FS_UNUSED;
619 		else
620 			adt.fstype = FS_ADOS;
621 		return adt;
622 	case DOST_AMIX:
623 		adt.archtype = ADT_AMIX;
624 		if (b1 == 2)
625 			adt.fstype = FS_BSDFFS;
626 		else
627 			adt.fstype = FS_UNUSED;
628 		return adt;
629 	case DOST_XXXBSD:
630 #ifdef DIAGNOSTIC
631 		printf("found dostype: 0x%lx which is deprecated", dostype);
632 #endif
633 		if (b1 == 'S') {
634 			dostype = DOST_NBS;
635 			dostype |= FS_SWAP;
636 		} else {
637 			if (b1 == 'R')
638 				dostype = DOST_NBR;
639 			else
640 				dostype = DOST_NBU;
641 			dostype |= FS_BSDFFS;
642 		}
643 #ifdef DIAGNOSTIC
644 		printf(" using: 0x%lx instead\n", dostype);
645 #endif
646 		return(getadostype(dostype));
647 	case DOST_EXT2:
648 		adt.archtype = ADT_EXT2;
649 		adt.fstype = FS_EX2FS;
650 		return adt;
651 	case DOST_RAID:
652 		adt.archtype = ADT_RAID;
653 		adt.fstype = FS_RAID;
654 		return adt;
655 	case DOST_MSD:
656 		adt.archtype = ADT_MSD;
657 		adt.fstype = FS_MSDOS;
658 		return adt;
659 	default:
660 #ifdef DIAGNOSTIC
661 		printf("warning unknown dostype: 0x%lx marking unused\n",
662 		    dostype);
663 #endif
664 		adt.archtype = ADT_UNKNOWN;
665 		adt.fstype = FS_UNUSED;
666 		return adt;
667 	}
668 }
669 #endif /* RDB_PART */
670 
671 /*
672  * Get raw NetBSD disk label
673  */
674 static int
read_netbsd_label(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * osdep)675 read_netbsd_label(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
676     struct cpu_disklabel *osdep)
677 {
678 	struct buf *bp;
679 	struct disklabel *dlp;
680 
681 	/* get a buffer and initialize it */
682 	bp = geteblk((int)lp->d_secsize);
683 	bp->b_dev = dev;
684 
685 	/* Now get the label block */
686 	bp->b_blkno = osdep->cd_labelsector;
687 	bp->b_bcount = lp->d_secsize;
688 	bp->b_flags |= B_READ;
689 	bp->b_cylinder = bp->b_blkno / (lp->d_secsize / DEV_BSIZE) / lp->d_secpercyl;
690 	(*strat)(bp);
691 
692 	if (biowait(bp))
693 		goto done;
694 
695 	for (dlp = (struct disklabel *)((char *)bp->b_data +
696 		 osdep->cd_labeloffset);
697 	     dlp <= (struct disklabel *)((char *)bp->b_data + lp->d_secsize -
698 	         sizeof (*dlp));
699 	     dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
700 		if (dlp->d_magic == DISKMAGIC
701 		    && dlp->d_magic2 == DISKMAGIC
702 		    && dlp->d_npartitions <= MAXPARTITIONS
703 		    && dkcksum(dlp) == 0) {
704 			*lp = *dlp;
705 			osdep->cd_labeloffset = (char *)dlp -
706 			    (char *)bp->b_data;
707 			brelse(bp, 0);
708 			return 1;
709 		}
710 	}
711 done:
712 	brelse(bp, 0);
713 	return 0;
714 }
715 
716 /*
717  * Attempt to read a disk label from a device using the indicated strategy
718  * routine.  The label must be partly set up before this: secpercyl and
719  * anything required in the strategy routine (e.g., sector size) must be
720  * filled in before calling us.  Returns null on success and an error
721  * string on failure.
722  */
723 const char *
readdisklabel(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * osdep)724 readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
725     struct cpu_disklabel *osdep)
726 {
727 	struct buf *bp;
728 	const char *msg = NULL;
729 
730 	if (lp->d_secperunit == 0)
731 		lp->d_secperunit = 0x1fffffff;
732 
733 	if (lp->d_secpercyl == 0) {
734 		return msg = "Zero secpercyl";
735 	}
736 
737 	/* no valid RDB found */
738 	osdep->rdblock = RDBNULL;
739 
740 	/* XXX cd_start is abused as a flag for fictitious disklabel */
741 	osdep->cd_start = -1;
742 
743 	osdep->cd_labelsector = LABELSECTOR;
744 	osdep->cd_labeloffset = LABELOFFSET;
745 
746 	bp = geteblk((int)lp->d_secsize);
747 
748 	bp->b_dev = dev;
749 	bp->b_blkno = MBR_BBSECTOR;
750 	bp->b_resid = 0;
751 	bp->b_bcount = lp->d_secsize;
752 	bp->b_flags |= B_READ;
753 	bp->b_cylinder = MBR_BBSECTOR / lp->d_secpercyl;
754 	(*strat)(bp);
755 
756 	if (biowait(bp)) {
757 		msg = "I/O error reading block zero";
758 		goto done;
759 	}
760 
761 	if (bswap16(*(u_int16_t *)((char *)bp->b_data + MBR_MAGIC_OFFSET))
762 	    == MBR_MAGIC) {
763 		/*
764 		 * We've got an MBR partitioned disk.
765 		 * read_dos_label figures out labelsector/offset itself
766 		 */
767 		msg = read_dos_label(dev, strat, lp, osdep);
768 	} else {
769 #ifdef RDB_PART
770 		/* scan for RDB partitions */
771 		msg = read_rdb_label(dev, strat, lp, osdep);
772 #else
773 		msg = "no NetBSD disk label";
774 #endif
775 		if (msg != NULL) {
776 			/* try reading a raw NetBSD disklabel at last */
777 			if (read_netbsd_label(dev, strat, lp, osdep))
778 				msg = NULL;
779 		}
780 	}
781 	if (msg == NULL)
782 		osdep->cd_start = 0;
783 
784     done:
785 	brelse(bp, 0);
786 	return msg;
787 }
788 
789 /*
790  * Write disk label back to device after modification.
791  */
792 int
writedisklabel(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * osdep)793 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
794     struct cpu_disklabel *osdep)
795 {
796 	struct buf *bp;
797 	int error;
798 	struct disklabel label;
799 
800 	/*
801 	 * Try to re-read a disklabel, in case the MBR was modified.
802 	 */
803 	label = *lp;
804 	readdisklabel(dev, strat, &label, osdep);
805 
806 	/* If an RDB was present, we don't support writing it yet. */
807 	if (osdep->rdblock != RDBNULL)
808 		return EINVAL;
809 
810 	/* get a buffer and initialize it */
811 	bp = geteblk(lp->d_secsize);
812 	bp->b_dev = dev;
813 
814 	bp->b_blkno = osdep->cd_labelsector;
815 	bp->b_cylinder = bp->b_blkno / (lp->d_secsize / DEV_BSIZE) /
816 	    lp->d_secpercyl;
817 	bp->b_bcount = lp->d_secsize;
818 
819 	bp->b_flags |= B_READ;
820 	(*strat)(bp);
821 	error = biowait(bp);
822 	if (error != 0)
823 		goto done;
824 
825 	bp->b_flags &= ~B_READ;
826 	bp->b_flags |= B_WRITE;
827 	bp->b_oflags &= ~BO_DONE;
828 
829 	memcpy((char *)bp->b_data + osdep->cd_labeloffset, (void *)lp,
830 	    sizeof *lp);
831 
832 	(*strat)(bp);
833 	error = biowait(bp);
834 
835     done:
836 	brelse(bp, 0);
837 
838 	return error;
839 }
840