1 /* $NetBSD: ofdev.c,v 1.37 2017/09/15 13:25:34 martin Exp $ */ 2 3 /* 4 * Copyright (C) 1995, 1996 Wolfgang Solfrank. 5 * Copyright (C) 1995, 1996 TooLs GmbH. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by TooLs GmbH. 19 * 4. The name of TooLs GmbH may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 /* 34 * Device I/O routines using Open Firmware 35 */ 36 #include <sys/param.h> 37 #include <sys/disklabel.h> 38 #ifdef NETBOOT 39 #include <netinet/in.h> 40 #endif 41 42 #include <lib/libsa/stand.h> 43 #include <lib/libsa/ufs.h> 44 #include <lib/libsa/lfs.h> 45 #include <lib/libsa/cd9660.h> 46 #ifdef NETBOOT 47 #include <lib/libsa/nfs.h> 48 #include <lib/libsa/tftp.h> 49 #endif 50 #include <lib/libkern/libkern.h> 51 52 #include <dev/sun/disklabel.h> 53 #include <dev/raidframe/raidframevar.h> 54 55 #include <machine/promlib.h> 56 57 #include "ofdev.h" 58 #include "boot.h" 59 #include "net.h" 60 61 extern char bootdev[]; 62 extern bool root_fs_quickseekable; 63 64 struct btinfo_bootdev_unit bi_unit; 65 bool bootinfo_pass_bootunit = false; 66 67 /* 68 * This is ugly. A path on a sparc machine is something like this: 69 * 70 * [device] [-<options] [path] [-options] [otherstuff] [-<more options] 71 * 72 */ 73 74 char * 75 filename(char *str, char *ppart) 76 { 77 char *cp, *lp; 78 char savec; 79 int dhandle; 80 char devtype[16]; 81 82 lp = str; 83 devtype[0] = 0; 84 *ppart = '\0'; 85 for (cp = str; *cp; lp = cp) { 86 /* For each component of the path name... */ 87 while (*++cp && *cp != '/'); 88 savec = *cp; 89 *cp = 0; 90 /* ...look whether there is a device with this name */ 91 dhandle = prom_finddevice(str); 92 DPRINTF(("filename: prom_finddevice(%s) returned %x\n", 93 str, dhandle)); 94 *cp = savec; 95 if (dhandle == -1) { 96 /* 97 * if not, lp is the delimiter between device and 98 * path. if the last component was a block device. 99 */ 100 if (strcmp(devtype, "block") == 0 101 || strcmp(devtype, "scsi") == 0) { 102 /* search for arguments */ 103 DPRINTF(("filename: hunting for arguments " 104 "in %s\n", lp)); 105 for (cp = lp; ; ) { 106 cp--; 107 if (cp < str || 108 cp[0] == '/' || 109 (cp[0] == ' ' && (cp+1) != lp && 110 cp[1] == '-')) 111 break; 112 } 113 if (cp >= str && *cp == '-') 114 /* found arguments, make firmware 115 ignore them */ 116 *cp = 0; 117 for (cp = lp; *--cp && *cp != ',' 118 && *cp != ':';) 119 ; 120 if (cp[0] == ':' && cp[1] >= 'a' && 121 cp[1] <= 'a' + MAXPARTITIONS) { 122 *ppart = cp[1]; 123 cp[0] = '\0'; 124 } 125 } 126 DPRINTF(("filename: found %s\n",lp)); 127 return lp; 128 } else if (_prom_getprop(dhandle, "device_type", devtype, 129 sizeof devtype) < 0) 130 devtype[0] = 0; 131 } 132 DPRINTF(("filename: not found\n")); 133 return 0; 134 } 135 136 static int 137 strategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf, size_t *rsize) 138 { 139 struct of_dev *dev = devdata; 140 u_quad_t pos; 141 int n; 142 143 if (rw != F_READ) 144 return EPERM; 145 if (dev->type != OFDEV_DISK) 146 panic("strategy"); 147 148 #ifdef NON_DEBUG 149 printf("strategy: block %lx, partition offset %lx, blksz %lx\n", 150 (long)blk, (long)dev->partoff, (long)dev->bsize); 151 printf("strategy: seek position should be: %lx\n", 152 (long)((blk + dev->partoff) * dev->bsize)); 153 #endif 154 pos = (u_quad_t)(blk + dev->partoff) * dev->bsize; 155 156 for (;;) { 157 #ifdef NON_DEBUG 158 printf("strategy: seeking to %lx\n", (long)pos); 159 #endif 160 if (prom_seek(dev->handle, pos) < 0) 161 break; 162 #ifdef NON_DEBUG 163 printf("strategy: reading %lx at %p\n", (long)size, buf); 164 #endif 165 n = prom_read(dev->handle, buf, size); 166 if (n == -2) 167 continue; 168 if (n < 0) 169 break; 170 *rsize = n; 171 return 0; 172 } 173 return EIO; 174 } 175 176 static int 177 devclose(struct open_file *of) 178 { 179 struct of_dev *op = of->f_devdata; 180 181 #ifdef NETBOOT 182 if (op->type == OFDEV_NET) 183 net_close(op); 184 #endif 185 prom_close(op->handle); 186 op->handle = -1; 187 return 0; 188 } 189 190 static struct devsw ofdevsw[1] = { 191 { 192 "OpenFirmware", 193 strategy, 194 (int (*)(struct open_file *, ...))nodev, 195 devclose, 196 noioctl 197 } 198 }; 199 int ndevs = sizeof ofdevsw / sizeof ofdevsw[0]; 200 201 202 #ifdef SPARC_BOOT_UFS 203 static struct fs_ops file_system_ufs[] = 204 { FS_OPS(ufs), FS_OPS(ffsv2), FS_OPS(lfsv1), FS_OPS(lfsv2) }; 205 #endif 206 #ifdef SPARC_BOOT_CD9660 207 static struct fs_ops file_system_cd9660 = FS_OPS(cd9660); 208 #endif 209 #ifdef NETBOOT 210 static struct fs_ops file_system_nfs = FS_OPS(nfs); 211 static struct fs_ops file_system_tftp = FS_OPS(tftp); 212 #endif 213 214 struct fs_ops file_system[7]; 215 int nfsys; 216 217 static struct of_dev ofdev = { 218 -1, 219 }; 220 221 char opened_name[256]; 222 int floppyboot; 223 224 /************************************************************************ 225 * 226 * The rest of this was taken from arch/sparc64/scsi/sun_disklabel.c 227 * and then substantially rewritten by Gordon W. Ross 228 * 229 ************************************************************************/ 230 231 /* What partition types to assume for Sun disklabels: */ 232 static u_char 233 sun_fstypes[8] = { 234 FS_BSDFFS, /* a */ 235 FS_SWAP, /* b */ 236 FS_OTHER, /* c - whole disk */ 237 FS_BSDFFS, /* d */ 238 FS_BSDFFS, /* e */ 239 FS_BSDFFS, /* f */ 240 FS_BSDFFS, /* g */ 241 FS_BSDFFS, /* h */ 242 }; 243 244 /* 245 * Given a SunOS disk label, set lp to a BSD disk label. 246 * Returns NULL on success, else an error string. 247 * 248 * The BSD label is cleared out before this is called. 249 */ 250 static char * 251 disklabel_sun_to_bsd(char *cp, struct disklabel *lp) 252 { 253 struct sun_disklabel *sl; 254 struct partition *npp; 255 struct sun_dkpart *spp; 256 int i, secpercyl; 257 u_short cksum, *sp1, *sp2; 258 259 sl = (struct sun_disklabel *)cp; 260 261 /* Verify the XOR check. */ 262 sp1 = (u_short *)sl; 263 sp2 = (u_short *)(sl + 1); 264 cksum = 0; 265 while (sp1 < sp2) 266 cksum ^= *sp1++; 267 if (cksum != 0) 268 return("SunOS disk label, bad checksum"); 269 270 /* Format conversion. */ 271 lp->d_magic = DISKMAGIC; 272 lp->d_magic2 = DISKMAGIC; 273 memcpy(lp->d_packname, sl->sl_text, sizeof(lp->d_packname)); 274 275 lp->d_secsize = 512; 276 lp->d_nsectors = sl->sl_nsectors; 277 lp->d_ntracks = sl->sl_ntracks; 278 lp->d_ncylinders = sl->sl_ncylinders; 279 280 secpercyl = sl->sl_nsectors * sl->sl_ntracks; 281 lp->d_secpercyl = secpercyl; 282 lp->d_secperunit = secpercyl * sl->sl_ncylinders; 283 284 lp->d_sparespercyl = sl->sl_sparespercyl; 285 lp->d_acylinders = sl->sl_acylinders; 286 lp->d_rpm = sl->sl_rpm; 287 lp->d_interleave = sl->sl_interleave; 288 289 lp->d_npartitions = 8; 290 /* These are as defined in <ufs/ffs/fs.h> */ 291 lp->d_bbsize = 8192; /* XXX */ 292 lp->d_sbsize = 8192; /* XXX */ 293 294 for (i = 0; i < 8; i++) { 295 spp = &sl->sl_part[i]; 296 npp = &lp->d_partitions[i]; 297 npp->p_offset = spp->sdkp_cyloffset * secpercyl; 298 npp->p_size = spp->sdkp_nsectors; 299 DPRINTF(("partition %d start %x size %x\n", i, (int)npp->p_offset, (int)npp->p_size)); 300 if (npp->p_size == 0) { 301 npp->p_fstype = FS_UNUSED; 302 } else { 303 npp->p_fstype = sun_fstypes[i]; 304 if (npp->p_fstype == FS_BSDFFS) { 305 /* 306 * The sun label does not store the FFS fields, 307 * so just set them with default values here. 308 */ 309 npp->p_fsize = 1024; 310 npp->p_frag = 8; 311 npp->p_cpg = 16; 312 } 313 } 314 } 315 316 lp->d_checksum = 0; 317 lp->d_checksum = dkcksum(lp); 318 DPRINTF(("disklabel_sun_to_bsd: success!\n")); 319 return (NULL); 320 } 321 322 /* 323 * Find a valid disklabel. 324 */ 325 static char * 326 search_label(struct of_dev *devp, u_long off, char *buf, 327 struct disklabel *lp, u_long off0) 328 { 329 size_t readsize; 330 struct disklabel *dlp; 331 struct sun_disklabel *slp; 332 333 /* minimal requirements for archtypal disk label */ 334 if (lp->d_secperunit == 0) 335 lp->d_secperunit = 0x1fffffff; 336 lp->d_npartitions = 1; 337 if (lp->d_partitions[0].p_size == 0) 338 lp->d_partitions[0].p_size = 0x1fffffff; 339 lp->d_partitions[0].p_offset = 0; 340 341 if (strategy(devp, F_READ, LABELSECTOR, DEV_BSIZE, buf, &readsize) 342 || readsize != DEV_BSIZE) 343 return ("Cannot read label"); 344 /* Check for a NetBSD disk label. */ 345 dlp = (struct disklabel *) (buf + LABELOFFSET); 346 if (dlp->d_magic == DISKMAGIC) { 347 if (dkcksum(dlp)) 348 return ("NetBSD disk label corrupted"); 349 *lp = *dlp; 350 DPRINTF(("search_label: found NetBSD label\n")); 351 return (NULL); 352 } 353 354 /* Check for a Sun disk label (for PROM compatibility). */ 355 slp = (struct sun_disklabel *) buf; 356 if (slp->sl_magic == SUN_DKMAGIC) 357 return (disklabel_sun_to_bsd(buf, lp)); 358 359 360 memset(buf, 0, DEV_BSIZE); 361 return ("no disk label"); 362 } 363 364 static void 365 device_target_unit(const char *dev, int ihandle) 366 { 367 cell_t units[4], phandle, myself, depth = 0, odepth = 0, cnt; 368 char buf[256]; 369 370 /* init the data passed to the kernel */ 371 bootinfo_pass_bootunit = false; 372 memset(&bi_unit, 0, sizeof(bi_unit)); 373 374 /* save old my-self value */ 375 OF_interpret("my-self", 0, 1, &myself); 376 /* set our device as my-self */ 377 OF_interpret("to my-self", 1, 0, HDL2CELL(ihandle)); 378 379 /* 380 * my-unit delivers a variable number of cells, we could 381 * walk up the path and find a #address-cells value that 382 * describes it, but it seems to just work this simple 383 * way. 384 */ 385 OF_interpret("depth", 0, 1, &odepth); 386 OF_interpret("my-unit depth", 0, 5, &depth, 387 &units[0], &units[1], &units[2], &units[3]); 388 cnt = depth-odepth; 389 390 /* 391 * Old versions of QEMU's OpenBIOS have a bug in the 392 * CIF implementation for instance_to_package, test 393 * for that explicitly here and work around it if needed. 394 */ 395 phandle = OF_instance_to_package(ihandle); 396 OF_package_to_path(phandle, buf, sizeof(buf)); 397 buf[sizeof(buf)-1] = 0; 398 if (strlen(buf) > 2 && strlen(dev) > 2 && 399 strncmp(buf, dev, strlen(buf)) != 0) { 400 DPRINTF(("OpenBIOS workaround: phandle %" PRIx32 "is %s, " 401 "does not match %s\n", (uint32_t)phandle, buf, dev)); 402 OF_interpret("my-self ihandle>non-interposed-phandle", 403 0, 1, &phandle); 404 OF_package_to_path(phandle, buf, sizeof(buf)); 405 DPRINTF(("new phandle %" PRIx32 " is %s\n", 406 (uint32_t)phandle, buf)); 407 } 408 409 bi_unit.phandle = phandle; 410 bi_unit.parent = OF_parent(phandle); 411 bi_unit.lun = units[cnt > 2 ? 3 : 1]; 412 bi_unit.target = units[cnt > 2 ? 2 : 0]; 413 if (cnt >= 4) 414 bi_unit.wwn = (uint64_t)units[0] << 32 | (uint32_t)units[1]; 415 DPRINTF(("boot device package: %" PRIx32 ", parent: %" PRIx32 416 ", lun: %" PRIu32 ", target: %" PRIu32 ", wwn: %" PRIx64 "\n", 417 bi_unit.phandle, bi_unit.parent, bi_unit.lun, bi_unit.target, 418 bi_unit.wwn)); 419 420 /* restore my-self */ 421 OF_interpret("to my-self", 1, 0, myself); 422 423 /* now that we have gatherd all the details, pass them to the kernel */ 424 bootinfo_pass_bootunit = true; 425 } 426 427 int 428 devopen(struct open_file *of, const char *name, char **file) 429 { 430 char *cp; 431 char partition; 432 char fname[256], devname[256]; 433 union { 434 char buf[DEV_BSIZE]; 435 struct disklabel label; 436 } b; 437 struct disklabel label; 438 int handle, part, try = 0; 439 size_t readsize; 440 char *errmsg = NULL, *pp = NULL, savedpart = 0; 441 int error = 0; 442 bool get_target_unit = false; 443 444 if (ofdev.handle != -1) 445 panic("devopen: ofdev already in use"); 446 if (of->f_flags != F_READ) 447 return EPERM; 448 DPRINTF(("devopen: you want %s\n", name)); 449 strcpy(fname, name); 450 cp = filename(fname, &partition); 451 if (cp) { 452 strcpy(b.buf, cp); 453 *cp = 0; 454 } 455 if (!cp || !b.buf[0]) 456 strcpy(b.buf, DEFAULT_KERNEL); 457 if (!*fname) 458 strcpy(fname, bootdev); 459 strcpy(opened_name, fname); 460 if (partition) { 461 cp = opened_name + strlen(opened_name); 462 *cp++ = ':'; 463 *cp++ = partition; 464 *cp = 0; 465 } 466 *file = opened_name + strlen(opened_name); 467 if (b.buf[0] != '/') 468 strcat(opened_name, "/"); 469 strcat(opened_name, b.buf); 470 DPRINTF(("devopen: trying %s\n", fname)); 471 if ((handle = prom_finddevice(fname)) == -1) 472 return ENOENT; 473 DPRINTF(("devopen: found %s\n", fname)); 474 if (_prom_getprop(handle, "name", b.buf, sizeof b.buf) < 0) 475 return ENXIO; 476 DPRINTF(("devopen: %s is called %s\n", fname, b.buf)); 477 floppyboot = !strcmp(b.buf, "floppy"); 478 if (_prom_getprop(handle, "device_type", b.buf, sizeof b.buf) < 0) 479 return ENXIO; 480 DPRINTF(("devopen: %s is a %s device\n", fname, b.buf)); 481 if (strcmp(b.buf, "block") == 0 || strcmp(b.buf, "scsi") == 0) { 482 483 get_target_unit = true; 484 485 pp = strrchr(fname, ':'); 486 if (pp && pp[1] >= 'a' && pp[1] <= 'f' && pp[2] == 0) { 487 savedpart = pp[1]; 488 } else { 489 savedpart = 'a'; 490 handle = prom_open(fname); 491 if (handle != -1) { 492 OF_instance_to_path(handle, devname, 493 sizeof(devname)); 494 DPRINTF(("real path: %s\n", devname)); 495 prom_close(handle); 496 pp = devname + strlen(devname); 497 if (pp > devname + 3) pp -= 2; 498 if (pp[0] == ':') 499 savedpart = pp[1]; 500 } 501 pp = fname + strlen(fname); 502 pp[0] = ':'; 503 pp[2] = '\0'; 504 } 505 pp[1] = 'c'; 506 DPRINTF(("devopen: replacing by whole disk device %s\n", 507 fname)); 508 if (savedpart) 509 partition = savedpart; 510 } 511 512 open_again: 513 DPRINTF(("devopen: opening %s\n", fname)); 514 if ((handle = prom_open(fname)) == -1) { 515 DPRINTF(("devopen: open of %s failed\n", fname)); 516 if (pp && savedpart) { 517 if (try == 0) { 518 pp[0] = '\0'; 519 try = 1; 520 } else { 521 pp[0] = ':'; 522 pp[1] = savedpart; 523 pp = NULL; 524 savedpart = '\0'; 525 } 526 goto open_again; 527 } 528 return ENXIO; 529 } 530 DPRINTF(("devopen: %s is now open\n", fname)); 531 532 if (get_target_unit) 533 device_target_unit(fname, handle); 534 535 memset(&ofdev, 0, sizeof ofdev); 536 ofdev.handle = handle; 537 if (strcmp(b.buf, "block") == 0 || strcmp(b.buf, "scsi") == 0) { 538 ofdev.type = OFDEV_DISK; 539 ofdev.bsize = DEV_BSIZE; 540 /* First try to find a disklabel without MBR partitions */ 541 DPRINTF(("devopen: trying to read disklabel\n")); 542 if (strategy(&ofdev, F_READ, 543 LABELSECTOR, DEV_BSIZE, b.buf, &readsize) != 0 544 || readsize != DEV_BSIZE 545 || (errmsg = getdisklabel(b.buf, &label))) { 546 if (errmsg) { 547 DPRINTF(("devopen: getdisklabel returned %s\n", 548 errmsg)); 549 } 550 /* Else try MBR partitions */ 551 errmsg = search_label(&ofdev, 0, b.buf, &label, 0); 552 if (errmsg) { 553 printf("devopen: search_label returned %s\n", errmsg); 554 error = ERDLAB; 555 } 556 if (error && error != ERDLAB) 557 goto bad; 558 } 559 560 if (error == ERDLAB) { 561 /* No, label, just use complete disk */ 562 ofdev.partoff = 0; 563 if (pp && savedpart) { 564 pp[1] = savedpart; 565 prom_close(handle); 566 if ((handle = prom_open(fname)) == -1) { 567 DPRINTF(("devopen: open of %s failed\n", 568 fname)); 569 return ENXIO; 570 } 571 ofdev.handle = handle; 572 DPRINTF(("devopen: back to original device %s\n", 573 fname)); 574 } 575 } else { 576 part = partition ? partition - 'a' : 0; 577 ofdev.partoff = label.d_partitions[part].p_offset; 578 DPRINTF(("devopen: setting partition %d offset %lx\n", 579 part, ofdev.partoff)); 580 if (label.d_partitions[part].p_fstype == FS_RAID) { 581 ofdev.partoff += RF_PROTECTED_SECTORS; 582 DPRINTF(("devopen: found RAID partition, " 583 "adjusting offset to %lx\n", ofdev.partoff)); 584 } 585 } 586 587 nfsys = 0; 588 of->f_dev = ofdevsw; 589 of->f_devdata = &ofdev; 590 #ifdef SPARC_BOOT_UFS 591 memcpy(&file_system[nfsys++], &file_system_ufs[0], sizeof file_system[0]); 592 memcpy(&file_system[nfsys++], &file_system_ufs[1], sizeof file_system[0]); 593 memcpy(&file_system[nfsys++], &file_system_ufs[2], sizeof file_system[0]); 594 memcpy(&file_system[nfsys++], &file_system_ufs[3], sizeof file_system[0]); 595 #endif 596 #ifdef SPARC_BOOT_CD9660 597 memcpy(&file_system[nfsys++], &file_system_cd9660, sizeof file_system[0]); 598 #endif 599 DPRINTF(("devopen: return 0\n")); 600 return 0; 601 } 602 #ifdef NETBOOT 603 if (!strcmp(b.buf, "network")) { 604 if ((error = net_open(&ofdev)) != 0) 605 goto bad; 606 607 ofdev.type = OFDEV_NET; 608 of->f_dev = ofdevsw; 609 of->f_devdata = &ofdev; 610 611 if (!strncmp(*file,"/tftp:",6)) { 612 *file += 6; 613 memcpy(&file_system[0], &file_system_tftp, sizeof file_system[0]); 614 if (net_tftp_bootp((int **)&of->f_devdata)) { 615 net_close(&ofdev); 616 goto bad; 617 } 618 root_fs_quickseekable = false; 619 } else { 620 memcpy(&file_system[0], &file_system_nfs, sizeof file_system[0]); 621 if ((error = net_mountroot()) != 0) { 622 net_close(&ofdev); 623 goto bad; 624 } 625 } 626 nfsys = 1; 627 return 0; 628 } 629 #endif 630 error = EFTYPE; 631 bad: 632 DPRINTF(("devopen: error %d, cannot open device\n", error)); 633 prom_close(handle); 634 ofdev.handle = -1; 635 return error; 636 } 637