1 /* $NetBSD: disksubr.c,v 1.22 2010/12/31 21:50:28 phx 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.22 2010/12/31 21:50:28 phx 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 * 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 + MBR_LABELSECTOR; 194 osdep->cd_labeloffset = MBR_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 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 * 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 disklabel *dlp; 235 struct partition *pp = NULL; 236 struct partblock *pbp; 237 struct rdblock *rbp; 238 const char *msg; 239 char *bcpls, *s, bcpli; 240 int cindex, i, nopname; 241 u_long nextb; 242 243 osdep->rdblock = RDBNULL; 244 lp->d_npartitions = RAW_PART + 1; 245 246 if (lp->d_partitions[RAW_PART].p_size == 0) 247 lp->d_partitions[RAW_PART].p_size = 0x1fffffff; 248 lp->d_partitions[RAW_PART].p_offset = 0; 249 /* if no 'a' partition, default it to copy of 'c' as BSDFFS */ 250 if (lp->d_partitions[0].p_size == 0) { 251 lp->d_partitions[0].p_size = lp->d_partitions[RAW_PART].p_size; 252 lp->d_partitions[0].p_offset = 0; 253 lp->d_partitions[0].p_fstype = FS_BSDFFS; 254 lp->d_partitions[0].p_fsize = 1024; 255 lp->d_partitions[0].p_frag = 8; 256 lp->d_partitions[0].p_cpg = 0; 257 } 258 259 /* obtain buffer to probe drive with */ 260 bp = geteblk((int)lp->d_secsize); 261 262 /* 263 * request no partition relocation by driver on I/O operations 264 */ 265 #ifdef _KERNEL 266 bp->b_dev = MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART); 267 #else 268 bp->b_dev = dev; 269 #endif 270 msg = NULL; 271 272 /* 273 * find the RDB block 274 */ 275 for (nextb = 0; nextb < RDB_MAXBLOCKS; nextb++) { 276 bp->b_blkno = nextb; 277 bp->b_cylinder = bp->b_blkno / lp->d_secpercyl; 278 bp->b_bcount = lp->d_secsize; 279 bp->b_oflags &= ~(BO_DONE); 280 bp->b_flags |= B_READ; 281 #ifdef SD_C_ADJUSTS_NR 282 bp->b_blkno *= (lp->d_secsize / DEV_BSIZE); 283 #endif 284 strat(bp); 285 286 if (biowait(bp)) { 287 msg = "rdb scan I/O error"; 288 goto done; 289 } 290 rbp = baddr(bp); 291 if (rbp->id == RDBLOCK_ID) { 292 if (rdbchksum(rbp) == 0) 293 break; 294 else 295 msg = "rdb bad checksum"; 296 } 297 /* Check for native NetBSD label? */ 298 dlp = (struct disklabel *)((char*)bp->b_data + LABELOFFSET); 299 if (dlp->d_magic == DISKMAGIC) { 300 if (dkcksum(dlp)) 301 msg = "NetBSD disk label corrupted"; 302 else { 303 /* remember block and continue searching? */ 304 *lp = *dlp; 305 brelse(bp, 0); 306 return msg; 307 } 308 } 309 } 310 if (nextb == RDB_MAXBLOCKS) { 311 if (msg == NULL) 312 msg = "no disk label"; 313 goto done; 314 } else if (msg) { 315 /* 316 * maybe we found an invalid one before a valid. 317 * clear err. 318 */ 319 msg = NULL; 320 } 321 osdep->rdblock = nextb; 322 323 /* RDB present, clear disklabel partition table before doing PART blks */ 324 for (i = 0; i < MAXPARTITIONS; i++) { 325 osdep->pbindex[i] = -1; 326 osdep->pblist[i] = RDBNULL; 327 if (i == RAW_PART) 328 continue; 329 lp->d_partitions[i].p_size = 0; 330 lp->d_partitions[i].p_offset = 0; 331 } 332 333 lp->d_secsize = rbp->nbytes; 334 lp->d_nsectors = rbp->nsectors; 335 lp->d_ntracks = rbp->nheads; 336 /* 337 * should be rdb->ncylinders however this is a bogus value 338 * sometimes it seems 339 */ 340 if (rbp->highcyl == 0) 341 lp->d_ncylinders = rbp->ncylinders; 342 else 343 lp->d_ncylinders = rbp->highcyl + 1; 344 /* 345 * I also don't trust rdb->secpercyl 346 */ 347 lp->d_secpercyl = min(rbp->secpercyl, lp->d_nsectors * lp->d_ntracks); 348 if (lp->d_secpercyl == 0) 349 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 350 #ifdef DIAGNOSTIC 351 if (lp->d_ncylinders != rbp->ncylinders) 352 printf("warning found rdb->ncylinders(%ld) != " 353 "rdb->highcyl(%ld) + 1\n", rbp->ncylinders, 354 rbp->highcyl); 355 if (lp->d_nsectors * lp->d_ntracks != rbp->secpercyl) 356 printf("warning found rdb->secpercyl(%ld) != " 357 "rdb->nsectors(%ld) * rdb->nheads(%ld)\n", rbp->secpercyl, 358 rbp->nsectors, rbp->nheads); 359 #endif 360 lp->d_sparespercyl = 361 max(rbp->secpercyl, lp->d_nsectors * lp->d_ntracks) 362 - lp->d_secpercyl; 363 if (lp->d_sparespercyl == 0) 364 lp->d_sparespertrack = 0; 365 else { 366 lp->d_sparespertrack = lp->d_sparespercyl / lp->d_ntracks; 367 #ifdef DIAGNOSTIC 368 if (lp->d_sparespercyl % lp->d_ntracks) 369 printf("warning lp->d_sparespercyl(%d) not multiple " 370 "of lp->d_ntracks(%d)\n", lp->d_sparespercyl, 371 lp->d_ntracks); 372 #endif 373 } 374 375 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; 376 lp->d_acylinders = rbp->ncylinders - (rbp->highcyl - rbp->lowcyl + 1); 377 lp->d_rpm = 3600; /* good guess I suppose. */ 378 lp->d_interleave = rbp->interleave; 379 lp->d_headswitch = lp->d_flags = lp->d_trackskew = lp->d_cylskew = 0; 380 lp->d_trkseek = /* rbp->steprate */ 0; 381 382 /* 383 * raw partition gets the entire disk 384 */ 385 lp->d_partitions[RAW_PART].p_size = rbp->ncylinders * lp->d_secpercyl; 386 387 /* 388 * scan for partition blocks 389 */ 390 nopname = 1; 391 cindex = 0; 392 for (nextb = rbp->partbhead; nextb != RDBNULL; nextb = pbp->next) { 393 bp->b_blkno = nextb; 394 bp->b_cylinder = bp->b_blkno / lp->d_secpercyl; 395 bp->b_bcount = lp->d_secsize; 396 bp->b_oflags &= ~(BO_DONE); 397 bp->b_flags |= B_READ; 398 #ifdef SD_C_ADJUSTS_NR 399 bp->b_blkno *= (lp->d_secsize / DEV_BSIZE); 400 #endif 401 strat(bp); 402 403 if (biowait(bp)) { 404 msg = "partition scan I/O error"; 405 goto done; 406 } 407 pbp = baddr(bp); 408 409 if (pbp->id != PARTBLOCK_ID) { 410 msg = "partition block with bad id"; 411 goto done; 412 } 413 if (rdbchksum(pbp)) { 414 msg = "partition block bad checksum"; 415 goto done; 416 } 417 418 if (pbp->e.tabsize < 11) { 419 /* 420 * not enough info, too funky for us. 421 * I don't want to skip I want it fixed. 422 */ 423 msg = "bad partition info (environ < 11)"; 424 goto done; 425 continue; 426 } 427 428 /* 429 * XXXX should be ">" however some vendors don't know 430 * what a table size is so, we hack for them. 431 * the other checks can fail for all I care but this 432 * is a very common value. *sigh*. 433 */ 434 if (pbp->e.tabsize >= 16) 435 adt = getadostype(pbp->e.dostype); 436 else { 437 adt.archtype = ADT_UNKNOWN; 438 adt.fstype = FS_UNUSED; 439 } 440 441 switch (adt.archtype) { 442 case ADT_NETBSDROOT: 443 pp = &lp->d_partitions[0]; 444 if (pp->p_size) { 445 printf("WARN: more than one root, ignoring\n"); 446 osdep->rdblock = RDBNULL; /* invlidate cpulab */ 447 continue; 448 } 449 break; 450 case ADT_NETBSDSWAP: 451 pp = &lp->d_partitions[1]; 452 if (pp->p_size) { 453 printf("WARN: more than one swap, ignoring\n"); 454 osdep->rdblock = RDBNULL; /* invlidate cpulab */ 455 continue; 456 } 457 break; 458 case ADT_NETBSDUSER: 459 case ADT_AMIGADOS: 460 case ADT_AMIX: 461 case ADT_EXT2: 462 case ADT_RAID: 463 case ADT_UNKNOWN: 464 pp = &lp->d_partitions[lp->d_npartitions]; 465 break; 466 } 467 if (lp->d_npartitions <= (pp - lp->d_partitions)) 468 lp->d_npartitions = (pp - lp->d_partitions) + 1; 469 470 #ifdef DIAGNOSTIC 471 if (lp->d_secpercyl * lp->d_secsize != 472 (pbp->e.secpertrk * pbp->e.numheads * pbp->e.sizeblock<<2)) { 473 if (pbp->partname[0] < sizeof(pbp->partname)) 474 pbp->partname[pbp->partname[0] + 1] = 0; 475 else 476 pbp->partname[sizeof(pbp->partname) - 1] = 0; 477 printf("Partition '%s' geometry %ld/%ld differs", 478 pbp->partname + 1, pbp->e.numheads, 479 pbp->e.secpertrk); 480 printf(" from RDB %d/%d=%d\n", lp->d_ntracks, 481 lp->d_nsectors, lp->d_secpercyl); 482 } 483 #endif 484 /* 485 * insert sort in increasing offset order 486 */ 487 while ((pp - lp->d_partitions) > RAW_PART + 1) { 488 daddr_t boff; 489 490 boff = pbp->e.lowcyl * pbp->e.secpertrk 491 * pbp->e.numheads; 492 if (boff > (pp - 1)->p_offset) 493 break; 494 *pp = *(pp - 1); /* struct copy */ 495 pp--; 496 } 497 i = (pp - lp->d_partitions); 498 if (nopname || i == 1) { 499 /* 500 * either we have no packname yet or we found 501 * the swap partition. copy BCPL string into packname 502 * [the reason we use the swap partition: the user 503 * can supply a decent packname without worry 504 * of having to access an odly named partition 505 * under AmigaDos] 506 */ 507 s = lp->d_packname; 508 bcpls = &pbp->partname[1]; 509 bcpli = pbp->partname[0]; 510 if (sizeof(lp->d_packname) <= bcpli) 511 bcpli = sizeof(lp->d_packname) - 1; 512 while (bcpli--) 513 *s++ = *bcpls++; 514 *s = 0; 515 nopname = 0; 516 } 517 518 pp->p_size = (pbp->e.highcyl - pbp->e.lowcyl + 1) 519 * pbp->e.secpertrk * pbp->e.numheads 520 * ((pbp->e.sizeblock << 2) / lp->d_secsize); 521 pp->p_offset = pbp->e.lowcyl * pbp->e.secpertrk 522 * pbp->e.numheads 523 * ((pbp->e.sizeblock << 2) / lp->d_secsize); 524 pp->p_fstype = adt.fstype; 525 if (adt.archtype == ADT_AMIGADOS) { 526 /* 527 * Save reserved blocks at begin in cpg and 528 * adjust size by reserved blocks at end 529 */ 530 int bsize, secperblk, minbsize, prefac; 531 532 minbsize = max(512, lp->d_secsize); 533 534 bsize = pbp->e.sizeblock << 2; 535 secperblk = pbp->e.secperblk; 536 prefac = pbp->e.prefac; 537 538 while (bsize > minbsize) { 539 bsize >>= 1; 540 secperblk <<= 1; 541 prefac <<= 1; 542 } 543 544 if (bsize == minbsize) { 545 pp->p_fsize = bsize; 546 pp->p_frag = secperblk; 547 pp->p_cpg = pbp->e.resvblocks; 548 pp->p_size -= prefac; 549 } else { 550 adt.archtype = ADT_UNKNOWN; 551 adt.fstype = FS_UNUSED; 552 } 553 } else if (pbp->e.tabsize > 22 && ISFSARCH_NETBSD(adt)) { 554 pp->p_fsize = pbp->e.fsize; 555 pp->p_frag = pbp->e.frag; 556 pp->p_cpg = pbp->e.cpg; 557 } else { 558 pp->p_fsize = 1024; 559 pp->p_frag = 8; 560 pp->p_cpg = 0; 561 } 562 563 /* 564 * store this partitions block number 565 */ 566 osdep->pblist[osdep->pbindex[i] = cindex++] = nextb; 567 } 568 /* 569 * calulate new checksum. 570 */ 571 lp->d_magic = lp->d_magic2 = DISKMAGIC; 572 lp->d_checksum = 0; 573 lp->d_checksum = dkcksum(lp); 574 if (osdep->rdblock != RDBNULL) 575 osdep->valid = 1; 576 done: 577 if (osdep->valid == 0) 578 osdep->rdblock = RDBNULL; 579 brelse(bp, 0); 580 return msg; 581 } 582 583 static u_long 584 rdbchksum(void *bdata) 585 { 586 u_long *blp, cnt, val; 587 588 blp = bdata; 589 cnt = blp[1]; 590 val = 0; 591 592 while (cnt--) 593 val += *blp++; 594 return val; 595 } 596 597 static struct adostype 598 getadostype(u_long dostype) 599 { 600 struct adostype adt; 601 u_long b1, t3; 602 603 t3 = dostype & 0xffffff00; 604 b1 = dostype & 0x000000ff; 605 606 adt.fstype = b1; 607 608 switch (t3) { 609 case DOST_NBR: 610 adt.archtype = ADT_NETBSDROOT; 611 return adt; 612 case DOST_NBS: 613 adt.archtype = ADT_NETBSDSWAP; 614 return adt; 615 case DOST_NBU: 616 adt.archtype = ADT_NETBSDUSER; 617 return adt; 618 case DOST_MUFS: 619 /* check for 'muFS'? */ 620 adt.archtype = ADT_AMIGADOS; 621 adt.fstype = FS_ADOS; 622 return adt; 623 case DOST_DOS: 624 adt.archtype = ADT_AMIGADOS; 625 if (b1 > 5) 626 adt.fstype = FS_UNUSED; 627 else 628 adt.fstype = FS_ADOS; 629 return adt; 630 case DOST_AMIX: 631 adt.archtype = ADT_AMIX; 632 if (b1 == 2) 633 adt.fstype = FS_BSDFFS; 634 else 635 adt.fstype = FS_UNUSED; 636 return adt; 637 case DOST_XXXBSD: 638 #ifdef DIAGNOSTIC 639 printf("found dostype: 0x%lx which is deprecated", dostype); 640 #endif 641 if (b1 == 'S') { 642 dostype = DOST_NBS; 643 dostype |= FS_SWAP; 644 } else { 645 if (b1 == 'R') 646 dostype = DOST_NBR; 647 else 648 dostype = DOST_NBU; 649 dostype |= FS_BSDFFS; 650 } 651 #ifdef DIAGNOSTIC 652 printf(" using: 0x%lx instead\n", dostype); 653 #endif 654 return(getadostype(dostype)); 655 case DOST_EXT2: 656 adt.archtype = ADT_EXT2; 657 adt.fstype = FS_EX2FS; 658 return adt; 659 case DOST_RAID: 660 adt.archtype = ADT_RAID; 661 adt.fstype = FS_RAID; 662 return adt; 663 default: 664 #ifdef DIAGNOSTIC 665 printf("warning unknown dostype: 0x%lx marking unused\n", 666 dostype); 667 #endif 668 adt.archtype = ADT_UNKNOWN; 669 adt.fstype = FS_UNUSED; 670 return adt; 671 } 672 } 673 #endif /* RDB_PART */ 674 675 /* 676 * Get raw NetBSD disk label 677 */ 678 static int 679 read_netbsd_label(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, 680 struct cpu_disklabel *osdep) 681 { 682 struct buf *bp; 683 struct disklabel *dlp; 684 685 /* get a buffer and initialize it */ 686 bp = geteblk((int)lp->d_secsize); 687 bp->b_dev = dev; 688 689 /* Now get the label block */ 690 bp->b_blkno = osdep->cd_labelsector; 691 bp->b_bcount = lp->d_secsize; 692 bp->b_flags |= B_READ; 693 bp->b_cylinder = bp->b_blkno / (lp->d_secsize / DEV_BSIZE) / lp->d_secpercyl; 694 (*strat)(bp); 695 696 if (biowait(bp)) 697 goto done; 698 699 for (dlp = (struct disklabel *)((char *)bp->b_data + 700 osdep->cd_labeloffset); 701 dlp <= (struct disklabel *)((char *)bp->b_data + lp->d_secsize - 702 sizeof (*dlp)); 703 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { 704 if (dlp->d_magic == DISKMAGIC 705 && dlp->d_magic2 == DISKMAGIC 706 && dlp->d_npartitions <= MAXPARTITIONS 707 && dkcksum(dlp) == 0) { 708 *lp = *dlp; 709 osdep->cd_labeloffset = (char *)dlp - 710 (char *)bp->b_data; 711 brelse(bp, 0); 712 return 1; 713 } 714 } 715 done: 716 brelse(bp, 0); 717 return 0; 718 } 719 720 /* 721 * Attempt to read a disk label from a device using the indicated strategy 722 * routine. The label must be partly set up before this: secpercyl and 723 * anything required in the strategy routine (e.g., sector size) must be 724 * filled in before calling us. Returns null on success and an error 725 * string on failure. 726 */ 727 const char * 728 readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, 729 struct cpu_disklabel *osdep) 730 { 731 struct buf *bp; 732 const char *msg = NULL; 733 734 if (lp->d_secperunit == 0) 735 lp->d_secperunit = 0x1fffffff; 736 737 if (lp->d_secpercyl == 0) { 738 return msg = "Zero secpercyl"; 739 } 740 bp = geteblk((int)lp->d_secsize); 741 742 bp->b_dev = dev; 743 bp->b_blkno = 0; 744 bp->b_resid = 0; 745 bp->b_bcount = lp->d_secsize; 746 bp->b_flags |= B_READ; 747 bp->b_cylinder = 1 / lp->d_secpercyl; 748 (*strat)(bp); 749 750 /* no valid RDB found */ 751 osdep->rdblock = RDBNULL; 752 753 /* XXX cd_start is abused as a flag for fictious disklabel */ 754 osdep->cd_start = -1; 755 756 if (biowait(bp)) { 757 msg = "I/O error reading block zero"; 758 goto done; 759 } 760 761 osdep->cd_labelsector = LABELSECTOR; 762 osdep->cd_labeloffset = LABELOFFSET; 763 764 if (read_netbsd_label(dev, strat, lp, osdep)) 765 osdep->cd_start = 0; 766 else { 767 if (bswap16(*(u_int16_t *)((char *)bp->b_data + 768 MBR_MAGIC_OFFSET)) == MBR_MAGIC) { 769 /* read_dos_label figures out labelsector/offset */ 770 msg = read_dos_label(dev, strat, lp, osdep); 771 if (!msg) 772 osdep->cd_start = 0; 773 } else { 774 #ifdef RDB_PART 775 /* scan for RDB partitions */ 776 msg = read_rdb_label(dev, strat, lp, osdep); 777 #else 778 msg = "no disk label"; 779 #endif 780 osdep->cd_start = 0; /* XXX for now */ 781 } 782 } 783 784 done: 785 brelse(bp, 0); 786 return msg; 787 } 788 789 /* 790 * Check new disk label for sensibility before setting it. 791 */ 792 int 793 setdisklabel(struct disklabel *olp, struct disklabel *nlp, u_long openmask, 794 struct cpu_disklabel *osdep) 795 { 796 int i; 797 struct partition *opp, *npp; 798 799 /* sanity clause */ 800 if (nlp->d_secpercyl == 0 || nlp->d_secsize == 0 801 || (nlp->d_secsize % DEV_BSIZE) != 0) 802 return EINVAL; 803 804 /* special case to allow disklabel to be invalidated */ 805 if (nlp->d_magic == 0xffffffff) { 806 *olp = *nlp; 807 return 0; 808 } 809 810 if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC 811 || dkcksum(nlp) != 0) 812 return EINVAL; 813 814 while ((i = ffs(openmask)) != 0) { 815 i--; 816 openmask &= ~(1 << i); 817 if (nlp->d_npartitions <= i) 818 return EBUSY; 819 opp = &olp->d_partitions[i]; 820 npp = &nlp->d_partitions[i]; 821 if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size) 822 return EBUSY; 823 /* 824 * Copy internally-set partition information 825 * if new label doesn't include it. XXX 826 */ 827 if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) { 828 npp->p_fstype = opp->p_fstype; 829 npp->p_fsize = opp->p_fsize; 830 npp->p_frag = opp->p_frag; 831 npp->p_cpg = opp->p_cpg; 832 } 833 } 834 nlp->d_checksum = 0; 835 nlp->d_checksum = dkcksum(nlp); 836 837 *olp = *nlp; 838 return 0; 839 } 840 841 /* 842 * Write disk label back to device after modification. 843 */ 844 int 845 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, 846 struct cpu_disklabel *osdep) 847 { 848 struct buf *bp; 849 int error; 850 struct disklabel label; 851 852 /* If RDB was present, we don't support writing them yet. */ 853 if (osdep->rdblock != RDBNULL) 854 return EINVAL; 855 856 /* 857 * Try to re-read a disklabel, in case he changed the MBR. 858 */ 859 label = *lp; 860 readdisklabel(dev, strat, &label, osdep); 861 if (osdep->cd_start < 0) 862 return EINVAL; 863 864 /* get a buffer and initialize it */ 865 bp = geteblk(lp->d_secsize); 866 bp->b_dev = dev; 867 868 bp->b_blkno = osdep->cd_start + osdep->cd_labelsector; 869 bp->b_cylinder = bp->b_blkno / (lp->d_secsize / DEV_BSIZE) / 870 lp->d_secpercyl; 871 bp->b_bcount = lp->d_secsize; 872 873 bp->b_flags |= B_READ; 874 (*strat)(bp); 875 error = biowait(bp); 876 if (error != 0) 877 goto done; 878 879 bp->b_flags &= ~B_READ; 880 bp->b_flags |= B_WRITE; 881 bp->b_oflags &= ~BO_DONE; 882 883 memcpy((char *)bp->b_data + osdep->cd_labeloffset, (void *)lp, 884 sizeof *lp); 885 886 (*strat)(bp); 887 error = biowait(bp); 888 889 done: 890 brelse(bp, 0); 891 892 return error; 893 } 894