1/* $OpenBSD: ofdev.c,v 1.40 2024/04/14 03:26:25 jsg Exp $ */ 2/* $NetBSD: ofdev.c,v 1.1 2000/08/20 14:58:41 mrg Exp $ */ 3 4/* 5 * Copyright (C) 1995, 1996 Wolfgang Solfrank. 6 * Copyright (C) 1995, 1996 TooLs GmbH. 7 * All rights reserved. 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 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by TooLs GmbH. 20 * 4. The name of TooLs GmbH may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 29 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34/* 35 * Device I/O routines using Open Firmware 36 */ 37#include <sys/param.h> 38#include <sys/disklabel.h> 39#ifdef NETBOOT 40#include <netinet/in.h> 41#endif 42 43#include <lib/libkern/funcs.h> 44#include <lib/libsa/stand.h> 45#include <lib/libsa/ufs.h> 46#include <lib/libsa/ufs2.h> 47#include <lib/libsa/cd9660.h> 48#ifdef NETBOOT 49#include <lib/libsa/nfs.h> 50#endif 51 52#ifdef SOFTRAID 53#include <sys/queue.h> 54#include <dev/softraidvar.h> 55#include "softraid_sparc64.h" 56#include "disk.h" 57#endif 58 59#include <dev/sun/disklabel.h> 60#include "openfirm.h" 61#include "ofdev.h" 62 63/* needed for DISKLABELV1_FFS_FRAGBLOCK */ 64int ffs(int); 65 66extern char bootdev[]; 67 68/* 69 * This is ugly. A path on a sparc machine is something like this: 70 * 71 * [device] [-<options] [path] [-options] [otherstuff] [-<more options] 72 * 73 */ 74 75static char * 76filename(char *str, char *ppart) 77{ 78 char *cp, *lp; 79 char savec; 80 int dhandle; 81 char devtype[16]; 82 83 lp = str; 84 devtype[0] = 0; 85 *ppart = 0; 86 for (cp = str; *cp; lp = cp) { 87 /* For each component of the path name... */ 88 while (*++cp && *cp != '/'); 89 savec = *cp; 90 *cp = 0; 91 /* ...look whether there is a device with this name */ 92 dhandle = OF_finddevice(str); 93 DNPRINTF(BOOT_D_OFDEV, "filename: OF_finddevice(%s) says %x\n", 94 str, dhandle); 95 *cp = savec; 96 if (dhandle == -1) { 97 /* if not, lp is the delimiter between device and path */ 98 /* if the last component was a block device... */ 99 if (!strcmp(devtype, "block")) { 100 /* search for arguments */ 101 DNPRINTF(BOOT_D_OFDEV, "filename: hunting for " 102 "arguments in %s\n", str); 103 for (cp = lp; 104 --cp >= str && *cp != '/' && *cp != '-';); 105 if (cp >= str && *cp == '-') { 106 /* found arguments, make firmware ignore them */ 107 *cp = 0; 108 for (cp = lp; *--cp && *cp != ',';) 109 ; 110 if (*++cp >= 'a' && *cp <= 'a' + MAXPARTITIONS) 111 *ppart = *cp; 112 } 113 } 114 DNPRINTF(BOOT_D_OFDEV, "filename: found %s\n", lp); 115 return lp; 116 } else if (OF_getprop(dhandle, "device_type", devtype, sizeof devtype) < 0) 117 devtype[0] = 0; 118 } 119 DNPRINTF(BOOT_D_OFDEV, "filename: not found\n", lp); 120 return 0; 121} 122 123int 124strategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf, 125 size_t *rsize) 126{ 127 struct of_dev *dev = devdata; 128 u_quad_t pos; 129 int n; 130 131#ifdef SOFTRAID 132 /* Intercept strategy for softraid volumes. */ 133 if (dev->type == OFDEV_SOFTRAID) 134 return sr_strategy(bootdev_dip->sr_vol, bootdev_dip->sr_handle, 135 rw, blk, size, buf, rsize); 136#endif 137 if (dev->type != OFDEV_DISK) 138 panic("strategy"); 139 140 DNPRINTF(BOOT_D_OFDEV, "strategy: block %lx, partition offset %lx, " 141 "blksz %lx\n", (long)blk, (long)dev->partoff, (long)dev->bsize); 142 DNPRINTF(BOOT_D_OFDEV, "strategy: seek position should be: %lx\n", 143 (long)((blk + dev->partoff) * dev->bsize)); 144 pos = (u_quad_t)(blk + dev->partoff) * dev->bsize; 145 146 for (;;) { 147 DNPRINTF(BOOT_D_OFDEV, "strategy: seeking to %lx\n", (long)pos); 148 if (OF_seek(dev->handle, pos) < 0) 149 break; 150 DNPRINTF(BOOT_D_OFDEV, "strategy: reading %lx at %p\n", 151 (long)size, buf); 152 if (rw == F_READ) 153 n = OF_read(dev->handle, buf, size); 154 else 155 n = OF_write(dev->handle, buf, size); 156 if (n == -2) 157 continue; 158 if (n < 0) 159 break; 160 if (rsize) 161 *rsize = n; 162 return 0; 163 } 164 return EIO; 165} 166 167static int 168devclose(struct open_file *of) 169{ 170 struct of_dev *op = of->f_devdata; 171 172#ifdef NETBOOT 173 if (op->type == OFDEV_NET) 174 net_close(op); 175#endif 176#ifdef SOFTRAID 177 if (op->type == OFDEV_SOFTRAID) { 178 op->handle = -1; 179 return 0; 180 } 181#endif 182 OF_close(op->handle); 183 op->handle = -1; 184 return 0; 185} 186 187struct devsw devsw[1] = { 188 { 189 "OpenFirmware", 190 strategy, 191 (int (*)(struct open_file *, ...))nodev, 192 devclose, 193 noioctl 194 } 195}; 196int ndevs = sizeof devsw / sizeof devsw[0]; 197 198#ifdef SPARC_BOOT_UFS 199static struct fs_ops file_system_ufs = { 200 ufs_open, ufs_close, ufs_read, ufs_write, ufs_seek, 201 ufs_stat, ufs_readdir, ufs_fchmod 202}; 203static struct fs_ops file_system_ufs2 = { 204 ufs2_open, ufs2_close, ufs2_read, ufs2_write, ufs2_seek, 205 ufs2_stat, ufs2_readdir, ufs2_fchmod 206}; 207#endif 208#ifdef SPARC_BOOT_HSFS 209static struct fs_ops file_system_cd9660 = { 210 cd9660_open, cd9660_close, cd9660_read, cd9660_write, cd9660_seek, 211 cd9660_stat, cd9660_readdir 212}; 213#endif 214#ifdef NETBOOT 215static struct fs_ops file_system_nfs = { 216 nfs_open, nfs_close, nfs_read, nfs_write, nfs_seek, 217 nfs_stat, nfs_readdir 218}; 219#endif 220 221struct fs_ops file_system[4]; 222int nfsys; 223 224static struct of_dev ofdev = { 225 -1, 226}; 227 228char opened_name[256]; 229 230/************************************************************************ 231 * 232 * The rest of this was taken from arch/sparc64/scsi/sun_disklabel.c 233 * and then substantially rewritten by Gordon W. Ross 234 * 235 ************************************************************************/ 236 237/* What partition types to assume for Sun disklabels: */ 238static u_char 239sun_fstypes[8] = { 240 FS_BSDFFS, /* a */ 241 FS_SWAP, /* b */ 242 FS_OTHER, /* c - whole disk */ 243 FS_BSDFFS, /* d */ 244 FS_BSDFFS, /* e */ 245 FS_BSDFFS, /* f */ 246 FS_BSDFFS, /* g */ 247 FS_BSDFFS, /* h */ 248}; 249 250/* 251 * Given a struct sun_disklabel, assume it has an extended partition 252 * table and compute the correct value for sl_xpsum. 253 */ 254static __inline u_int 255sun_extended_sum(struct sun_disklabel *sl, void *end) 256{ 257 u_int sum, *xp, *ep; 258 259 xp = (u_int *)&sl->sl_xpmag; 260 ep = (u_int *)end; 261 262 sum = 0; 263 for (; xp < ep; xp++) 264 sum += *xp; 265 return (sum); 266} 267 268/* 269 * Given a SunOS disk label, set lp to a BSD disk label. 270 * The BSD label is cleared out before this is called. 271 */ 272static int 273disklabel_sun_to_bsd(struct sun_disklabel *sl, struct disklabel *lp) 274{ 275 struct sun_preamble *preamble = (struct sun_preamble *)sl; 276 struct sun_partinfo *ppp; 277 struct sun_dkpart *spp; 278 struct partition *npp; 279 u_short cksum = 0, *sp1, *sp2; 280 int i, secpercyl; 281 282 /* Verify the XOR check. */ 283 sp1 = (u_short *)sl; 284 sp2 = (u_short *)(sl + 1); 285 while (sp1 < sp2) 286 cksum ^= *sp1++; 287 if (cksum != 0) 288 return (EINVAL); /* SunOS disk label, bad checksum */ 289 290 /* Format conversion. */ 291 lp->d_magic = DISKMAGIC; 292 lp->d_magic2 = DISKMAGIC; 293 lp->d_flags = D_VENDOR; 294 memcpy(lp->d_packname, sl->sl_text, sizeof(lp->d_packname)); 295 296 lp->d_secsize = DEV_BSIZE; 297 lp->d_nsectors = sl->sl_nsectors; 298 lp->d_ntracks = sl->sl_ntracks; 299 lp->d_ncylinders = sl->sl_ncylinders; 300 301 secpercyl = sl->sl_nsectors * sl->sl_ntracks; 302 lp->d_secpercyl = secpercyl; 303 if (DL_GETDSIZE(lp) == 0) 304 DL_SETDSIZE(lp, (u_int64_t)secpercyl * sl->sl_ncylinders); 305 lp->d_version = 1; 306 307 memcpy(&lp->d_uid, &sl->sl_uid, sizeof(lp->d_uid)); 308 309 lp->d_acylinders = sl->sl_acylinders; 310 311 lp->d_npartitions = MAXPARTITIONS; 312 313 for (i = 0; i < 8; i++) { 314 spp = &sl->sl_part[i]; 315 npp = &lp->d_partitions[i]; 316 DL_SETPOFFSET(npp, spp->sdkp_cyloffset * secpercyl); 317 DL_SETPSIZE(npp, spp->sdkp_nsectors); 318 if (DL_GETPSIZE(npp) == 0) { 319 npp->p_fstype = FS_UNUSED; 320 } else { 321 npp->p_fstype = sun_fstypes[i]; 322 if (npp->p_fstype == FS_BSDFFS) { 323 /* 324 * The sun label does not store the FFS fields, 325 * so just set them with default values here. 326 */ 327 npp->p_fragblock = 328 DISKLABELV1_FFS_FRAGBLOCK(2048, 8); 329 npp->p_cpg = 16; 330 } 331 } 332 } 333 334 /* Clear "extended" partition info, tentatively */ 335 for (i = 0; i < SUNXPART; i++) { 336 npp = &lp->d_partitions[i+8]; 337 DL_SETPOFFSET(npp, 0); 338 DL_SETPSIZE(npp, 0); 339 npp->p_fstype = FS_UNUSED; 340 } 341 342 /* Check to see if there's an "extended" partition table 343 * SL_XPMAG partitions had checksums up to just before the 344 * (new) sl_types variable, while SL_XPMAGTYP partitions have 345 * checksums up to the just before the (new) sl_xxx1 variable. 346 * Also, disklabels created prior to the addition of sl_uid will 347 * have a checksum to just before the sl_uid variable. 348 */ 349 if ((sl->sl_xpmag == SL_XPMAG && 350 sun_extended_sum(sl, &sl->sl_types) == sl->sl_xpsum) || 351 (sl->sl_xpmag == SL_XPMAGTYP && 352 sun_extended_sum(sl, &sl->sl_uid) == sl->sl_xpsum) || 353 (sl->sl_xpmag == SL_XPMAGTYP && 354 sun_extended_sum(sl, &sl->sl_xxx1) == sl->sl_xpsum)) { 355 /* 356 * There is. Copy over the "extended" partitions. 357 * This code parallels the loop for partitions a-h. 358 */ 359 for (i = 0; i < SUNXPART; i++) { 360 spp = &sl->sl_xpart[i]; 361 npp = &lp->d_partitions[i+8]; 362 DL_SETPOFFSET(npp, spp->sdkp_cyloffset * secpercyl); 363 DL_SETPSIZE(npp, spp->sdkp_nsectors); 364 if (DL_GETPSIZE(npp) == 0) { 365 npp->p_fstype = FS_UNUSED; 366 continue; 367 } 368 npp->p_fstype = FS_BSDFFS; 369 npp->p_fragblock = 370 DISKLABELV1_FFS_FRAGBLOCK(2048, 8); 371 npp->p_cpg = 16; 372 } 373 if (sl->sl_xpmag == SL_XPMAGTYP) { 374 for (i = 0; i < MAXPARTITIONS; i++) { 375 npp = &lp->d_partitions[i]; 376 npp->p_fstype = sl->sl_types[i]; 377 npp->p_fragblock = sl->sl_fragblock[i]; 378 npp->p_cpg = sl->sl_cpg[i]; 379 } 380 } 381 } else if (preamble->sl_nparts <= 8) { 382 /* 383 * A more traditional Sun label. Recognise certain filesystem 384 * types from it, if they are available. 385 */ 386 i = preamble->sl_nparts; 387 if (i == 0) 388 i = 8; 389 390 npp = &lp->d_partitions[i-1]; 391 ppp = &preamble->sl_part[i-1]; 392 for (; i > 0; i--, npp--, ppp--) { 393 if (npp->p_size == 0) 394 continue; 395 if ((ppp->spi_tag == 0) && (ppp->spi_flag == 0)) 396 continue; 397 398 switch (ppp->spi_tag) { 399 case SPTAG_SUNOS_ROOT: 400 case SPTAG_SUNOS_USR: 401 case SPTAG_SUNOS_VAR: 402 case SPTAG_SUNOS_HOME: 403 npp->p_fstype = FS_BSDFFS; 404 npp->p_fragblock = 405 DISKLABELV1_FFS_FRAGBLOCK(2048, 8); 406 npp->p_cpg = 16; 407 break; 408 case SPTAG_LINUX_EXT2: 409 npp->p_fstype = FS_EXT2FS; 410 break; 411 default: 412 /* FS_SWAP for _SUNOS_SWAP and _LINUX_SWAP? */ 413 npp->p_fstype = FS_UNUSED; 414 break; 415 } 416 } 417 } 418 419 lp->d_checksum = 0; 420 lp->d_checksum = dkcksum(lp); 421 DNPRINTF(BOOT_D_OFDEV, "disklabel_sun_to_bsd: success!\n"); 422 return (0); 423} 424 425/* 426 * Find a valid disklabel. 427 */ 428static char * 429search_label(struct of_dev *devp, u_long off, char *buf, struct disklabel *lp, 430 u_long off0) 431{ 432 struct disklabel *dlp; 433 struct sun_disklabel *slp; 434 size_t read; 435 436 /* minimal requirements for archetypal disk label */ 437 if (DL_GETDSIZE(lp) == 0) 438 DL_SETDSIZE(lp, 0x1fffffff); 439 lp->d_npartitions = MAXPARTITIONS; 440 if (DL_GETPSIZE(&lp->d_partitions[0]) == 0) 441 DL_SETPSIZE(&lp->d_partitions[0], 0x1fffffff); 442 DL_SETPOFFSET(&lp->d_partitions[0], 0); 443 444 if (strategy(devp, F_READ, off, DEV_BSIZE, buf, &read) 445 || read != DEV_BSIZE) 446 return ("Cannot read label"); 447 448 /* Check for a disk label. */ 449 dlp = (struct disklabel *) (buf + LABELOFFSET); 450 if (dlp->d_magic == DISKMAGIC) { 451 if (dkcksum(dlp)) 452 return ("corrupt disk label"); 453 *lp = *dlp; 454 DNPRINTF(BOOT_D_OFDEV, "search_label: found disk label\n"); 455 return (NULL); 456 } 457 458 /* Check for a Sun disk label (for PROM compatibility). */ 459 slp = (struct sun_disklabel *)buf; 460 if (slp->sl_magic == SUN_DKMAGIC) { 461 if (disklabel_sun_to_bsd(slp, lp) != 0) 462 return ("corrupt disk label"); 463 DNPRINTF(BOOT_D_OFDEV, "search_label: found disk label\n"); 464 return (NULL); 465 } 466 467 return ("no disk label"); 468} 469 470int 471load_disklabel(struct of_dev *ofdev, struct disklabel *label) 472{ 473 char buf[DEV_BSIZE]; 474 size_t read; 475 int error = 0; 476 char *errmsg = NULL; 477 478 DNPRINTF(BOOT_D_OFDEV, "load_disklabel: trying to read disklabel\n"); 479 if (strategy(ofdev, F_READ, 480 LABELSECTOR, DEV_BSIZE, buf, &read) != 0 481 || read != DEV_BSIZE 482 || (errmsg = getdisklabel(buf, label))) { 483#ifdef BOOT_DEBUG 484 if (errmsg) 485 DNPRINTF(BOOT_D_OFDEV, 486 "load_disklabel: getdisklabel says %s\n", errmsg); 487#endif 488 errmsg = search_label(ofdev, LABELSECTOR, buf, label, 0); 489 if (errmsg) { 490 printf("load_disklabel: search_label says %s\n", 491 errmsg); 492 error = ERDLAB; 493 } 494 } 495 496 return (error); 497} 498 499int 500devopen(struct open_file *of, const char *name, char **file) 501{ 502 char *cp; 503 char partition; 504 char fname[256]; 505 char buf[DEV_BSIZE]; 506 struct disklabel label; 507 int dhandle, ihandle, part, parent; 508 int error = 0; 509#ifdef SOFTRAID 510 char volno; 511#endif 512 513 nfsys = 0; 514 if (ofdev.handle != -1) 515 panic("devopen"); 516 DNPRINTF(BOOT_D_OFDEV, "devopen: you want %s\n", name); 517 if (strlcpy(fname, name, sizeof fname) >= sizeof fname) 518 return ENAMETOOLONG; 519#ifdef SOFTRAID 520 if (bootdev_dip) { 521 if (fname[0] == 's' && fname[1] == 'r' && 522 '0' <= fname[2] && fname[2] <= '9') { 523 /* We only support read-only softraid. */ 524 of->f_flags |= F_NOWRITE; 525 526 volno = fname[2]; 527 if ('a' <= fname[3] && 528 fname[3] <= 'a' + MAXPARTITIONS) { 529 partition = fname[3]; 530 if (fname[4] == ':') 531 cp = &fname[5]; 532 else 533 cp = &fname[4]; 534 } else { 535 partition = 'a'; 536 cp = &fname[3]; 537 } 538 } else { 539 volno = '0'; 540 partition = 'a'; 541 cp = &fname[0]; 542 } 543 snprintf(buf, sizeof buf, "sr%c%c:", volno, partition); 544 if (strlcpy(opened_name, buf, sizeof opened_name) 545 >= sizeof opened_name) 546 return ENAMETOOLONG; 547 *file = opened_name + strlen(opened_name); 548 if (!*cp) { 549 if (strlcpy(buf, DEFAULT_KERNEL, sizeof buf) 550 >= sizeof buf) 551 return ENAMETOOLONG; 552 } else { 553 if (snprintf(buf, sizeof buf, "%s%s", 554 *cp == '/' ? "" : "/", cp) >= sizeof buf) 555 return ENAMETOOLONG; 556 } 557 if (strlcat(opened_name, buf, sizeof opened_name) >= 558 sizeof opened_name) 559 return ENAMETOOLONG; 560 } else { 561#endif 562 cp = filename(fname, &partition); 563 if (cp) { 564 if (strlcpy(buf, cp, sizeof buf) >= sizeof buf) 565 return ENAMETOOLONG; 566 *cp = 0; 567 } 568 if (!cp || !*buf) { 569 if (strlcpy(buf, DEFAULT_KERNEL, sizeof buf) 570 >= sizeof buf) 571 return ENAMETOOLONG; 572 } 573 if (!*fname) { 574 if (strlcpy(fname, bootdev, sizeof fname) 575 >= sizeof fname) 576 return ENAMETOOLONG; 577 } 578 if (strlcpy(opened_name, fname, 579 partition ? (sizeof opened_name) - 2 : sizeof opened_name) 580 >= sizeof opened_name) 581 return ENAMETOOLONG; 582 if (partition) { 583 cp = opened_name + strlen(opened_name); 584 *cp++ = ':'; 585 *cp++ = partition; 586 *cp = 0; 587 } 588 if (*buf != '/') { 589 if (strlcat(opened_name, "/", sizeof opened_name) >= 590 sizeof opened_name) 591 return ENAMETOOLONG; 592 } 593 if (strlcat(opened_name, buf, sizeof opened_name) >= 594 sizeof opened_name) 595 return ENAMETOOLONG; 596 *file = opened_name + strlen(fname) + 1; 597#ifdef SOFTRAID 598 } 599#endif 600 DNPRINTF(BOOT_D_OFDEV, "devopen: trying %s\n", fname); 601#ifdef SOFTRAID 602 if (bootdev_dip) { 603 /* Redirect to the softraid boot volume. */ 604 struct partition *pp; 605 606 bzero(&ofdev, sizeof ofdev); 607 ofdev.type = OFDEV_SOFTRAID; 608 609 if (partition) { 610 if (partition < 'a' || 611 partition >= 'a' + MAXPARTITIONS) { 612 printf("invalid partition '%c'\n", partition); 613 return EINVAL; 614 } 615 part = partition - 'a'; 616 pp = &bootdev_dip->disklabel.d_partitions[part]; 617 if (pp->p_fstype == FS_UNUSED || pp->p_size == 0) { 618 printf("invalid partition '%c'\n", partition); 619 return EINVAL; 620 } 621 bootdev_dip->sr_vol->sbv_part = partition; 622 } else 623 bootdev_dip->sr_vol->sbv_part = 'a'; 624 625 of->f_dev = devsw; 626 of->f_devdata = &ofdev; 627 628#ifdef SPARC_BOOT_UFS 629 bcopy(&file_system_ufs, &file_system[nfsys++], sizeof file_system[0]); 630 bcopy(&file_system_ufs2, &file_system[nfsys++], sizeof file_system[0]); 631#else 632#error "-DSOFTRAID requires -DSPARC_BOOT_UFS" 633#endif 634 return 0; 635 } 636#endif 637 if ((dhandle = OF_finddevice(fname)) == -1) 638 return ENOENT; 639 640 DNPRINTF(BOOT_D_OFDEV, "devopen: found %s\n", fname); 641 if (OF_getprop(dhandle, "name", buf, sizeof buf) < 0) 642 return ENXIO; 643 DNPRINTF(BOOT_D_OFDEV, "devopen: %s is called %s\n", fname, buf); 644 if (OF_getprop(dhandle, "device_type", buf, sizeof buf) < 0) 645 return ENXIO; 646 DNPRINTF(BOOT_D_OFDEV, "devopen: %s is a %s device\n", fname, buf); 647 DNPRINTF(BOOT_D_OFDEV, "devopen: opening %s\n", fname); 648 if ((ihandle = OF_open(fname)) == -1) { 649 DNPRINTF(BOOT_D_OFDEV, "devopen: open of %s failed\n", fname); 650 return ENXIO; 651 } 652 DNPRINTF(BOOT_D_OFDEV, "devopen: %s is now open\n", fname); 653 bzero(&ofdev, sizeof ofdev); 654 ofdev.handle = ihandle; 655 ofdev.type = OFDEV_DISK; 656 ofdev.bsize = DEV_BSIZE; 657 if (!strcmp(buf, "block")) { 658 error = load_disklabel(&ofdev, &label); 659 if (error && error != ERDLAB) 660 goto bad; 661 else if (error == ERDLAB) { 662 if (partition) 663 /* User specified a partition, but there is none */ 664 goto bad; 665 /* No, label, just use complete disk */ 666 ofdev.partoff = 0; 667 } else { 668 part = partition ? partition - 'a' : 0; 669 ofdev.partoff = label.d_partitions[part].p_offset; 670 DNPRINTF(BOOT_D_OFDEV, "devopen: setting partition %d " 671 "offset %x\n", part, ofdev.partoff); 672 } 673 674 of->f_dev = devsw; 675 of->f_devdata = &ofdev; 676 677 /* Some PROMS have buggy writing code for IDE block devices */ 678 parent = OF_parent(dhandle); 679 if (parent && OF_getprop(parent, "device_type", buf, 680 sizeof(buf)) > 0 && strcmp(buf, "ide") == 0) { 681 DNPRINTF(BOOT_D_OFDEV, 682 "devopen: Disable writing for IDE block device\n"); 683 of->f_flags |= F_NOWRITE; 684 } 685 686#ifdef SPARC_BOOT_UFS 687 bcopy(&file_system_ufs, &file_system[nfsys++], sizeof file_system[0]); 688 bcopy(&file_system_ufs2, &file_system[nfsys++], sizeof file_system[0]); 689#endif 690#ifdef SPARC_BOOT_HSFS 691 bcopy(&file_system_cd9660, &file_system[nfsys++], 692 sizeof file_system[0]); 693#endif 694 DNPRINTF(BOOT_D_OFDEV, "devopen: return 0\n"); 695 return 0; 696 } 697#ifdef NETBOOT 698 if (!strcmp(buf, "network")) { 699 ofdev.type = OFDEV_NET; 700 of->f_dev = devsw; 701 of->f_devdata = &ofdev; 702 bcopy(&file_system_nfs, file_system, sizeof file_system[0]); 703 nfsys = 1; 704 if ((error = net_open(&ofdev))) 705 goto bad; 706 return 0; 707 } 708#endif 709 error = EFTYPE; 710bad: 711 DNPRINTF(BOOT_D_OFDEV, "devopen: error %d, cannot open device\n", 712 error); 713 OF_close(ihandle); 714 ofdev.handle = -1; 715 return error; 716} 717