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