1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * Copyright 2026 Oxide Computer Company 26 */ 27 28 29 #include <stdio.h> 30 #include <string.h> 31 #include <strings.h> 32 #include <unistd.h> 33 #include <stdlib.h> 34 #include <thread.h> 35 #include <synch.h> 36 #include <sys/types.h> 37 #include <ctype.h> 38 #include <sys/stat.h> 39 #include <fcntl.h> 40 #include <sys/modctl.h> 41 #include <errno.h> 42 #include <sys/openpromio.h> 43 #include <ftw.h> 44 #include <sys/ddi.h> 45 #include <sys/sunddi.h> 46 #include <sys/debug.h> 47 #include <limits.h> 48 49 #include "device_info.h" 50 51 /* 52 * #define's 53 */ 54 55 /* alias node searching return values */ 56 #define NO_MATCH -1 57 #define EXACT_MATCH 1 58 #define INEXACT_MATCH 2 59 60 /* for prom io operations */ 61 #define BUFSIZE 4096 62 #define MAXPROPSIZE 256 63 #define MAXVALSIZE (BUFSIZE - MAXPROPSIZE - sizeof (uint_t)) 64 CTASSERT(MAXVALSIZE <= BUFSIZE - sizeof (struct openpromio)); 65 66 /* prom_obp_vers() return values */ 67 #define OBP_OF 0x4 /* versions OBP 3.x */ 68 #define OBP_NO_ALIAS_NODE 0x8 /* No alias node */ 69 70 /* for nftw call */ 71 #define FT_DEPTH 15 72 73 /* default logical and physical device name space */ 74 #define DEV "/dev" 75 #define DEVICES "/devices" 76 77 /* for boot device identification on x86 */ 78 #define CREATE_DISKMAP "/boot/solaris/bin/create_diskmap" 79 #define GRUBDISK_MAP "/var/run/solaris_grubdisk.map" 80 81 /* 82 * internal structure declarations 83 */ 84 85 /* for prom io functions */ 86 typedef union { 87 char buf[BUFSIZE]; 88 struct openpromio opp; 89 } Oppbuf; 90 91 /* used to manage lists of devices and aliases */ 92 struct name_list { 93 char *name; 94 struct name_list *next; 95 }; 96 97 /* 98 * internal global data 99 */ 100 101 /* global since nftw does not let you pass args to be updated */ 102 static struct name_list **dev_list; 103 104 /* global since nftw does not let you pass args to be updated */ 105 static struct boot_dev **bootdev_list; 106 107 /* mutex to protect bootdev_list and dev_list */ 108 static mutex_t dev_lists_lk = DEFAULTMUTEX; 109 110 /* 111 * internal function prototypes 112 */ 113 114 static int prom_open(int); 115 static void prom_close(int); 116 static int is_openprom(int); 117 118 static int prom_dev_to_alias(char *dev, uint_t options, char ***ret_buf); 119 static int alias_to_prom_dev(char *alias, char *ret_buf); 120 static int prom_srch_aliases_by_def(char *, struct name_list **, 121 struct name_list **, int); 122 static int prom_find_aliases_node(int fd); 123 static int prom_compare_devs(char *prom_dev1, char *prom_dev2); 124 static int _prom_strcmp(char *s1, char *s2); 125 static int prom_srch_node(int fd, char *prop_name, char *ret_buf); 126 static uint_t prom_next_node(int fd, uint_t node_id); 127 static uint_t prom_child_node(int fd, uint_t node_id); 128 129 static int prom_obp_vers(void); 130 131 static void parse_name(char *, char **, char **, char **); 132 static int process_bootdev(const char *, const char *, struct boot_dev ***); 133 static int process_minor_name(char *dev_path, const char *default_root); 134 static void options_override(char *prom_path, char *alias_name); 135 static int devfs_phys_to_logical(struct boot_dev **bootdev_array, 136 const int array_size, const char *default_root); 137 static int check_logical_dev(const char *, const struct stat *, int, 138 struct FTW *); 139 static struct boot_dev *alloc_bootdev(char *); 140 static void free_name_list(struct name_list *list, int free_name); 141 static int insert_alias_list(struct name_list **list, 142 char *alias_name); 143 static int get_boot_dev_var(struct openpromio *opp); 144 static int set_boot_dev_var(struct openpromio *opp, char *bootdev); 145 static int devfs_prom_to_dev_name(char *prom_path, char *dev_path); 146 static int devfs_dev_to_prom_names(char *dev_path, char *prom_path, size_t len); 147 148 /* 149 * frees a list of paths from devfs_get_prom_name_list 150 */ 151 static void 152 prom_list_free(char **prom_list) 153 { 154 int i = 0; 155 156 if (!prom_list) 157 return; 158 159 while (prom_list[i]) { 160 free(prom_list[i]); 161 i++; 162 } 163 free(prom_list); 164 } 165 166 static int 167 devfs_get_prom_name_list(const char *dev_name, char ***prom_list) 168 { 169 char *prom_path = NULL; 170 int count = 0; /* # of slots we will need in prom_list */ 171 int ret, i, len; 172 char **list; 173 char *ptr; 174 175 if (dev_name == NULL) 176 return (DEVFS_INVAL); 177 if (*dev_name != '/') 178 return (DEVFS_INVAL); 179 if (prom_list == NULL) 180 return (DEVFS_INVAL); 181 182 /* 183 * make sure we are on a machine which supports a prom 184 * and we have permission to use /dev/openprom 185 */ 186 if ((ret = prom_obp_vers()) < 0) 187 return (ret); 188 if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL) 189 return (DEVFS_NOMEM); 190 /* 191 * get the prom path name 192 */ 193 ret = devfs_dev_to_prom_names((char *)dev_name, prom_path, MAXVALSIZE); 194 if (ret < 0) { 195 free(prom_path); 196 return (ret); 197 } 198 /* deal with list of names */ 199 for (i = 0; i < ret; i++) 200 if (prom_path[i] == '\0') 201 count++; 202 203 if ((list = (char **)calloc(count + 1, sizeof (char *))) == NULL) { 204 free(prom_path); 205 return (DEVFS_NOMEM); 206 } 207 208 ptr = prom_path; 209 for (i = 0; i < count; i++) { 210 len = strlen(ptr) + 1; 211 if ((list[i] = (char *)malloc(len)) == NULL) { 212 free(prom_path); 213 free(list); 214 return (DEVFS_NOMEM); 215 } 216 (void) snprintf(list[i], len, "%s", ptr); 217 ptr += len; 218 } 219 220 free(prom_path); 221 222 *prom_list = list; 223 return (0); 224 } 225 226 /* 227 * retrieve the list of prom representations for a given device name 228 * the list will be sorted in the following order: exact aliases, 229 * inexact aliases, prom device path name. If multiple matches occur 230 * for exact or inexact aliases, then these are sorted in collating 231 * order. The list is returned in prom_list 232 * 233 * the list may be restricted by specifying the correct flags in options. 234 */ 235 int 236 devfs_get_prom_names(const char *dev_name, uint_t options, char ***prom_list) 237 { 238 char *prom_path = NULL; 239 int count = 0; /* # of slots we will need in prom_list */ 240 char **alias_list = NULL; 241 char **list; 242 int ret; 243 244 if (dev_name == NULL) { 245 return (DEVFS_INVAL); 246 } 247 if (*dev_name != '/') { 248 return (DEVFS_INVAL); 249 } 250 if (prom_list == NULL) { 251 return (DEVFS_INVAL); 252 } 253 /* 254 * make sure we are on a machine which supports a prom 255 * and we have permission to use /dev/openprom 256 */ 257 if ((ret = prom_obp_vers()) < 0) { 258 return (ret); 259 } 260 if ((prom_path = (char *)malloc(MAXPATHLEN)) == NULL) { 261 return (DEVFS_NOMEM); 262 } 263 /* 264 * get the prom path name 265 */ 266 ret = devfs_dev_to_prom_name((char *)dev_name, prom_path); 267 if (ret < 0) { 268 free(prom_path); 269 return (ret); 270 } 271 /* get the list of aliases (exact and inexact) */ 272 if ((ret = prom_dev_to_alias(prom_path, options, &alias_list)) < 0) { 273 free(prom_path); 274 return (ret); 275 } 276 /* now figure out how big the return array must be */ 277 if (alias_list != NULL) { 278 while (alias_list[count] != NULL) { 279 count++; 280 } 281 } 282 if ((options & BOOTDEV_NO_PROM_PATH) == 0) { 283 count++; /* # of slots we will need in prom_list */ 284 } 285 count++; /* for the null terminator */ 286 287 /* allocate space for the list */ 288 if ((list = (char **)calloc(count, sizeof (char *))) == NULL) { 289 count = 0; 290 while ((alias_list) && (alias_list[count] != NULL)) { 291 free(alias_list[count]); 292 count++; 293 } 294 free(alias_list); 295 free(prom_path); 296 return (DEVFS_NOMEM); 297 } 298 /* fill in the array and free the name list of aliases. */ 299 count = 0; 300 while ((alias_list) && (alias_list[count] != NULL)) { 301 list[count] = alias_list[count]; 302 count++; 303 } 304 if ((options & BOOTDEV_NO_PROM_PATH) == 0) { 305 list[count] = prom_path; 306 } 307 if (alias_list != NULL) { 308 free(alias_list); 309 } 310 *prom_list = list; 311 return (0); 312 } 313 314 /* 315 * Get a list prom-path translations for a solaris device. 316 * 317 * Returns the number of and all OBP paths and alias variants that 318 * reference the Solaris device path passed in. 319 */ 320 int 321 devfs_get_all_prom_names(const char *solaris_path, uint_t flags, 322 struct devfs_prom_path **paths) 323 { 324 int ret, len, i, count = 0; 325 char *ptr, *prom_path; 326 struct devfs_prom_path *cur = NULL, *new; 327 328 if ((ret = prom_obp_vers()) < 0) 329 return (ret); 330 if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL) 331 return (DEVFS_NOMEM); 332 333 if ((ret = devfs_dev_to_prom_names((char *)solaris_path, 334 prom_path, MAXVALSIZE)) < 0) { 335 free(prom_path); 336 return (ret); 337 } 338 339 for (i = 0; i < ret; i++) 340 if (prom_path[i] == '\0') 341 count++; 342 343 *paths = NULL; 344 ptr = prom_path; 345 for (i = 0; i < count; i++) { 346 new = calloc(1, sizeof (struct devfs_prom_path)); 347 if (new == NULL) { 348 free(prom_path); 349 devfs_free_all_prom_names(*paths); 350 return (DEVFS_NOMEM); 351 } 352 353 if (cur == NULL) 354 *paths = new; 355 else 356 cur->next = new; 357 cur = new; 358 359 len = strlen(ptr) + 1; 360 if ((cur->obp_path = (char *)calloc(len, 1)) == NULL) { 361 free(prom_path); 362 devfs_free_all_prom_names(*paths); 363 return (DEVFS_NOMEM); 364 } 365 366 (void) snprintf(cur->obp_path, len, "%s", ptr); 367 ptr += len; 368 if ((ret = prom_dev_to_alias(cur->obp_path, flags, 369 &(cur->alias_list))) < 0) { 370 free(prom_path); 371 devfs_free_all_prom_names(*paths); 372 return (ret); 373 } 374 } 375 376 free(prom_path); 377 return (count); 378 } 379 380 void 381 devfs_free_all_prom_names(struct devfs_prom_path *paths) 382 { 383 int i; 384 385 if (paths == NULL) 386 return; 387 388 devfs_free_all_prom_names(paths->next); 389 390 if (paths->obp_path != NULL) 391 free(paths->obp_path); 392 393 if (paths->alias_list != NULL) { 394 for (i = 0; paths->alias_list[i] != NULL; i++) 395 if (paths->alias_list[i] != NULL) 396 free(paths->alias_list[i]); 397 398 free(paths->alias_list); 399 } 400 401 free(paths); 402 } 403 404 /* 405 * Accepts a device name as an input argument. Uses this to set the 406 * boot-device (or like) variable 407 * 408 * By default, this routine prepends to the list and converts the 409 * logical device name to its most compact prom representation. 410 * Available options include: converting the device name to a prom 411 * path name (but not an alias) or performing no conversion at all; 412 * overwriting the existing contents of boot-device rather than 413 * prepending. 414 */ 415 int 416 devfs_bootdev_set_list(const char *dev_name, const uint_t options) 417 { 418 char *prom_path; 419 char *new_bootdev; 420 char *ptr; 421 char **alias_list = NULL; 422 char **prom_list = NULL; 423 Oppbuf oppbuf; 424 struct openpromio *opp = &(oppbuf.opp); 425 int ret, len, i, j; 426 427 if (devfs_bootdev_modifiable() != 0) { 428 return (DEVFS_NOTSUP); 429 } 430 if (dev_name == NULL) { 431 return (DEVFS_INVAL); 432 } 433 if (strlen(dev_name) >= MAXPATHLEN) 434 return (DEVFS_INVAL); 435 436 if ((*dev_name != '/') && !(options & BOOTDEV_LITERAL)) { 437 return (DEVFS_INVAL); 438 } 439 if ((options & BOOTDEV_LITERAL) && (options & BOOTDEV_PROMDEV)) { 440 return (DEVFS_INVAL); 441 } 442 /* 443 * if we are prepending, make sure that this obp rev 444 * supports multiple boot device entries. 445 */ 446 ret = prom_obp_vers(); 447 if (ret < 0) { 448 return (ret); 449 } 450 451 if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL) { 452 return (DEVFS_NOMEM); 453 } 454 if (options & BOOTDEV_LITERAL) { 455 (void) strcpy(prom_path, dev_name); 456 } else { 457 /* need to convert to prom representation */ 458 ret = devfs_get_prom_name_list(dev_name, &prom_list); 459 if (ret < 0) { 460 free(prom_path); 461 return (ret); 462 } 463 464 len = MAXVALSIZE; 465 i = 0; 466 ptr = prom_path; 467 while (prom_list && prom_list[i]) { 468 if (!(options & BOOTDEV_PROMDEV)) { 469 ret = prom_dev_to_alias(prom_list[i], 0, 470 &alias_list); 471 if (ret < 0) { 472 free(prom_path); 473 prom_list_free(prom_list); 474 return (ret); 475 } 476 if ((alias_list != NULL) && 477 (alias_list[0] != NULL)) { 478 (void) snprintf(ptr, len, "%s ", 479 alias_list[0]); 480 for (ret = 0; alias_list[ret] != NULL; 481 ret++) 482 free(alias_list[ret]); 483 } else { 484 (void) snprintf(ptr, len, "%s ", 485 prom_list[i]); 486 } 487 if (alias_list != NULL) 488 free(alias_list); 489 } else { 490 (void) snprintf(ptr, len, "%s ", prom_list[i]); 491 } 492 j = strlen(ptr); 493 len -= j; 494 ptr += j; 495 i++; 496 } 497 ptr--; 498 *ptr = 0; 499 500 prom_list_free(prom_list); 501 } 502 if (options & BOOTDEV_OVERWRITE) { 503 new_bootdev = prom_path; 504 } else { 505 /* retrieve the current value of boot-device */ 506 ret = get_boot_dev_var(opp); 507 if (ret < 0) { 508 free(prom_path); 509 return (ret); 510 } 511 /* prepend new entry - deal with duplicates */ 512 new_bootdev = (char *)malloc(strlen(opp->oprom_array) 513 + strlen(prom_path) + 2); 514 if (new_bootdev == NULL) { 515 free(prom_path); 516 return (DEVFS_NOMEM); 517 } 518 (void) strcpy(new_bootdev, prom_path); 519 if (opp->oprom_size > 0) { 520 for (ptr = strtok(opp->oprom_array, " "); ptr != NULL; 521 ptr = strtok(NULL, " ")) { 522 /* we strip out duplicates */ 523 if (strcmp(prom_path, ptr) == 0) { 524 continue; 525 } 526 (void) strcat(new_bootdev, " "); 527 (void) strcat(new_bootdev, ptr); 528 } 529 } 530 } 531 532 /* now set the new value */ 533 ret = set_boot_dev_var(opp, new_bootdev); 534 535 if (options & BOOTDEV_OVERWRITE) { 536 free(prom_path); 537 } else { 538 free(new_bootdev); 539 free(prom_path); 540 } 541 542 return (ret); 543 } 544 545 /* 546 * sets the string bootdev as the new value for boot-device 547 */ 548 static int 549 set_boot_dev_var(struct openpromio *opp, char *bootdev) 550 { 551 int prom_fd; 552 int i; 553 int ret; 554 char *valbuf; 555 char *save_bootdev; 556 char *bootdev_variables[] = { 557 "boot-device", 558 "bootdev", 559 "boot-from", 560 NULL 561 }; 562 int found = 0; 563 int *ip = (int *)((void *)opp->oprom_array); 564 565 /* query the prom */ 566 prom_fd = prom_open(O_RDWR); 567 if (prom_fd < 0) { 568 return (prom_fd); 569 } 570 571 /* get the diagnostic-mode? property */ 572 (void) strlcpy(opp->oprom_array, "diagnostic-mode?", MAXVALSIZE); 573 opp->oprom_size = MAXVALSIZE; 574 if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) { 575 if ((opp->oprom_size > 0) && 576 (strcmp(opp->oprom_array, "true") == 0)) { 577 prom_close(prom_fd); 578 return (DEVFS_ERR); 579 } 580 } 581 /* get the diag-switch? property */ 582 (void) strlcpy(opp->oprom_array, "diag-switch?", MAXVALSIZE); 583 opp->oprom_size = MAXVALSIZE; 584 if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) { 585 if ((opp->oprom_size > 0) && 586 (strcmp(opp->oprom_array, "true") == 0)) { 587 prom_close(prom_fd); 588 return (DEVFS_ERR); 589 } 590 } 591 /* 592 * look for one of the following properties in order: 593 * boot-device 594 * bootdev 595 * boot-from 596 * 597 * Use the first one that we find. 598 */ 599 *ip = 0; 600 opp->oprom_size = MAXPROPSIZE; 601 while ((opp->oprom_size != 0) && (!found)) { 602 opp->oprom_size = MAXPROPSIZE; 603 if (ioctl(prom_fd, OPROMNXTOPT, opp) < 0) { 604 break; 605 } 606 for (i = 0; bootdev_variables[i] != NULL; i++) { 607 if (strcmp(opp->oprom_array, bootdev_variables[i]) 608 == 0) { 609 found = 1; 610 break; 611 } 612 } 613 } 614 if (found) { 615 (void) strlcpy(opp->oprom_array, bootdev_variables[i], 616 MAXVALSIZE); 617 opp->oprom_size = MAXVALSIZE; 618 if (ioctl(prom_fd, OPROMGETOPT, opp) < 0) { 619 prom_close(prom_fd); 620 return (DEVFS_NOTSUP); 621 } 622 } else { 623 prom_close(prom_fd); 624 return (DEVFS_NOTSUP); 625 } 626 627 /* save the old copy in case we fail */ 628 if ((save_bootdev = strdup(opp->oprom_array)) == NULL) { 629 prom_close(prom_fd); 630 return (DEVFS_NOMEM); 631 } 632 /* set up the new value of boot-device */ 633 (void) strlcpy(opp->oprom_array, bootdev_variables[i], MAXVALSIZE); 634 valbuf = opp->oprom_array + strlen(opp->oprom_array) + 1; 635 (void) strlcpy(valbuf, bootdev, 636 MAXVALSIZE - strlen(opp->oprom_array) - 1); 637 638 opp->oprom_size = strlen(valbuf) + strlen(opp->oprom_array) + 2; 639 640 if (ioctl(prom_fd, OPROMSETOPT, opp) < 0) { 641 free(save_bootdev); 642 prom_close(prom_fd); 643 return (DEVFS_ERR); 644 } 645 646 /* 647 * now read it back to make sure it took 648 */ 649 (void) strlcpy(opp->oprom_array, bootdev_variables[i], MAXVALSIZE); 650 opp->oprom_size = MAXVALSIZE; 651 if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) { 652 if (_prom_strcmp(opp->oprom_array, bootdev) == 0) { 653 /* success */ 654 free(save_bootdev); 655 prom_close(prom_fd); 656 return (0); 657 } 658 /* deal with setting it to "" */ 659 if ((strlen(bootdev) == 0) && (opp->oprom_size == 0)) { 660 /* success */ 661 free(save_bootdev); 662 prom_close(prom_fd); 663 return (0); 664 } 665 } 666 /* 667 * something did not take - write out the old value and 668 * hope that we can restore things... 669 * 670 * unfortunately, there is no way for us to differentiate 671 * whether we exceeded the maximum number of characters 672 * allowable. The limit varies from prom rev to prom 673 * rev, and on some proms, when the limit is 674 * exceeded, whatever was in the 675 * boot-device variable becomes unreadable. 676 * 677 * so if we fail, we will assume we ran out of room. If we 678 * not able to restore the original setting, then we will 679 * return DEVFS_ERR instead. 680 */ 681 ret = DEVFS_LIMIT; 682 (void) strlcpy(opp->oprom_array, bootdev_variables[i], MAXVALSIZE); 683 valbuf = opp->oprom_array + strlen(opp->oprom_array) + 1; 684 (void) strlcpy(valbuf, save_bootdev, 685 MAXVALSIZE - strlen(opp->oprom_array) - 1); 686 687 opp->oprom_size = strlen(valbuf) + strlen(opp->oprom_array) + 2; 688 689 if (ioctl(prom_fd, OPROMSETOPT, opp) < 0) { 690 ret = DEVFS_ERR; 691 } 692 free(save_bootdev); 693 prom_close(prom_fd); 694 return (ret); 695 } 696 /* 697 * retrieve the current value for boot-device 698 */ 699 static int 700 get_boot_dev_var(struct openpromio *opp) 701 { 702 int prom_fd; 703 int i; 704 char *bootdev_variables[] = { 705 "boot-device", 706 "bootdev", 707 "boot-from", 708 NULL 709 }; 710 int found = 0; 711 int *ip = (int *)((void *)opp->oprom_array); 712 713 /* query the prom */ 714 prom_fd = prom_open(O_RDONLY); 715 if (prom_fd < 0) { 716 return (prom_fd); 717 } 718 719 /* get the diagnostic-mode? property */ 720 (void) strlcpy(opp->oprom_array, "diagnostic-mode?", MAXVALSIZE); 721 opp->oprom_size = MAXVALSIZE; 722 if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) { 723 if ((opp->oprom_size > 0) && 724 (strcmp(opp->oprom_array, "true") == 0)) { 725 prom_close(prom_fd); 726 return (DEVFS_ERR); 727 } 728 } 729 /* get the diag-switch? property */ 730 (void) strlcpy(opp->oprom_array, "diag-switch?", MAXVALSIZE); 731 opp->oprom_size = MAXVALSIZE; 732 if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) { 733 if ((opp->oprom_size > 0) && 734 (strcmp(opp->oprom_array, "true") == 0)) { 735 prom_close(prom_fd); 736 return (DEVFS_ERR); 737 } 738 } 739 /* 740 * look for one of the following properties in order: 741 * boot-device 742 * bootdev 743 * boot-from 744 * 745 * Use the first one that we find. 746 */ 747 *ip = 0; 748 opp->oprom_size = MAXPROPSIZE; 749 while ((opp->oprom_size != 0) && (!found)) { 750 opp->oprom_size = MAXPROPSIZE; 751 if (ioctl(prom_fd, OPROMNXTOPT, opp) < 0) { 752 break; 753 } 754 for (i = 0; bootdev_variables[i] != NULL; i++) { 755 if (strcmp(opp->oprom_array, bootdev_variables[i]) 756 == 0) { 757 found = 1; 758 break; 759 } 760 } 761 } 762 if (found) { 763 (void) strlcpy(opp->oprom_array, bootdev_variables[i], 764 MAXVALSIZE); 765 opp->oprom_size = MAXVALSIZE; 766 if (ioctl(prom_fd, OPROMGETOPT, opp) < 0) { 767 prom_close(prom_fd); 768 return (DEVFS_ERR); 769 } 770 /* boot-device exists but contains nothing */ 771 if (opp->oprom_size == 0) { 772 *opp->oprom_array = '\0'; 773 } 774 } else { 775 prom_close(prom_fd); 776 return (DEVFS_NOTSUP); 777 } 778 prom_close(prom_fd); 779 return (0); 780 } 781 782 #ifndef __sparc 783 static FILE * 784 open_diskmap(void) 785 { 786 FILE *fp; 787 char cmd[PATH_MAX]; 788 789 /* make sure we have a map file */ 790 fp = fopen(GRUBDISK_MAP, "r"); 791 if (fp == NULL) { 792 (void) snprintf(cmd, sizeof (cmd), 793 "%s > /dev/null", CREATE_DISKMAP); 794 (void) system(cmd); 795 fp = fopen(GRUBDISK_MAP, "r"); 796 } 797 return (fp); 798 } 799 800 static int 801 find_x86_boot_device(struct openpromio *opp) 802 { 803 int ret = DEVFS_ERR; 804 char *cp, line[MAXVALSIZE + 6]; 805 FILE *file; 806 807 file = open_diskmap(); 808 if (file == NULL) 809 return (DEVFS_ERR); 810 811 while (fgets(line, MAXVALSIZE + 6, file)) { 812 if (strncmp(line, "0 ", 2) != 0) 813 continue; 814 /* drop new-line */ 815 line[strlen(line) - 1] = '\0'; 816 /* 817 * an x86 BIOS only boots a disk, not a partition 818 * or a slice, so hard-code :q (p0) 819 */ 820 cp = strchr(line + 2, ' '); 821 if (cp == NULL) 822 break; 823 (void) snprintf(opp->oprom_array, MAXVALSIZE, 824 "%s:q", cp + 1); 825 opp->oprom_size = MAXVALSIZE; 826 ret = 0; 827 break; 828 } 829 (void) fclose(file); 830 return (ret); 831 } 832 #endif /* ndef __sparc */ 833 834 /* 835 * retrieve the list of entries in the boot-device configuration 836 * variable. An array of boot_dev structs will be created, one entry 837 * for each device name in the boot-device variable. Each entry 838 * in the array will contain the logical device representation of the 839 * boot-device entry, if any. 840 * 841 * default_root. if set, is used to locate logical device entries in 842 * directories other than /dev 843 */ 844 int 845 devfs_bootdev_get_list(const char *default_root, 846 struct boot_dev ***bootdev_list) 847 { 848 Oppbuf oppbuf; 849 struct openpromio *opp = &(oppbuf.opp); 850 int i; 851 struct boot_dev **tmp_list; 852 853 if (default_root == NULL) { 854 default_root = ""; 855 } else if (*default_root != '/') { 856 return (DEVFS_INVAL); 857 } 858 859 if (bootdev_list == NULL) { 860 return (DEVFS_INVAL); 861 } 862 863 /* get the boot-device variable */ 864 #if defined(sparc) 865 i = get_boot_dev_var(opp); 866 #else 867 i = find_x86_boot_device(opp); 868 #endif 869 if (i < 0) { 870 return (i); 871 } 872 /* now try to translate each entry to a logical device. */ 873 i = process_bootdev(opp->oprom_array, default_root, &tmp_list); 874 if (i == 0) { 875 *bootdev_list = tmp_list; 876 return (0); 877 } else { 878 return (i); 879 } 880 } 881 882 /* 883 * loop thru the list of entries in a boot-device configuration 884 * variable. 885 */ 886 static int 887 process_bootdev(const char *bootdevice, const char *default_root, 888 struct boot_dev ***list) 889 { 890 int i; 891 char *entry, *ptr; 892 char prom_path[MAXPATHLEN]; 893 char ret_buf[MAXPATHLEN]; 894 struct boot_dev **bootdev_array; 895 int num_entries = 0; 896 int found = 0; 897 int vers; 898 899 if ((entry = (char *)malloc(strlen(bootdevice) + 1)) == NULL) { 900 return (DEVFS_NOMEM); 901 } 902 /* count the number of entries */ 903 (void) strcpy(entry, bootdevice); 904 for (ptr = strtok(entry, " "); ptr != NULL; 905 ptr = strtok(NULL, " ")) { 906 num_entries++; 907 } 908 (void) strcpy(entry, bootdevice); 909 910 bootdev_array = (struct boot_dev **) 911 calloc((size_t)num_entries + 1, sizeof (struct boot_dev *)); 912 913 if (bootdev_array == NULL) { 914 free(entry); 915 return (DEVFS_NOMEM); 916 } 917 918 vers = prom_obp_vers(); 919 if (vers < 0) { 920 free(entry); 921 return (vers); 922 } 923 924 /* for each entry in boot-device, do... */ 925 for (ptr = strtok(entry, " "), i = 0; ptr != NULL; 926 ptr = strtok(NULL, " "), i++) { 927 928 if ((bootdev_array[i] = alloc_bootdev(ptr)) == NULL) { 929 devfs_bootdev_free_list(bootdev_array); 930 free(entry); 931 return (DEVFS_NOMEM); 932 } 933 934 /* 935 * prom boot-device may be aliased, so we need to do 936 * the necessary prom alias to dev translation. 937 */ 938 if (*ptr != '/') { 939 if (alias_to_prom_dev(ptr, prom_path) < 0) { 940 continue; 941 } 942 } else { 943 (void) strcpy(prom_path, ptr); 944 } 945 946 /* now we have a prom device path - convert to a devfs name */ 947 if (devfs_prom_to_dev_name(prom_path, ret_buf) < 0) { 948 continue; 949 } 950 951 /* append any default minor names necessary */ 952 if (process_minor_name(ret_buf, default_root) < 0) { 953 continue; 954 } 955 found = 1; 956 957 /* 958 * store the physical device path for now - when 959 * we are all done with the entries, we will convert 960 * these to their logical device name equivalents 961 */ 962 bootdev_array[i]->bootdev_trans[0] = strdup(ret_buf); 963 } 964 /* 965 * Convert all of the boot-device entries that translated to a 966 * physical device path in /devices to a logical device path 967 * in /dev (note that there may be several logical device paths 968 * associated with a single physical device path - return them all 969 */ 970 if (found) { 971 if (devfs_phys_to_logical(bootdev_array, num_entries, 972 default_root) < 0) { 973 devfs_bootdev_free_list(bootdev_array); 974 bootdev_array = NULL; 975 } 976 } 977 free(entry); 978 *list = bootdev_array; 979 return (0); 980 } 981 982 /* 983 * We may get a device path from the prom that has no minor name 984 * information included in it. Since this device name will not 985 * correspond directly to a physical device in /devices, we do our 986 * best to append what the default minor name should be and try this. 987 * 988 * For sparc: we append slice 0 (:a). 989 * For x86: we append fdisk partition 0 (:q). 990 */ 991 static int 992 process_minor_name(char *dev_path, const char *root) 993 { 994 char *cp; 995 #if defined(sparc) 996 const char *default_minor_name = "a"; 997 #else 998 const char *default_minor_name = "q"; 999 #endif 1000 int n; 1001 struct stat stat_buf; 1002 char path[MAXPATHLEN]; 1003 1004 (void) snprintf(path, sizeof (path), "%s%s%s", root, DEVICES, dev_path); 1005 /* 1006 * if the device file already exists as given to us, there 1007 * is nothing to do but return. 1008 */ 1009 if (stat(path, &stat_buf) == 0) { 1010 return (0); 1011 } 1012 /* 1013 * if there is no ':' after the last '/' character, or if there is 1014 * a ':' with no specifier, append the default segment specifier 1015 * ; if there is a ':' followed by a digit, this indicates 1016 * a partition number (which does not map into the /devices name 1017 * space), so strip the number and replace it with the letter 1018 * that represents the partition index 1019 */ 1020 if ((cp = strrchr(dev_path, '/')) != NULL) { 1021 if ((cp = strchr(cp, ':')) == NULL) { 1022 (void) strcat(dev_path, ":"); 1023 (void) strcat(dev_path, default_minor_name); 1024 } else if (*++cp == '\0') { 1025 (void) strcat(dev_path, default_minor_name); 1026 } else if (isdigit(*cp)) { 1027 n = atoi(cp); 1028 /* make sure to squash the digit */ 1029 *cp = '\0'; 1030 switch (n) { 1031 case 0: (void) strcat(dev_path, "q"); 1032 break; 1033 case 1: (void) strcat(dev_path, "r"); 1034 break; 1035 case 2: (void) strcat(dev_path, "s"); 1036 break; 1037 case 3: (void) strcat(dev_path, "t"); 1038 break; 1039 case 4: (void) strcat(dev_path, "u"); 1040 break; 1041 default: (void) strcat(dev_path, "a"); 1042 break; 1043 } 1044 } 1045 } 1046 /* 1047 * see if we can find something now. 1048 */ 1049 (void) snprintf(path, sizeof (path), "%s%s%s", root, DEVICES, dev_path); 1050 1051 if (stat(path, &stat_buf) == 0) { 1052 return (0); 1053 } else { 1054 return (-1); 1055 } 1056 } 1057 1058 /* 1059 * for each entry in bootdev_array, convert the physical device 1060 * representation of the boot-device entry to one or more logical device 1061 * entries. We use the hammer method - walk through the logical device 1062 * name space looking for matches (/dev). We use nftw to do this. 1063 */ 1064 static int 1065 devfs_phys_to_logical(struct boot_dev **bootdev_array, const int array_size, 1066 const char *default_root) 1067 { 1068 int walk_flags = FTW_PHYS | FTW_MOUNT; 1069 char *full_path; 1070 struct name_list *list; 1071 int count, i; 1072 char **dev_name_array; 1073 size_t default_root_len; 1074 char *dev_dir = DEV; 1075 int len; 1076 1077 if (array_size < 0) { 1078 return (-1); 1079 } 1080 1081 if (bootdev_array == NULL) { 1082 return (-1); 1083 } 1084 if (default_root == NULL) { 1085 return (-1); 1086 } 1087 default_root_len = strlen(default_root); 1088 if ((default_root_len != 0) && (*default_root != '/')) { 1089 return (-1); 1090 } 1091 1092 /* short cut for an empty array */ 1093 if (*bootdev_array == NULL) { 1094 return (0); 1095 } 1096 1097 /* tell nftw where to start (default: /dev) */ 1098 len = default_root_len + strlen(dev_dir) + 1; 1099 if ((full_path = (char *)malloc(len)) == NULL) { 1100 return (-1); 1101 } 1102 1103 /* 1104 * if the default root path is terminated with a /, we have to 1105 * make sure we don't end up with one too many slashes in the 1106 * path we are building. 1107 */ 1108 if ((default_root_len > (size_t)0) && 1109 (default_root[default_root_len - 1] == '/')) { 1110 (void) snprintf(full_path, len, "%s%s", default_root, 1111 &dev_dir[1]); 1112 } else { 1113 (void) snprintf(full_path, len, "%s%s", default_root, dev_dir); 1114 } 1115 1116 /* 1117 * we need to muck with global data to make nftw work 1118 * so single thread access 1119 */ 1120 (void) mutex_lock(&dev_lists_lk); 1121 1122 /* 1123 * set the global vars bootdev_list and dev_list for use by nftw 1124 * dev_list is an array of lists - one for each boot-device 1125 * entry. The nftw function will create a list of logical device 1126 * entries for each boot-device and put all of the lists in 1127 * dev_list. 1128 */ 1129 dev_list = (struct name_list **) 1130 calloc(array_size, sizeof (struct name_list *)); 1131 if (dev_list == NULL) { 1132 free(full_path); 1133 (void) mutex_unlock(&dev_lists_lk); 1134 return (-1); 1135 } 1136 bootdev_list = bootdev_array; 1137 1138 if (nftw(full_path, check_logical_dev, FT_DEPTH, walk_flags) == -1) { 1139 bootdev_list = NULL; 1140 free(full_path); 1141 for (i = 0; i < array_size; i++) { 1142 free_name_list(dev_list[i], 1); 1143 } 1144 /* don't free dev_list here because it's been handed off */ 1145 dev_list = NULL; 1146 (void) mutex_unlock(&dev_lists_lk); 1147 return (-1); 1148 } 1149 1150 /* 1151 * now we have a filled in dev_list. So for each logical device 1152 * list in dev_list, count the number of entries in the list, 1153 * create an array of strings of logical devices, and save in the 1154 * corresponding boot_dev structure. 1155 */ 1156 for (i = 0; i < array_size; i++) { 1157 /* get the next list */ 1158 list = dev_list[i]; 1159 count = 0; 1160 1161 if (bootdev_array[i] == NULL) 1162 continue; 1163 1164 /* count the number of entries in the list */ 1165 while (list != NULL) { 1166 count++; 1167 list = list->next; 1168 } 1169 if ((dev_name_array = 1170 (char **)malloc((count + 1) * sizeof (char *))) 1171 == NULL) { 1172 continue; 1173 } 1174 list = dev_list[i]; 1175 count = 0; 1176 1177 /* fill in the array */ 1178 while (list != NULL) { 1179 dev_name_array[count] = list->name; 1180 count++; 1181 list = list->next; 1182 } 1183 1184 /* 1185 * null terminate the array 1186 */ 1187 dev_name_array[count] = NULL; 1188 1189 /* 1190 * At this point, only bootdev_trans[0] has been populated 1191 * (via process_bootdev). Replace the translation array with 1192 * the full set of logical device names. 1193 */ 1194 free(bootdev_array[i]->bootdev_trans[0]); 1195 free(bootdev_array[i]->bootdev_trans); 1196 bootdev_array[i]->bootdev_trans = dev_name_array; 1197 } 1198 bootdev_list = NULL; 1199 free(full_path); 1200 for (i = 0; i < array_size; i++) { 1201 free_name_list(dev_list[i], 0); 1202 } 1203 free(dev_list); 1204 dev_list = NULL; 1205 (void) mutex_unlock(&dev_lists_lk); 1206 return (0); 1207 } 1208 /* 1209 * nftw function 1210 * for a logical dev entry, it walks the list of boot-devices and 1211 * sees if there are any matches. If so, it saves the logical device 1212 * name off in the appropriate list in dev_list 1213 */ 1214 /* ARGSUSED */ 1215 static int 1216 check_logical_dev(const char *node, const struct stat *node_stat, int flags, 1217 struct FTW *ftw_info) 1218 { 1219 char link_buf[MAXPATHLEN]; 1220 int link_buf_len; 1221 char *name; 1222 struct name_list *dev; 1223 char *physdev; 1224 int i; 1225 1226 if (flags != FTW_SL) { 1227 return (0); 1228 } 1229 1230 if ((link_buf_len = readlink(node, (void *)link_buf, MAXPATHLEN)) 1231 == -1) { 1232 return (0); 1233 } 1234 link_buf[link_buf_len] = '\0'; 1235 if ((name = strstr(link_buf, DEVICES)) == NULL) { 1236 return (0); 1237 } 1238 name = (char *)(name + strlen(DEVICES)); 1239 1240 for (i = 0; bootdev_list[i] != NULL; i++) { 1241 if (bootdev_list[i]->bootdev_trans[0] == NULL) { 1242 continue; 1243 } 1244 /* 1245 * compare the contents of the link with the physical 1246 * device representation of this boot device 1247 */ 1248 physdev = bootdev_list[i]->bootdev_trans[0]; 1249 if ((strcmp(name, physdev) == 0) && 1250 (strlen(name) == strlen(physdev))) { 1251 if ((dev = (struct name_list *) 1252 malloc(sizeof (struct name_list))) == NULL) { 1253 return (-1); 1254 } 1255 if ((dev->name = strdup(node)) == NULL) { 1256 free(dev); 1257 return (-1); 1258 } 1259 if (dev_list[i] == NULL) { 1260 dev_list[i] = dev; 1261 dev_list[i]->next = NULL; 1262 } else { 1263 dev->next = dev_list[i]; 1264 dev_list[i] = dev; 1265 } 1266 } 1267 } 1268 return (0); 1269 } 1270 1271 /* 1272 * frees a list of boot_dev struct pointers 1273 */ 1274 void 1275 devfs_bootdev_free_list(struct boot_dev **array) 1276 { 1277 int i = 0; 1278 int j; 1279 1280 if (array == NULL) { 1281 return; 1282 } 1283 1284 while (array[i] != NULL) { 1285 free(array[i]->bootdev_element); 1286 j = 0; 1287 while (array[i]->bootdev_trans[j] != NULL) { 1288 free(array[i]->bootdev_trans[j++]); 1289 } 1290 free(array[i]->bootdev_trans); 1291 free(array[i]); 1292 i++; 1293 } 1294 free(array); 1295 } 1296 /* 1297 * allocates a boot_dev struct and fills in the bootdev_element portion 1298 */ 1299 static struct boot_dev * 1300 alloc_bootdev(char *entry_name) 1301 { 1302 struct boot_dev *entry; 1303 1304 entry = (struct boot_dev *)calloc(1, sizeof (struct boot_dev)); 1305 1306 if (entry == NULL) { 1307 return (NULL); 1308 } 1309 if ((entry->bootdev_element = strdup(entry_name)) == NULL) { 1310 free(entry); 1311 return (NULL); 1312 } 1313 /* 1314 * Allocate room for 1 name and a null terminator - the caller of 1315 * this function will need the first slot right away. 1316 */ 1317 if ((entry->bootdev_trans = (char **)calloc(2, sizeof (char *))) 1318 == NULL) { 1319 free(entry->bootdev_element); 1320 free(entry); 1321 return (NULL); 1322 } 1323 return (entry); 1324 } 1325 1326 /* 1327 * will come back with a concatenated list of paths 1328 */ 1329 int 1330 devfs_dev_to_prom_names(char *dev_path, char *prom_path, size_t len) 1331 { 1332 Oppbuf oppbuf; 1333 struct openpromio *opp = &(oppbuf.opp); 1334 int prom_fd; 1335 int ret = DEVFS_INVAL; 1336 int i; 1337 1338 if (prom_path == NULL) { 1339 return (DEVFS_INVAL); 1340 } 1341 if (dev_path == NULL) { 1342 return (DEVFS_INVAL); 1343 } 1344 if (strlen(dev_path) >= MAXPATHLEN) 1345 return (DEVFS_INVAL); 1346 1347 if (*dev_path != '/') 1348 return (DEVFS_INVAL); 1349 1350 prom_fd = prom_open(O_RDONLY); 1351 if (prom_fd < 0) { 1352 return (prom_fd); 1353 } 1354 1355 /* query the prom */ 1356 (void) snprintf(opp->oprom_array, MAXVALSIZE, "%s", dev_path); 1357 opp->oprom_size = MAXVALSIZE; 1358 1359 if (ioctl(prom_fd, OPROMDEV2PROMNAME, opp) == 0) { 1360 prom_close(prom_fd); 1361 1362 /* return the prom path in prom_path */ 1363 1364 i = len - opp->oprom_size; 1365 if (i < 0) { 1366 bcopy(opp->oprom_array, prom_path, len); 1367 prom_path[len - 1] = '\0'; 1368 return (len); 1369 } else { 1370 bcopy(opp->oprom_array, prom_path, len); 1371 return (opp->oprom_size); 1372 } 1373 } 1374 /* 1375 * either the prom does not support this ioctl or the argument 1376 * was invalid. 1377 */ 1378 if (errno == ENXIO) { 1379 ret = DEVFS_NOTSUP; 1380 } 1381 prom_close(prom_fd); 1382 return (ret); 1383 } 1384 1385 /* 1386 * Convert a physical or logical device name to a name the prom would 1387 * understand. Fail if this platform does not support a prom or if 1388 * the device does not correspond to a valid prom device. 1389 * dev_path should be the name of a device in the logical or 1390 * physical device namespace. 1391 * prom_path is the prom version of the device name 1392 * prom_path must be large enough to contain the result and is 1393 * supplied by the user. 1394 * 1395 * This routine only supports converting leaf device paths 1396 */ 1397 int 1398 devfs_dev_to_prom_name(char *dev_path, char *prom_path) 1399 { 1400 int rval; 1401 1402 rval = devfs_dev_to_prom_names(dev_path, prom_path, MAXPATHLEN); 1403 1404 if (rval < 0) 1405 return (rval); 1406 else 1407 return (0); 1408 } 1409 1410 /* 1411 * Use the openprom driver's OPROMPATH2DRV ioctl to convert a devfs 1412 * path to a driver name. 1413 * devfs_path - the pathname of interest. This must be the physcical device 1414 * path with the mount point prefix (ie. /devices) stripped off. 1415 * drv_buf - user supplied buffer - the driver name will be stored here. 1416 * 1417 * If the prom lookup fails, we return the name of the last component in 1418 * the pathname. This routine is useful for looking up driver names 1419 * associated with generically named devices. 1420 * 1421 * This routine returns driver names that have aliases resolved. 1422 */ 1423 int 1424 devfs_path_to_drv(char *devfs_path, char *drv_buf) 1425 { 1426 Oppbuf oppbuf; 1427 struct openpromio *opp = &(oppbuf.opp); 1428 char *slash, *colon, *dev_addr; 1429 char driver_path[MAXPATHLEN]; 1430 int prom_fd; 1431 1432 if (drv_buf == NULL) { 1433 return (-1); 1434 } 1435 if (devfs_path == NULL) { 1436 return (-1); 1437 } 1438 1439 if (strlen(devfs_path) >= MAXPATHLEN) 1440 return (-1); 1441 1442 if (*devfs_path != '/') 1443 return (-1); 1444 1445 1446 /* strip off any minor node info at the end of the path */ 1447 (void) strcpy(driver_path, devfs_path); 1448 slash = strrchr(driver_path, '/'); 1449 if (slash == NULL) 1450 return (-1); 1451 colon = strrchr(slash, ':'); 1452 if (colon != NULL) 1453 *colon = '\0'; 1454 1455 /* query the prom */ 1456 if ((prom_fd = prom_open(O_RDONLY)) >= 0) { 1457 (void) strlcpy(opp->oprom_array, driver_path, MAXVALSIZE); 1458 opp->oprom_size = MAXVALSIZE; 1459 1460 if (ioctl(prom_fd, OPROMPATH2DRV, opp) == 0) { 1461 prom_close(prom_fd); 1462 /* return the driver name in drv_buf */ 1463 (void) strcpy(drv_buf, opp->oprom_array); 1464 return (0); 1465 } 1466 prom_close(prom_fd); 1467 } else if (prom_fd != DEVFS_NOTSUP) 1468 return (-1); 1469 /* 1470 * If we get here, then either: 1471 * 1. this platform does not support an openprom driver 1472 * 2. we were asked to look up a device the prom does 1473 * not know about (e.g. a pseudo device) 1474 * In this case, we use the last component of the devfs path 1475 * name and try to derive the driver name 1476 */ 1477 1478 /* use the last component of devfs_path as the driver name */ 1479 if ((dev_addr = strrchr(slash, '@')) != NULL) 1480 *dev_addr = '\0'; 1481 slash++; 1482 1483 /* use opp->oprom_array as a buffer */ 1484 (void) strlcpy(opp->oprom_array, slash, MAXVALSIZE); 1485 if (devfs_resolve_aliases(opp->oprom_array) == NULL) 1486 return (-1); 1487 (void) strcpy(drv_buf, opp->oprom_array); 1488 return (0); 1489 } 1490 1491 /* 1492 * These modctl calls do the equivalent of: 1493 * ddi_name_to_major() 1494 * ddi_major_to_name() 1495 * This results in two things: 1496 * - the driver name must be a valid one 1497 * - any driver aliases are resolved. 1498 * drv is overwritten with the resulting name. 1499 */ 1500 char * 1501 devfs_resolve_aliases(char *drv) 1502 { 1503 major_t maj; 1504 char driver_name[MAXNAMELEN + 1]; 1505 1506 if (drv == NULL) { 1507 return (NULL); 1508 } 1509 1510 if (modctl(MODGETMAJBIND, drv, strlen(drv) + 1, &maj) < 0) 1511 return (NULL); 1512 else if (modctl(MODGETNAME, driver_name, sizeof (driver_name), &maj) 1513 < 0) { 1514 return (NULL); 1515 } else { 1516 (void) strcpy(drv, driver_name); 1517 return (drv); 1518 } 1519 } 1520 1521 /* 1522 * open the openprom device. and verify that we are on an 1523 * OBP/1275 OF machine. If the prom does not exist, then we 1524 * return an error 1525 */ 1526 static int 1527 prom_open(int oflag) 1528 { 1529 int prom_fd = -1; 1530 char *promdev = "/dev/openprom"; 1531 1532 while (prom_fd < 0) { 1533 if ((prom_fd = open(promdev, oflag)) < 0) { 1534 if (errno == EAGAIN) { 1535 (void) sleep(5); 1536 continue; 1537 } 1538 if ((errno == ENXIO) || (errno == ENOENT)) { 1539 return (DEVFS_NOTSUP); 1540 } 1541 if ((errno == EPERM) || (errno == EACCES)) { 1542 return (DEVFS_PERM); 1543 } 1544 return (DEVFS_ERR); 1545 } else 1546 break; 1547 } 1548 if (is_openprom(prom_fd)) 1549 return (prom_fd); 1550 else { 1551 prom_close(prom_fd); 1552 return (DEVFS_ERR); 1553 } 1554 } 1555 1556 static void 1557 prom_close(int prom_fd) 1558 { 1559 (void) close(prom_fd); 1560 } 1561 1562 /* 1563 * is this an OBP/1275 OF machine? 1564 */ 1565 static int 1566 is_openprom(int prom_fd) 1567 { 1568 Oppbuf oppbuf; 1569 struct openpromio *opp = &(oppbuf.opp); 1570 unsigned int i; 1571 1572 opp->oprom_size = MAXVALSIZE; 1573 if (ioctl(prom_fd, OPROMGETCONS, opp) < 0) 1574 return (0); 1575 1576 i = (unsigned int)((unsigned char)opp->oprom_array[0]); 1577 return ((i & OPROMCONS_OPENPROM) == OPROMCONS_OPENPROM); 1578 } 1579 1580 /* 1581 * convert a prom device path name to an equivalent physical device 1582 * path in the kernel. 1583 */ 1584 static int 1585 devfs_prom_to_dev_name(char *prom_path, char *dev_path) 1586 { 1587 Oppbuf oppbuf; 1588 struct openpromio *opp = &(oppbuf.opp); 1589 int prom_fd; 1590 int ret = DEVFS_INVAL; 1591 1592 if (dev_path == NULL) { 1593 return (DEVFS_INVAL); 1594 } 1595 if (prom_path == NULL) { 1596 return (DEVFS_INVAL); 1597 } 1598 if (strlen(prom_path) >= MAXPATHLEN) 1599 return (DEVFS_INVAL); 1600 1601 if (*prom_path != '/') { 1602 return (DEVFS_INVAL); 1603 } 1604 1605 /* query the prom */ 1606 prom_fd = prom_open(O_RDONLY); 1607 if (prom_fd < 0) { 1608 return (prom_fd); 1609 } 1610 (void) strlcpy(opp->oprom_array, prom_path, MAXVALSIZE); 1611 opp->oprom_size = MAXVALSIZE; 1612 1613 if (ioctl(prom_fd, OPROMPROM2DEVNAME, opp) == 0) { 1614 prom_close(prom_fd); 1615 /* 1616 * success 1617 * return the prom path in prom_path 1618 */ 1619 (void) strcpy(dev_path, opp->oprom_array); 1620 return (0); 1621 } 1622 /* 1623 * either the argument was not a valid name or the openprom 1624 * driver does not support this ioctl. 1625 */ 1626 if (errno == ENXIO) { 1627 ret = DEVFS_NOTSUP; 1628 } 1629 prom_close(prom_fd); 1630 return (ret); 1631 } 1632 /* 1633 * convert a prom device path to a list of equivalent alias names 1634 * If there is no alias node, or there are no aliases that correspond 1635 * to dev, we return empty lists. 1636 */ 1637 static int 1638 prom_dev_to_alias(char *dev, uint_t options, char ***ret_buf) 1639 { 1640 struct name_list *exact_list; 1641 struct name_list *inexact_list; 1642 struct name_list *list; 1643 char *ptr; 1644 char **array; 1645 int prom_fd; 1646 int count; 1647 int vers; 1648 1649 vers = prom_obp_vers(); 1650 if (vers < 0) { 1651 return (vers); 1652 } 1653 1654 if (dev == NULL) { 1655 return (DEVFS_INVAL); 1656 } 1657 1658 if (*dev != '/') 1659 return (DEVFS_INVAL); 1660 1661 if (strlen(dev) >= MAXPATHLEN) 1662 return (DEVFS_INVAL); 1663 1664 if ((ptr = strchr(dev, ':')) != NULL) { 1665 if (strchr(ptr, '/') != NULL) 1666 return (DEVFS_INVAL); 1667 } 1668 if (ret_buf == NULL) { 1669 return (DEVFS_INVAL); 1670 } 1671 1672 prom_fd = prom_open(O_RDONLY); 1673 if (prom_fd < 0) { 1674 return (prom_fd); 1675 } 1676 1677 (void) prom_srch_aliases_by_def(dev, &exact_list, 1678 &inexact_list, prom_fd); 1679 1680 prom_close(prom_fd); 1681 1682 if ((options & BOOTDEV_NO_EXACT_ALIAS) != 0) { 1683 free_name_list(exact_list, 1); 1684 exact_list = NULL; 1685 } 1686 1687 if ((options & BOOTDEV_NO_INEXACT_ALIAS) != 0) { 1688 free_name_list(inexact_list, 1); 1689 inexact_list = NULL; 1690 } 1691 1692 count = 0; 1693 list = exact_list; 1694 while (list != NULL) { 1695 list = list->next; 1696 count++; 1697 } 1698 list = inexact_list; 1699 while (list != NULL) { 1700 list = list->next; 1701 count++; 1702 } 1703 1704 if ((*ret_buf = (char **)malloc((count + 1) * sizeof (char *))) 1705 == NULL) { 1706 free_name_list(inexact_list, 1); 1707 free_name_list(exact_list, 1); 1708 return (DEVFS_NOMEM); 1709 } 1710 1711 array = *ret_buf; 1712 count = 0; 1713 list = exact_list; 1714 while (list != NULL) { 1715 array[count] = list->name; 1716 list = list->next; 1717 count++; 1718 } 1719 list = inexact_list; 1720 while (list != NULL) { 1721 array[count] = list->name; 1722 list = list->next; 1723 count++; 1724 } 1725 array[count] = NULL; 1726 free_name_list(inexact_list, 0); 1727 free_name_list(exact_list, 0); 1728 1729 return (0); 1730 } 1731 1732 /* 1733 * determine the version of prom we are running on. 1734 * Also include any prom revision specific information. 1735 */ 1736 static int 1737 prom_obp_vers(void) 1738 { 1739 Oppbuf oppbuf; 1740 struct openpromio *opp = &(oppbuf.opp); 1741 int prom_fd; 1742 static int version = 0; 1743 1744 /* cache version */ 1745 if (version > 0) { 1746 return (version); 1747 } 1748 1749 prom_fd = prom_open(O_RDONLY); 1750 if (prom_fd < 0) { 1751 return (prom_fd); 1752 } 1753 1754 opp->oprom_size = MAXVALSIZE; 1755 1756 if ((ioctl(prom_fd, OPROMGETVERSION, opp)) < 0) { 1757 prom_close(prom_fd); 1758 return (DEVFS_ERR); 1759 } 1760 prom_close(prom_fd); 1761 1762 version |= OBP_OF; 1763 1764 return (version); 1765 } 1766 /* 1767 * search the aliases node by definition - compile a list of 1768 * alias names that are both exact and inexact matches. 1769 */ 1770 static int 1771 prom_srch_aliases_by_def(char *promdev_def, struct name_list **exact_list, 1772 struct name_list **inexact_list, int prom_fd) 1773 { 1774 Oppbuf oppbuf; 1775 Oppbuf propdef_oppbuf; 1776 struct openpromio *opp = &(oppbuf.opp); 1777 struct openpromio *propdef_opp = &(propdef_oppbuf.opp); 1778 int *ip = (int *)((void *)opp->oprom_array); 1779 int ret; 1780 struct name_list *inexact_match = *inexact_list = NULL; 1781 struct name_list *exact_match = *exact_list = NULL; 1782 char alias_buf[MAXNAMELEN]; 1783 int found = 0; 1784 1785 if ((ret = prom_find_aliases_node(prom_fd)) < 0) 1786 return (0); 1787 1788 (void) memset(oppbuf.buf, 0, BUFSIZE); 1789 opp->oprom_size = MAXPROPSIZE; 1790 *ip = 0; 1791 1792 if ((ret = ioctl(prom_fd, OPROMNXTPROP, opp)) < 0) 1793 return (0); 1794 if (opp->oprom_size == 0) 1795 return (0); 1796 1797 while ((ret >= 0) && (opp->oprom_size > 0)) { 1798 (void) strcpy(propdef_opp->oprom_array, opp->oprom_array); 1799 opp->oprom_size = MAXPROPSIZE; 1800 propdef_opp->oprom_size = MAXVALSIZE; 1801 if ((ioctl(prom_fd, OPROMGETPROP, propdef_opp) < 0) || 1802 (propdef_opp->oprom_size == 0)) { 1803 ret = ioctl(prom_fd, OPROMNXTPROP, opp); 1804 continue; 1805 } 1806 ret = prom_compare_devs(promdev_def, propdef_opp->oprom_array); 1807 if (ret == EXACT_MATCH) { 1808 found++; 1809 if (insert_alias_list(exact_list, opp->oprom_array) 1810 != 0) { 1811 free_name_list(exact_match, 1); 1812 free_name_list(inexact_match, 1); 1813 return (-1); 1814 } 1815 } 1816 if (ret == INEXACT_MATCH) { 1817 found++; 1818 (void) strcpy(alias_buf, opp->oprom_array); 1819 options_override(promdev_def, alias_buf); 1820 if (insert_alias_list(inexact_list, alias_buf) 1821 != 0) { 1822 free_name_list(exact_match, 1); 1823 free_name_list(inexact_match, 1); 1824 return (-1); 1825 } 1826 } 1827 ret = ioctl(prom_fd, OPROMNXTPROP, opp); 1828 } 1829 if (found) { 1830 return (0); 1831 } else { 1832 return (-1); 1833 } 1834 } 1835 1836 /* 1837 * free a list of name_list structs and optionally 1838 * free the strings they contain. 1839 */ 1840 static void 1841 free_name_list(struct name_list *list, int free_name) 1842 { 1843 struct name_list *next = list; 1844 1845 while (next != NULL) { 1846 list = list->next; 1847 if (free_name) 1848 free(next->name); 1849 free(next); 1850 next = list; 1851 } 1852 } 1853 1854 /* 1855 * insert a new alias in a list of aliases - the list is sorted 1856 * in collating order (ignoring anything that comes after the 1857 * ':' in the name). 1858 */ 1859 static int 1860 insert_alias_list(struct name_list **list, char *alias_name) 1861 { 1862 struct name_list *entry = *list; 1863 struct name_list *new_entry, *prev_entry; 1864 int ret; 1865 char *colon1, *colon2; 1866 1867 if ((new_entry = 1868 (struct name_list *)malloc(sizeof (struct name_list))) 1869 == NULL) { 1870 return (-1); 1871 } 1872 if ((new_entry->name = strdup(alias_name)) == NULL) { 1873 free(new_entry); 1874 return (-1); 1875 } 1876 new_entry->next = NULL; 1877 1878 if (entry == NULL) { 1879 *list = new_entry; 1880 return (0); 1881 } 1882 1883 if ((colon1 = strchr(alias_name, ':')) != NULL) { 1884 *colon1 = '\0'; 1885 } 1886 prev_entry = NULL; 1887 while (entry != NULL) { 1888 if ((colon2 = strchr(entry->name, ':')) != NULL) { 1889 *colon2 = '\0'; 1890 } 1891 ret = strcmp(alias_name, entry->name); 1892 if (colon2 != NULL) { 1893 *colon2 = ':'; 1894 } 1895 /* duplicate */ 1896 if (ret == 0) { 1897 free(new_entry->name); 1898 free(new_entry); 1899 if (colon1 != NULL) { 1900 *colon1 = ':'; 1901 } 1902 return (0); 1903 } 1904 if (ret < 0) { 1905 new_entry->next = entry; 1906 if (prev_entry == NULL) { 1907 /* in beginning of list */ 1908 *list = new_entry; 1909 } else { 1910 /* in middle of list */ 1911 prev_entry->next = new_entry; 1912 } 1913 if (colon1 != NULL) { 1914 *colon1 = ':'; 1915 } 1916 return (0); 1917 } 1918 prev_entry = entry; 1919 entry = entry->next; 1920 } 1921 /* at end of list */ 1922 prev_entry->next = new_entry; 1923 new_entry->next = NULL; 1924 if (colon1 != NULL) { 1925 *colon1 = ':'; 1926 } 1927 return (0); 1928 } 1929 /* 1930 * append :x to alias_name to override any default minor name options 1931 */ 1932 static void 1933 options_override(char *prom_path, char *alias_name) 1934 { 1935 char *colon; 1936 1937 if ((colon = strrchr(alias_name, ':')) != NULL) { 1938 /* 1939 * XXX - should alias names in /aliases ever have a 1940 * : embedded in them? 1941 * If so we ignore it. 1942 */ 1943 *colon = '\0'; 1944 } 1945 1946 if ((colon = strrchr(prom_path, ':')) != NULL) { 1947 (void) strcat(alias_name, colon); 1948 } 1949 } 1950 1951 /* 1952 * compare to prom device names. 1953 * if the device names are not fully qualified. we convert them - 1954 * we only do this as a last resort though since it requires 1955 * jumping into the kernel. 1956 */ 1957 static int 1958 prom_compare_devs(char *prom_dev1, char *prom_dev2) 1959 { 1960 char *dev1, *dev2; 1961 char *ptr1, *ptr2; 1962 char *drvname1, *addrname1, *minorname1; 1963 char *drvname2, *addrname2, *minorname2; 1964 char component1[MAXNAMELEN], component2[MAXNAMELEN]; 1965 char devname1[MAXPATHLEN], devname2[MAXPATHLEN]; 1966 int unqualified_name = 0; 1967 int error = EXACT_MATCH; 1968 int len1, len2; 1969 char *wildcard = ",0"; 1970 1971 ptr1 = prom_dev1; 1972 ptr2 = prom_dev2; 1973 1974 if ((ptr1 == NULL) || (*ptr1 != '/')) { 1975 return (NO_MATCH); 1976 } 1977 if ((ptr2 == NULL) || (*ptr2 != '/')) { 1978 return (NO_MATCH); 1979 } 1980 1981 /* 1982 * compare device names one component at a time. 1983 */ 1984 while ((ptr1 != NULL) && (ptr2 != NULL)) { 1985 *ptr1 = *ptr2 = '/'; 1986 dev1 = ptr1 + 1; 1987 dev2 = ptr2 + 1; 1988 if ((ptr1 = strchr(dev1, '/')) != NULL) 1989 *ptr1 = '\0'; 1990 if ((ptr2 = strchr(dev2, '/')) != NULL) 1991 *ptr2 = '\0'; 1992 1993 (void) strcpy(component1, dev1); 1994 (void) strcpy(component2, dev2); 1995 1996 parse_name(component1, &drvname1, &addrname1, &minorname1); 1997 parse_name(component2, &drvname2, &addrname2, &minorname2); 1998 1999 if ((drvname1 == NULL) && (addrname1 == NULL)) { 2000 error = NO_MATCH; 2001 break; 2002 } 2003 2004 if ((drvname2 == NULL) && (addrname2 == NULL)) { 2005 error = NO_MATCH; 2006 break; 2007 } 2008 2009 if (_prom_strcmp(drvname1, drvname2) != 0) { 2010 error = NO_MATCH; 2011 break; 2012 } 2013 2014 /* 2015 * a possible name is driver_name@address. The address 2016 * portion is optional (i.e. the name is not fully 2017 * qualified.). We have to deal with the case where 2018 * the component name is either driver_name or 2019 * driver_name@address 2020 */ 2021 if ((addrname1 == NULL) ^ (addrname2 == NULL)) { 2022 unqualified_name = 1; 2023 } else if (addrname1 && 2024 (_prom_strcmp(addrname1, addrname2) != 0)) { 2025 /* 2026 * check to see if appending a ",0" to the 2027 * shorter address causes a match to occur. 2028 * If so succeed. 2029 */ 2030 len1 = strlen(addrname1); 2031 len2 = strlen(addrname2); 2032 if ((len1 < len2) && 2033 (strncmp(addrname1, addrname2, len1) == 0) && 2034 (strcmp(wildcard, &addrname2[len1]) == 0)) { 2035 continue; 2036 } else if ((len2 < len1) && 2037 (strncmp(addrname1, addrname2, len2) == 0) && 2038 (strcmp(wildcard, &addrname1[len2]) == 0)) { 2039 continue; 2040 } 2041 error = NO_MATCH; 2042 break; 2043 } 2044 } 2045 2046 /* 2047 * if either of the two device paths still has more components, 2048 * then we do not have a match. 2049 */ 2050 if (ptr1 != NULL) { 2051 *ptr1 = '/'; 2052 error = NO_MATCH; 2053 } 2054 if (ptr2 != NULL) { 2055 *ptr2 = '/'; 2056 error = NO_MATCH; 2057 } 2058 if (error == NO_MATCH) { 2059 return (error); 2060 } 2061 2062 /* 2063 * OK - we found a possible match but one or more of the 2064 * path components was not fully qualified (did not have any 2065 * address information. So we need to convert it to a form 2066 * that is fully qualified and then compare the resulting 2067 * strings. 2068 */ 2069 if (unqualified_name != 0) { 2070 if ((devfs_prom_to_dev_name(prom_dev1, devname1) < 0) || 2071 (devfs_prom_to_dev_name(prom_dev2, devname2) < 0)) { 2072 return (NO_MATCH); 2073 } 2074 if ((dev1 = strrchr(devname1, ':')) != NULL) { 2075 *dev1 = '\0'; 2076 } 2077 if ((dev2 = strrchr(devname2, ':')) != NULL) { 2078 *dev2 = '\0'; 2079 } 2080 if (strcmp(devname1, devname2) != 0) { 2081 return (NO_MATCH); 2082 } 2083 } 2084 /* 2085 * the resulting strings matched. If the minorname information 2086 * matches, then we have an exact match, otherwise an inexact match 2087 */ 2088 if (_prom_strcmp(minorname1, minorname2) == 0) { 2089 return (EXACT_MATCH); 2090 } else { 2091 return (INEXACT_MATCH); 2092 } 2093 } 2094 2095 /* 2096 * wrapper or strcmp - deals with null strings. 2097 */ 2098 static int 2099 _prom_strcmp(char *s1, char *s2) 2100 { 2101 if ((s1 == NULL) && (s2 == NULL)) 2102 return (0); 2103 if ((s1 == NULL) && (s2 != NULL)) { 2104 return (-1); 2105 } 2106 if ((s1 != NULL) && (s2 == NULL)) { 2107 return (1); 2108 } 2109 return (strcmp(s1, s2)); 2110 } 2111 /* 2112 * break device@a,b:minor into components 2113 */ 2114 static void 2115 parse_name(char *name, char **drvname, char **addrname, char **minorname) 2116 { 2117 char *cp, ch; 2118 2119 cp = *drvname = name; 2120 *addrname = *minorname = NULL; 2121 if (*name == '@') 2122 *drvname = NULL; 2123 2124 while ((ch = *cp) != '\0') { 2125 if (ch == '@') 2126 *addrname = ++cp; 2127 else if (ch == ':') 2128 *minorname = ++cp; 2129 ++cp; 2130 } 2131 if (*addrname) { 2132 *((*addrname)-1) = '\0'; 2133 } 2134 if (*minorname) { 2135 *((*minorname)-1) = '\0'; 2136 } 2137 } 2138 2139 /* 2140 * converts a prom alias to a prom device name. 2141 * if we find no matching device, then we fail since if were 2142 * given a valid alias, then by definition, there must be a 2143 * device pathname associated with it in the /aliases node. 2144 */ 2145 static int 2146 alias_to_prom_dev(char *alias, char *ret_buf) 2147 { 2148 char *options_ptr; 2149 char alias_buf[MAXNAMELEN]; 2150 char alias_def[MAXPATHLEN]; 2151 char options[16] = ""; 2152 int prom_fd = -1; 2153 int ret; 2154 int i; 2155 2156 if (strchr(alias, '/') != NULL) 2157 return (DEVFS_INVAL); 2158 2159 if (strlen(alias) > (MAXNAMELEN - 1)) 2160 return (DEVFS_INVAL); 2161 2162 if (ret_buf == NULL) { 2163 return (DEVFS_INVAL); 2164 } 2165 2166 prom_fd = prom_open(O_RDONLY); 2167 if (prom_fd < 0) { 2168 return (prom_fd); 2169 } 2170 2171 (void) strlcpy(alias_buf, alias, sizeof (alias_buf)); 2172 2173 /* 2174 * save off any options (minor name info) that is 2175 * explicitly called out in the alias name 2176 */ 2177 if ((options_ptr = strchr(alias_buf, ':')) != NULL) { 2178 *options_ptr = '\0'; 2179 (void) strlcpy(options, ++options_ptr, sizeof (options)); 2180 } 2181 2182 *alias_def = '\0'; 2183 2184 ret = prom_find_aliases_node(prom_fd); 2185 if (ret == 0) { 2186 /* 2187 * we loop because one alias may define another... we have 2188 * to work our way down to an actual device definition. 2189 */ 2190 for (i = 0; i <= 10; i++) { 2191 ret = prom_srch_node(prom_fd, alias_buf, alias_def); 2192 if (ret == -1) { 2193 break; 2194 } 2195 (void) strlcpy(alias_buf, alias_def, 2196 sizeof (alias_buf)); 2197 if (*alias_def == '/') { 2198 break; 2199 } 2200 2201 /* 2202 * save off any explicit options (minor name info) 2203 * if none has been encountered yet 2204 */ 2205 if (options_ptr == NULL) { 2206 options_ptr = strchr(alias_buf, ':'); 2207 if (options_ptr != NULL) { 2208 *options_ptr = '\0'; 2209 (void) strlcpy(options, ++options_ptr, 2210 sizeof (options)); 2211 } 2212 } 2213 } 2214 } 2215 prom_close(prom_fd); 2216 2217 /* error */ 2218 if (ret == -1) { 2219 return (ret); 2220 } 2221 2222 (void) strlcpy(ret_buf, alias_def, MAXPATHLEN); 2223 2224 /* override minor name information */ 2225 if (options_ptr != NULL) { 2226 if ((options_ptr = strrchr(ret_buf, ':')) == NULL) { 2227 (void) strcat(ret_buf, ":"); 2228 } else { 2229 *(++options_ptr) = '\0'; 2230 } 2231 (void) strcat(ret_buf, options); 2232 } 2233 return (0); 2234 } 2235 2236 /* 2237 * search a prom node for a property name 2238 */ 2239 static int 2240 prom_srch_node(int fd, char *prop_name, char *ret_buf) 2241 { 2242 Oppbuf oppbuf; 2243 struct openpromio *opp = &(oppbuf.opp); 2244 int *ip = (int *)((void *)opp->oprom_array); 2245 2246 (void) memset(oppbuf.buf, 0, BUFSIZE); 2247 opp->oprom_size = MAXPROPSIZE; 2248 *ip = 0; 2249 2250 if (ioctl(fd, OPROMNXTPROP, opp) < 0) 2251 return (-1); 2252 if (opp->oprom_size == 0) 2253 return (-1); 2254 2255 while (strcmp(prop_name, opp->oprom_array) != 0) { 2256 opp->oprom_size = MAXPROPSIZE; 2257 if (ioctl(fd, OPROMNXTPROP, opp) < 0) 2258 return (-1); 2259 if (opp->oprom_size == 0) 2260 return (-1); 2261 } 2262 opp->oprom_size = MAXVALSIZE; 2263 if (ioctl(fd, OPROMGETPROP, opp) < 0) 2264 return (-1); 2265 2266 if (opp->oprom_size == 0) 2267 return (-1); 2268 (void) strlcpy(ret_buf, opp->oprom_array, MAXPATHLEN); 2269 return (0); 2270 } 2271 2272 /* 2273 * return the aliases node. 2274 */ 2275 static int 2276 prom_find_aliases_node(int fd) 2277 { 2278 uint_t child_id; 2279 char buf[MAXPATHLEN]; 2280 2281 if ((child_id = prom_next_node(fd, 0)) == 0) 2282 return (-1); 2283 if ((child_id = prom_child_node(fd, child_id)) == 0) 2284 return (-1); 2285 2286 while (child_id != 0) { 2287 if (prom_srch_node(fd, "name", buf) == 0) { 2288 if (strcmp(buf, "aliases") == 0) { 2289 return (0); 2290 } 2291 } 2292 child_id = prom_next_node(fd, child_id); 2293 } 2294 return (-1); 2295 } 2296 2297 /* 2298 * get sibling 2299 */ 2300 static uint_t 2301 prom_next_node(int fd, uint_t node_id) 2302 { 2303 Oppbuf oppbuf; 2304 struct openpromio *opp = &(oppbuf.opp); 2305 uint_t *ip = (uint_t *)((void *)opp->oprom_array); 2306 2307 (void) memset(oppbuf.buf, 0, BUFSIZE); 2308 opp->oprom_size = MAXVALSIZE; 2309 *ip = node_id; 2310 2311 if (ioctl(fd, OPROMNEXT, opp) < 0) 2312 return (0); 2313 2314 return (*(uint_t *)((void *)opp->oprom_array)); 2315 } 2316 2317 /* 2318 * get child 2319 */ 2320 static uint_t 2321 prom_child_node(int fd, uint_t node_id) 2322 { 2323 Oppbuf oppbuf; 2324 struct openpromio *opp = &(oppbuf.opp); 2325 uint_t *ip = (uint_t *)((void *)opp->oprom_array); 2326 2327 (void) memset(oppbuf.buf, 0, BUFSIZE); 2328 opp->oprom_size = MAXVALSIZE; 2329 *ip = node_id; 2330 2331 if (ioctl(fd, OPROMCHILD, opp) < 0) 2332 return (0); 2333 2334 return (*(uint_t *)((void *)opp->oprom_array)); 2335 } 2336 2337 /* 2338 * only on sparc for now 2339 */ 2340 int 2341 devfs_bootdev_modifiable(void) 2342 { 2343 #if defined(sparc) 2344 return (0); 2345 #else 2346 return (DEVFS_NOTSUP); 2347 #endif 2348 } 2349