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