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
88static const char *read_dos_label(dev_t, void (*)(struct buf *),
89    struct disklabel *, struct cpu_disklabel *);
90static int getFreeLabelEntry(struct disklabel *);
91static int read_netbsd_label(dev_t, void (*)(struct buf *), struct disklabel *,
92    struct cpu_disklabel *);
93#ifdef RDB_PART
94static const char *read_rdb_label(dev_t, void (*)(struct buf *),
95    struct disklabel *, struct cpu_disklabel *);
96static u_long rdbchksum(void *);
97static 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 */
109static const char *
110read_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
202done:
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 */
211static int
212getFreeLabelEntry(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 */
228static const char *
229read_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;
568done:
569	if (osdep->valid == 0)
570		osdep->rdblock = RDBNULL;
571	brelse(bp, 0);
572	return msg;
573}
574
575static u_long
576rdbchksum(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
589static struct adostype
590getadostype(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 */
674static int
675read_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	}
711done:
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 */
723const char *
724readdisklabel(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 */
792int
793writedisklabel(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