17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5b6f77fefSas158974 * Common Development and Distribution License (the "License"). 6b6f77fefSas158974 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*c279fc79Ssriman bhavanam - Sun Microsystems - Bangalore India * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include <stdio.h> 287c478bd9Sstevel@tonic-gate #include <string.h> 297c478bd9Sstevel@tonic-gate #include <strings.h> 307c478bd9Sstevel@tonic-gate #include <unistd.h> 317c478bd9Sstevel@tonic-gate #include <stdlib.h> 327c478bd9Sstevel@tonic-gate #include <thread.h> 337c478bd9Sstevel@tonic-gate #include <synch.h> 347c478bd9Sstevel@tonic-gate #include <sys/types.h> 357c478bd9Sstevel@tonic-gate #include <ctype.h> 367c478bd9Sstevel@tonic-gate #include <sys/stat.h> 377c478bd9Sstevel@tonic-gate #include <fcntl.h> 387c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 397c478bd9Sstevel@tonic-gate #include <errno.h> 407c478bd9Sstevel@tonic-gate #include <sys/openpromio.h> 417c478bd9Sstevel@tonic-gate #include <ftw.h> 427c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 437c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 447c478bd9Sstevel@tonic-gate #include <limits.h> 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate #include "device_info.h" 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate /* 497c478bd9Sstevel@tonic-gate * #define's 507c478bd9Sstevel@tonic-gate */ 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate /* alias node searching return values */ 537c478bd9Sstevel@tonic-gate #define NO_MATCH -1 547c478bd9Sstevel@tonic-gate #define EXACT_MATCH 1 557c478bd9Sstevel@tonic-gate #define INEXACT_MATCH 2 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate /* for prom io operations */ 587c478bd9Sstevel@tonic-gate #define BUFSIZE 4096 597c478bd9Sstevel@tonic-gate #define MAXPROPSIZE 256 607c478bd9Sstevel@tonic-gate #define MAXVALSIZE (BUFSIZE - MAXPROPSIZE - sizeof (uint_t)) 617c478bd9Sstevel@tonic-gate 62b6f77fefSas158974 /* prom_obp_vers() return values */ 637c478bd9Sstevel@tonic-gate #define OBP_OF 0x4 /* versions OBP 3.x */ 64b6f77fefSas158974 #define OBP_NO_ALIAS_NODE 0x8 /* No alias node */ 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate /* for nftw call */ 677c478bd9Sstevel@tonic-gate #define FT_DEPTH 15 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate /* default logical and physical device name space */ 707c478bd9Sstevel@tonic-gate #define DEV "/dev" 717c478bd9Sstevel@tonic-gate #define DEVICES "/devices" 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate /* for boot device identification on x86 */ 747c478bd9Sstevel@tonic-gate #define CREATE_DISKMAP "/boot/solaris/bin/create_diskmap" 757c478bd9Sstevel@tonic-gate #define GRUBDISK_MAP "/var/run/solaris_grubdisk.map" 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate /* 787c478bd9Sstevel@tonic-gate * internal structure declarations 797c478bd9Sstevel@tonic-gate */ 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate /* for prom io functions */ 827c478bd9Sstevel@tonic-gate typedef union { 837c478bd9Sstevel@tonic-gate char buf[BUFSIZE]; 847c478bd9Sstevel@tonic-gate struct openpromio opp; 857c478bd9Sstevel@tonic-gate } Oppbuf; 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate /* used to manage lists of devices and aliases */ 887c478bd9Sstevel@tonic-gate struct name_list { 897c478bd9Sstevel@tonic-gate char *name; 907c478bd9Sstevel@tonic-gate struct name_list *next; 917c478bd9Sstevel@tonic-gate }; 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate /* 947c478bd9Sstevel@tonic-gate * internal global data 957c478bd9Sstevel@tonic-gate */ 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate /* global since nftw does not let you pass args to be updated */ 987c478bd9Sstevel@tonic-gate static struct name_list **dev_list; 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate /* global since nftw does not let you pass args to be updated */ 1017c478bd9Sstevel@tonic-gate static struct boot_dev **bootdev_list; 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate /* mutex to protect bootdev_list and dev_list */ 1047c478bd9Sstevel@tonic-gate static mutex_t dev_lists_lk = DEFAULTMUTEX; 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate /* 1077c478bd9Sstevel@tonic-gate * internal function prototypes 1087c478bd9Sstevel@tonic-gate */ 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate static int prom_open(int); 1117c478bd9Sstevel@tonic-gate static void prom_close(int); 1127c478bd9Sstevel@tonic-gate static int is_openprom(int); 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate static int prom_dev_to_alias(char *dev, uint_t options, char ***ret_buf); 115b6f77fefSas158974 static int alias_to_prom_dev(char *alias, char *ret_buf); 1167c478bd9Sstevel@tonic-gate static int prom_srch_aliases_by_def(char *, struct name_list **, 1177c478bd9Sstevel@tonic-gate struct name_list **, int); 118b6f77fefSas158974 static int prom_find_aliases_node(int fd); 1197c478bd9Sstevel@tonic-gate static int prom_compare_devs(char *prom_dev1, char *prom_dev2); 1207c478bd9Sstevel@tonic-gate static int _prom_strcmp(char *s1, char *s2); 121b6f77fefSas158974 static int prom_srch_node(int fd, char *prop_name, char *ret_buf); 122b6f77fefSas158974 static uint_t prom_next_node(int fd, uint_t node_id); 123b6f77fefSas158974 static uint_t prom_child_node(int fd, uint_t node_id); 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate static int prom_obp_vers(void); 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate static void parse_name(char *, char **, char **, char **); 1287c478bd9Sstevel@tonic-gate static int process_bootdev(const char *, const char *, struct boot_dev ***); 1297c478bd9Sstevel@tonic-gate static int process_minor_name(char *dev_path, const char *default_root); 1307c478bd9Sstevel@tonic-gate static void options_override(char *prom_path, char *alias_name); 1317c478bd9Sstevel@tonic-gate static int devfs_phys_to_logical(struct boot_dev **bootdev_array, 1327c478bd9Sstevel@tonic-gate const int array_size, const char *default_root); 1337c478bd9Sstevel@tonic-gate static int check_logical_dev(const char *, const struct stat *, int, 1347c478bd9Sstevel@tonic-gate struct FTW *); 1357c478bd9Sstevel@tonic-gate static struct boot_dev *alloc_bootdev(char *); 1367c478bd9Sstevel@tonic-gate static void free_name_list(struct name_list *list, int free_name); 1377c478bd9Sstevel@tonic-gate static int insert_alias_list(struct name_list **list, 1387c478bd9Sstevel@tonic-gate char *alias_name); 1397c478bd9Sstevel@tonic-gate static int get_boot_dev_var(struct openpromio *opp); 1407c478bd9Sstevel@tonic-gate static int set_boot_dev_var(struct openpromio *opp, char *bootdev); 1417c478bd9Sstevel@tonic-gate static int devfs_prom_to_dev_name(char *prom_path, char *dev_path); 1427c478bd9Sstevel@tonic-gate static int devfs_dev_to_prom_names(char *dev_path, char *prom_path, size_t len); 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate /* 1457c478bd9Sstevel@tonic-gate * frees a list of paths from devfs_get_prom_name_list 1467c478bd9Sstevel@tonic-gate */ 1477c478bd9Sstevel@tonic-gate static void 1487c478bd9Sstevel@tonic-gate prom_list_free(char **prom_list) 1497c478bd9Sstevel@tonic-gate { 1507c478bd9Sstevel@tonic-gate int i = 0; 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate if (!prom_list) 1537c478bd9Sstevel@tonic-gate return; 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate while (prom_list[i]) { 1567c478bd9Sstevel@tonic-gate free(prom_list[i]); 1577c478bd9Sstevel@tonic-gate i++; 1587c478bd9Sstevel@tonic-gate } 1597c478bd9Sstevel@tonic-gate free(prom_list); 1607c478bd9Sstevel@tonic-gate } 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate static int 1637c478bd9Sstevel@tonic-gate devfs_get_prom_name_list(const char *dev_name, char ***prom_list) 1647c478bd9Sstevel@tonic-gate { 1657c478bd9Sstevel@tonic-gate char *prom_path = NULL; 1667c478bd9Sstevel@tonic-gate int count = 0; /* # of slots we will need in prom_list */ 1677c478bd9Sstevel@tonic-gate int ret, i, len; 1687c478bd9Sstevel@tonic-gate char **list; 1697c478bd9Sstevel@tonic-gate char *ptr; 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate if (dev_name == NULL) 1727c478bd9Sstevel@tonic-gate return (DEVFS_INVAL); 1737c478bd9Sstevel@tonic-gate if (*dev_name != '/') 1747c478bd9Sstevel@tonic-gate return (DEVFS_INVAL); 1757c478bd9Sstevel@tonic-gate if (prom_list == NULL) 1767c478bd9Sstevel@tonic-gate return (DEVFS_INVAL); 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate /* 1797c478bd9Sstevel@tonic-gate * make sure we are on a machine which supports a prom 1807c478bd9Sstevel@tonic-gate * and we have permission to use /dev/openprom 1817c478bd9Sstevel@tonic-gate */ 1827c478bd9Sstevel@tonic-gate if ((ret = prom_obp_vers()) < 0) 1837c478bd9Sstevel@tonic-gate return (ret); 1847c478bd9Sstevel@tonic-gate if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL) 1857c478bd9Sstevel@tonic-gate return (DEVFS_NOMEM); 1867c478bd9Sstevel@tonic-gate /* 1877c478bd9Sstevel@tonic-gate * get the prom path name 1887c478bd9Sstevel@tonic-gate */ 1897c478bd9Sstevel@tonic-gate ret = devfs_dev_to_prom_names((char *)dev_name, prom_path, MAXVALSIZE); 1907c478bd9Sstevel@tonic-gate if (ret < 0) { 1917c478bd9Sstevel@tonic-gate free(prom_path); 1927c478bd9Sstevel@tonic-gate return (ret); 1937c478bd9Sstevel@tonic-gate } 1947c478bd9Sstevel@tonic-gate /* deal with list of names */ 1957c478bd9Sstevel@tonic-gate for (i = 0; i < ret; i++) 1967c478bd9Sstevel@tonic-gate if (prom_path[i] == '\0') 1977c478bd9Sstevel@tonic-gate count++; 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate if ((list = (char **)calloc(count + 1, sizeof (char *))) == NULL) { 2007c478bd9Sstevel@tonic-gate free(prom_path); 2017c478bd9Sstevel@tonic-gate return (DEVFS_NOMEM); 2027c478bd9Sstevel@tonic-gate } 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate ptr = prom_path; 2057c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++) { 2067c478bd9Sstevel@tonic-gate len = strlen(ptr) + 1; 2077c478bd9Sstevel@tonic-gate if ((list[i] = (char *)malloc(len)) == NULL) { 2087c478bd9Sstevel@tonic-gate free(prom_path); 2097c478bd9Sstevel@tonic-gate free(list); 2107c478bd9Sstevel@tonic-gate return (DEVFS_NOMEM); 2117c478bd9Sstevel@tonic-gate } 2127c478bd9Sstevel@tonic-gate (void) snprintf(list[i], len, "%s", ptr); 2137c478bd9Sstevel@tonic-gate ptr += len; 2147c478bd9Sstevel@tonic-gate } 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate free(prom_path); 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate *prom_list = list; 2197c478bd9Sstevel@tonic-gate return (0); 2207c478bd9Sstevel@tonic-gate } 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate /* 2237c478bd9Sstevel@tonic-gate * retrieve the list of prom representations for a given device name 2247c478bd9Sstevel@tonic-gate * the list will be sorted in the following order: exact aliases, 2257c478bd9Sstevel@tonic-gate * inexact aliases, prom device path name. If multiple matches occur 2267c478bd9Sstevel@tonic-gate * for exact or inexact aliases, then these are sorted in collating 2277c478bd9Sstevel@tonic-gate * order. The list is returned in prom_list 2287c478bd9Sstevel@tonic-gate * 2297c478bd9Sstevel@tonic-gate * the list may be restricted by specifying the correct flags in options. 2307c478bd9Sstevel@tonic-gate */ 2317c478bd9Sstevel@tonic-gate int 2327c478bd9Sstevel@tonic-gate devfs_get_prom_names(const char *dev_name, uint_t options, char ***prom_list) 2337c478bd9Sstevel@tonic-gate { 2347c478bd9Sstevel@tonic-gate char *prom_path = NULL; 2357c478bd9Sstevel@tonic-gate int count = 0; /* # of slots we will need in prom_list */ 2367c478bd9Sstevel@tonic-gate char **alias_list = NULL; 2377c478bd9Sstevel@tonic-gate char **list; 2387c478bd9Sstevel@tonic-gate int ret; 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate if (dev_name == NULL) { 2417c478bd9Sstevel@tonic-gate return (DEVFS_INVAL); 2427c478bd9Sstevel@tonic-gate } 2437c478bd9Sstevel@tonic-gate if (*dev_name != '/') { 2447c478bd9Sstevel@tonic-gate return (DEVFS_INVAL); 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate if (prom_list == NULL) { 2477c478bd9Sstevel@tonic-gate return (DEVFS_INVAL); 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate /* 2507c478bd9Sstevel@tonic-gate * make sure we are on a machine which supports a prom 2517c478bd9Sstevel@tonic-gate * and we have permission to use /dev/openprom 2527c478bd9Sstevel@tonic-gate */ 2537c478bd9Sstevel@tonic-gate if ((ret = prom_obp_vers()) < 0) { 2547c478bd9Sstevel@tonic-gate return (ret); 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate if ((prom_path = (char *)malloc(MAXPATHLEN)) == NULL) { 2577c478bd9Sstevel@tonic-gate return (DEVFS_NOMEM); 2587c478bd9Sstevel@tonic-gate } 2597c478bd9Sstevel@tonic-gate /* 2607c478bd9Sstevel@tonic-gate * get the prom path name 2617c478bd9Sstevel@tonic-gate */ 2627c478bd9Sstevel@tonic-gate ret = devfs_dev_to_prom_name((char *)dev_name, prom_path); 2637c478bd9Sstevel@tonic-gate if (ret < 0) { 2647c478bd9Sstevel@tonic-gate free(prom_path); 2657c478bd9Sstevel@tonic-gate return (ret); 2667c478bd9Sstevel@tonic-gate } 2677c478bd9Sstevel@tonic-gate /* get the list of aliases (exact and inexact) */ 2687c478bd9Sstevel@tonic-gate if ((ret = prom_dev_to_alias(prom_path, options, &alias_list)) < 0) { 2697c478bd9Sstevel@tonic-gate free(prom_path); 2707c478bd9Sstevel@tonic-gate return (ret); 2717c478bd9Sstevel@tonic-gate } 2727c478bd9Sstevel@tonic-gate /* now figure out how big the return array must be */ 2737c478bd9Sstevel@tonic-gate if (alias_list != NULL) { 2747c478bd9Sstevel@tonic-gate while (alias_list[count] != NULL) { 2757c478bd9Sstevel@tonic-gate count++; 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate } 2787c478bd9Sstevel@tonic-gate if ((options & BOOTDEV_NO_PROM_PATH) == 0) { 2797c478bd9Sstevel@tonic-gate count++; /* # of slots we will need in prom_list */ 2807c478bd9Sstevel@tonic-gate } 2817c478bd9Sstevel@tonic-gate count++; /* for the null terminator */ 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate /* allocate space for the list */ 2847c478bd9Sstevel@tonic-gate if ((list = (char **)calloc(count, sizeof (char *))) == NULL) { 2857c478bd9Sstevel@tonic-gate count = 0; 2867c478bd9Sstevel@tonic-gate while ((alias_list) && (alias_list[count] != NULL)) { 2877c478bd9Sstevel@tonic-gate free(alias_list[count]); 2887c478bd9Sstevel@tonic-gate count++; 2897c478bd9Sstevel@tonic-gate } 2907c478bd9Sstevel@tonic-gate free(alias_list); 2917c478bd9Sstevel@tonic-gate free(prom_path); 2927c478bd9Sstevel@tonic-gate return (DEVFS_NOMEM); 2937c478bd9Sstevel@tonic-gate } 2947c478bd9Sstevel@tonic-gate /* fill in the array and free the name list of aliases. */ 2957c478bd9Sstevel@tonic-gate count = 0; 2967c478bd9Sstevel@tonic-gate while ((alias_list) && (alias_list[count] != NULL)) { 2977c478bd9Sstevel@tonic-gate list[count] = alias_list[count]; 2987c478bd9Sstevel@tonic-gate count++; 2997c478bd9Sstevel@tonic-gate } 3007c478bd9Sstevel@tonic-gate if ((options & BOOTDEV_NO_PROM_PATH) == 0) { 3017c478bd9Sstevel@tonic-gate list[count] = prom_path; 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate if (alias_list != NULL) { 3047c478bd9Sstevel@tonic-gate free(alias_list); 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate *prom_list = list; 3077c478bd9Sstevel@tonic-gate return (0); 3087c478bd9Sstevel@tonic-gate } 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate /* 3117c478bd9Sstevel@tonic-gate * Get a list prom-path translations for a solaris device. 3127c478bd9Sstevel@tonic-gate * 3137c478bd9Sstevel@tonic-gate * Returns the number of and all OBP paths and alias variants that 3147c478bd9Sstevel@tonic-gate * reference the Solaris device path passed in. 3157c478bd9Sstevel@tonic-gate */ 3167c478bd9Sstevel@tonic-gate int 3177c478bd9Sstevel@tonic-gate devfs_get_all_prom_names(const char *solaris_path, uint_t flags, 3187c478bd9Sstevel@tonic-gate struct devfs_prom_path **paths) 3197c478bd9Sstevel@tonic-gate { 3207c478bd9Sstevel@tonic-gate int ret, len, i, count = 0; 3217c478bd9Sstevel@tonic-gate char *ptr, *prom_path; 3227c478bd9Sstevel@tonic-gate struct devfs_prom_path *cur = NULL, *new; 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate if ((ret = prom_obp_vers()) < 0) 3257c478bd9Sstevel@tonic-gate return (ret); 3267c478bd9Sstevel@tonic-gate if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL) 3277c478bd9Sstevel@tonic-gate return (DEVFS_NOMEM); 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate if ((ret = devfs_dev_to_prom_names((char *)solaris_path, 3307c478bd9Sstevel@tonic-gate prom_path, MAXVALSIZE)) < 0) { 3317c478bd9Sstevel@tonic-gate free(prom_path); 3327c478bd9Sstevel@tonic-gate return (ret); 3337c478bd9Sstevel@tonic-gate } 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate for (i = 0; i < ret; i++) 3367c478bd9Sstevel@tonic-gate if (prom_path[i] == '\0') 3377c478bd9Sstevel@tonic-gate count++; 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate *paths = NULL; 3407c478bd9Sstevel@tonic-gate ptr = prom_path; 3417c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++) { 3427c478bd9Sstevel@tonic-gate if ((new = (struct devfs_prom_path *)calloc( 3437c478bd9Sstevel@tonic-gate sizeof (struct devfs_prom_path), 1)) == NULL) { 3447c478bd9Sstevel@tonic-gate free(prom_path); 3457c478bd9Sstevel@tonic-gate devfs_free_all_prom_names(*paths); 3467c478bd9Sstevel@tonic-gate return (DEVFS_NOMEM); 3477c478bd9Sstevel@tonic-gate } 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate if (cur == NULL) 3507c478bd9Sstevel@tonic-gate *paths = new; 3517c478bd9Sstevel@tonic-gate else 3527c478bd9Sstevel@tonic-gate cur->next = new; 3537c478bd9Sstevel@tonic-gate cur = new; 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate len = strlen(ptr) + 1; 3567c478bd9Sstevel@tonic-gate if ((cur->obp_path = (char *)calloc(len, 1)) == NULL) { 3577c478bd9Sstevel@tonic-gate free(prom_path); 3587c478bd9Sstevel@tonic-gate devfs_free_all_prom_names(*paths); 3597c478bd9Sstevel@tonic-gate return (DEVFS_NOMEM); 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate (void) snprintf(cur->obp_path, len, "%s", ptr); 3637c478bd9Sstevel@tonic-gate ptr += len; 3647c478bd9Sstevel@tonic-gate if ((ret = prom_dev_to_alias(cur->obp_path, flags, 3657c478bd9Sstevel@tonic-gate &(cur->alias_list))) < 0) { 3667c478bd9Sstevel@tonic-gate free(prom_path); 3677c478bd9Sstevel@tonic-gate devfs_free_all_prom_names(*paths); 3687c478bd9Sstevel@tonic-gate return (ret); 3697c478bd9Sstevel@tonic-gate } 3707c478bd9Sstevel@tonic-gate } 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate free(prom_path); 3737c478bd9Sstevel@tonic-gate return (count); 3747c478bd9Sstevel@tonic-gate } 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate void 3777c478bd9Sstevel@tonic-gate devfs_free_all_prom_names(struct devfs_prom_path *paths) 3787c478bd9Sstevel@tonic-gate { 3797c478bd9Sstevel@tonic-gate int i; 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate if (paths == NULL) 3827c478bd9Sstevel@tonic-gate return; 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate devfs_free_all_prom_names(paths->next); 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate if (paths->obp_path != NULL) 3877c478bd9Sstevel@tonic-gate free(paths->obp_path); 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate if (paths->alias_list != NULL) { 3907c478bd9Sstevel@tonic-gate for (i = 0; paths->alias_list[i] != NULL; i++) 3917c478bd9Sstevel@tonic-gate if (paths->alias_list[i] != NULL) 3927c478bd9Sstevel@tonic-gate free(paths->alias_list[i]); 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate free(paths->alias_list); 3957c478bd9Sstevel@tonic-gate } 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate free(paths); 3987c478bd9Sstevel@tonic-gate } 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate /* 4017c478bd9Sstevel@tonic-gate * Accepts a device name as an input argument. Uses this to set the 4027c478bd9Sstevel@tonic-gate * boot-device (or like) variable 4037c478bd9Sstevel@tonic-gate * 4047c478bd9Sstevel@tonic-gate * By default, this routine prepends to the list and converts the 4057c478bd9Sstevel@tonic-gate * logical device name to its most compact prom representation. 4067c478bd9Sstevel@tonic-gate * Available options include: converting the device name to a prom 4077c478bd9Sstevel@tonic-gate * path name (but not an alias) or performing no conversion at all; 4087c478bd9Sstevel@tonic-gate * overwriting the existing contents of boot-device rather than 4097c478bd9Sstevel@tonic-gate * prepending. 4107c478bd9Sstevel@tonic-gate */ 4117c478bd9Sstevel@tonic-gate int 4127c478bd9Sstevel@tonic-gate devfs_bootdev_set_list(const char *dev_name, const uint_t options) 4137c478bd9Sstevel@tonic-gate { 4147c478bd9Sstevel@tonic-gate char *prom_path; 4157c478bd9Sstevel@tonic-gate char *new_bootdev; 4167c478bd9Sstevel@tonic-gate char *ptr; 4177c478bd9Sstevel@tonic-gate char **alias_list = NULL; 4187c478bd9Sstevel@tonic-gate char **prom_list = NULL; 4197c478bd9Sstevel@tonic-gate Oppbuf oppbuf; 4207c478bd9Sstevel@tonic-gate struct openpromio *opp = &(oppbuf.opp); 4217c478bd9Sstevel@tonic-gate int ret, len, i, j; 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate if (devfs_bootdev_modifiable() != 0) { 4247c478bd9Sstevel@tonic-gate return (DEVFS_NOTSUP); 4257c478bd9Sstevel@tonic-gate } 4267c478bd9Sstevel@tonic-gate if (dev_name == NULL) { 4277c478bd9Sstevel@tonic-gate return (DEVFS_INVAL); 4287c478bd9Sstevel@tonic-gate } 4297c478bd9Sstevel@tonic-gate if (strlen(dev_name) >= MAXPATHLEN) 4307c478bd9Sstevel@tonic-gate return (DEVFS_INVAL); 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate if ((*dev_name != '/') && !(options & BOOTDEV_LITERAL)) { 4337c478bd9Sstevel@tonic-gate return (DEVFS_INVAL); 4347c478bd9Sstevel@tonic-gate } 4357c478bd9Sstevel@tonic-gate if ((options & BOOTDEV_LITERAL) && (options & BOOTDEV_PROMDEV)) { 4367c478bd9Sstevel@tonic-gate return (DEVFS_INVAL); 4377c478bd9Sstevel@tonic-gate } 4387c478bd9Sstevel@tonic-gate /* 4397c478bd9Sstevel@tonic-gate * if we are prepending, make sure that this obp rev 4407c478bd9Sstevel@tonic-gate * supports multiple boot device entries. 4417c478bd9Sstevel@tonic-gate */ 4427c478bd9Sstevel@tonic-gate ret = prom_obp_vers(); 4437c478bd9Sstevel@tonic-gate if (ret < 0) { 4447c478bd9Sstevel@tonic-gate return (ret); 4457c478bd9Sstevel@tonic-gate } 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL) { 4487c478bd9Sstevel@tonic-gate return (DEVFS_NOMEM); 4497c478bd9Sstevel@tonic-gate } 4507c478bd9Sstevel@tonic-gate if (options & BOOTDEV_LITERAL) { 4517c478bd9Sstevel@tonic-gate (void) strcpy(prom_path, dev_name); 4527c478bd9Sstevel@tonic-gate } else { 4537c478bd9Sstevel@tonic-gate /* need to convert to prom representation */ 4547c478bd9Sstevel@tonic-gate ret = devfs_get_prom_name_list(dev_name, &prom_list); 4557c478bd9Sstevel@tonic-gate if (ret < 0) { 4567c478bd9Sstevel@tonic-gate free(prom_path); 4577c478bd9Sstevel@tonic-gate return (ret); 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate len = MAXVALSIZE; 4617c478bd9Sstevel@tonic-gate i = 0; 4627c478bd9Sstevel@tonic-gate ptr = prom_path; 4637c478bd9Sstevel@tonic-gate while (prom_list && prom_list[i]) { 4647c478bd9Sstevel@tonic-gate if (!(options & BOOTDEV_PROMDEV)) { 4657c478bd9Sstevel@tonic-gate ret = prom_dev_to_alias(prom_list[i], 0, 4667c478bd9Sstevel@tonic-gate &alias_list); 4677c478bd9Sstevel@tonic-gate if (ret < 0) { 4687c478bd9Sstevel@tonic-gate free(prom_path); 4697c478bd9Sstevel@tonic-gate prom_list_free(prom_list); 4707c478bd9Sstevel@tonic-gate return (ret); 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate if ((alias_list != NULL) && 4737c478bd9Sstevel@tonic-gate (alias_list[0] != NULL)) { 4747c478bd9Sstevel@tonic-gate (void) snprintf(ptr, len, "%s ", 4757c478bd9Sstevel@tonic-gate alias_list[0]); 4767c478bd9Sstevel@tonic-gate for (ret = 0; alias_list[ret] != NULL; 4777c478bd9Sstevel@tonic-gate ret++) 4787c478bd9Sstevel@tonic-gate free(alias_list[ret]); 4797c478bd9Sstevel@tonic-gate } else { 4807c478bd9Sstevel@tonic-gate (void) snprintf(ptr, len, "%s ", 4817c478bd9Sstevel@tonic-gate prom_list[i]); 4827c478bd9Sstevel@tonic-gate } 4837c478bd9Sstevel@tonic-gate if (alias_list != NULL) 4847c478bd9Sstevel@tonic-gate free(alias_list); 4857c478bd9Sstevel@tonic-gate } else { 4867c478bd9Sstevel@tonic-gate (void) snprintf(ptr, len, "%s ", prom_list[i]); 4877c478bd9Sstevel@tonic-gate } 4887c478bd9Sstevel@tonic-gate j = strlen(ptr); 4897c478bd9Sstevel@tonic-gate len -= j; 4907c478bd9Sstevel@tonic-gate ptr += j; 4917c478bd9Sstevel@tonic-gate i++; 4927c478bd9Sstevel@tonic-gate } 4937c478bd9Sstevel@tonic-gate ptr--; 4947c478bd9Sstevel@tonic-gate *ptr = NULL; 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate prom_list_free(prom_list); 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate if (options & BOOTDEV_OVERWRITE) { 4997c478bd9Sstevel@tonic-gate new_bootdev = prom_path; 5007c478bd9Sstevel@tonic-gate } else { 5017c478bd9Sstevel@tonic-gate /* retrieve the current value of boot-device */ 5027c478bd9Sstevel@tonic-gate ret = get_boot_dev_var(opp); 5037c478bd9Sstevel@tonic-gate if (ret < 0) { 5047c478bd9Sstevel@tonic-gate free(prom_path); 5057c478bd9Sstevel@tonic-gate return (ret); 5067c478bd9Sstevel@tonic-gate } 5077c478bd9Sstevel@tonic-gate /* prepend new entry - deal with duplicates */ 5087c478bd9Sstevel@tonic-gate new_bootdev = (char *)malloc(strlen(opp->oprom_array) 5097c478bd9Sstevel@tonic-gate + strlen(prom_path) + 2); 5107c478bd9Sstevel@tonic-gate if (new_bootdev == NULL) { 5117c478bd9Sstevel@tonic-gate free(prom_path); 5127c478bd9Sstevel@tonic-gate return (DEVFS_NOMEM); 5137c478bd9Sstevel@tonic-gate } 5147c478bd9Sstevel@tonic-gate (void) strcpy(new_bootdev, prom_path); 5157c478bd9Sstevel@tonic-gate if (opp->oprom_size > 0) { 5167c478bd9Sstevel@tonic-gate for (ptr = strtok(opp->oprom_array, " "); ptr != NULL; 5177c478bd9Sstevel@tonic-gate ptr = strtok(NULL, " ")) { 5187c478bd9Sstevel@tonic-gate /* we strip out duplicates */ 5197c478bd9Sstevel@tonic-gate if (strcmp(prom_path, ptr) == 0) { 5207c478bd9Sstevel@tonic-gate continue; 5217c478bd9Sstevel@tonic-gate } 5227c478bd9Sstevel@tonic-gate (void) strcat(new_bootdev, " "); 5237c478bd9Sstevel@tonic-gate (void) strcat(new_bootdev, ptr); 5247c478bd9Sstevel@tonic-gate } 5257c478bd9Sstevel@tonic-gate } 5267c478bd9Sstevel@tonic-gate } 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate /* now set the new value */ 5297c478bd9Sstevel@tonic-gate ret = set_boot_dev_var(opp, new_bootdev); 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate if (options & BOOTDEV_OVERWRITE) { 5327c478bd9Sstevel@tonic-gate free(prom_path); 5337c478bd9Sstevel@tonic-gate } else { 5347c478bd9Sstevel@tonic-gate free(new_bootdev); 5357c478bd9Sstevel@tonic-gate free(prom_path); 5367c478bd9Sstevel@tonic-gate } 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate return (ret); 5397c478bd9Sstevel@tonic-gate } 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate /* 5427c478bd9Sstevel@tonic-gate * sets the string bootdev as the new value for boot-device 5437c478bd9Sstevel@tonic-gate */ 5447c478bd9Sstevel@tonic-gate static int 5457c478bd9Sstevel@tonic-gate set_boot_dev_var(struct openpromio *opp, char *bootdev) 5467c478bd9Sstevel@tonic-gate { 5477c478bd9Sstevel@tonic-gate int prom_fd; 5487c478bd9Sstevel@tonic-gate int i; 5497c478bd9Sstevel@tonic-gate int ret; 5507c478bd9Sstevel@tonic-gate char *valbuf; 5517c478bd9Sstevel@tonic-gate char *save_bootdev; 5527c478bd9Sstevel@tonic-gate char *bootdev_variables[] = { 5537c478bd9Sstevel@tonic-gate "boot-device", 5547c478bd9Sstevel@tonic-gate "bootdev", 5557c478bd9Sstevel@tonic-gate "boot-from", 5567c478bd9Sstevel@tonic-gate NULL 5577c478bd9Sstevel@tonic-gate }; 5587c478bd9Sstevel@tonic-gate int found = 0; 5597c478bd9Sstevel@tonic-gate int *ip = (int *)((void *)opp->oprom_array); 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate /* query the prom */ 5627c478bd9Sstevel@tonic-gate prom_fd = prom_open(O_RDWR); 5637c478bd9Sstevel@tonic-gate if (prom_fd < 0) { 5647c478bd9Sstevel@tonic-gate return (prom_fd); 5657c478bd9Sstevel@tonic-gate } 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate /* get the diagnostic-mode? property */ 5687c478bd9Sstevel@tonic-gate (void) strcpy(opp->oprom_array, "diagnostic-mode?"); 5697c478bd9Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE; 5707c478bd9Sstevel@tonic-gate if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) { 5717c478bd9Sstevel@tonic-gate if ((opp->oprom_size > 0) && 5727c478bd9Sstevel@tonic-gate (strcmp(opp->oprom_array, "true") == 0)) { 5737c478bd9Sstevel@tonic-gate prom_close(prom_fd); 5747c478bd9Sstevel@tonic-gate return (DEVFS_ERR); 5757c478bd9Sstevel@tonic-gate } 5767c478bd9Sstevel@tonic-gate } 5777c478bd9Sstevel@tonic-gate /* get the diag-switch? property */ 5787c478bd9Sstevel@tonic-gate (void) strcpy(opp->oprom_array, "diag-switch?"); 5797c478bd9Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE; 5807c478bd9Sstevel@tonic-gate if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) { 5817c478bd9Sstevel@tonic-gate if ((opp->oprom_size > 0) && 5827c478bd9Sstevel@tonic-gate (strcmp(opp->oprom_array, "true") == 0)) { 5837c478bd9Sstevel@tonic-gate prom_close(prom_fd); 5847c478bd9Sstevel@tonic-gate return (DEVFS_ERR); 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate } 5877c478bd9Sstevel@tonic-gate /* 5887c478bd9Sstevel@tonic-gate * look for one of the following properties in order: 5897c478bd9Sstevel@tonic-gate * boot-device 5907c478bd9Sstevel@tonic-gate * bootdev 5917c478bd9Sstevel@tonic-gate * boot-from 5927c478bd9Sstevel@tonic-gate * 5937c478bd9Sstevel@tonic-gate * Use the first one that we find. 5947c478bd9Sstevel@tonic-gate */ 5957c478bd9Sstevel@tonic-gate *ip = 0; 5967c478bd9Sstevel@tonic-gate opp->oprom_size = MAXPROPSIZE; 5977c478bd9Sstevel@tonic-gate while ((opp->oprom_size != 0) && (!found)) { 5987c478bd9Sstevel@tonic-gate opp->oprom_size = MAXPROPSIZE; 5997c478bd9Sstevel@tonic-gate if (ioctl(prom_fd, OPROMNXTOPT, opp) < 0) { 6007c478bd9Sstevel@tonic-gate break; 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate for (i = 0; bootdev_variables[i] != NULL; i++) { 6037c478bd9Sstevel@tonic-gate if (strcmp(opp->oprom_array, bootdev_variables[i]) 6047c478bd9Sstevel@tonic-gate == 0) { 6057c478bd9Sstevel@tonic-gate found = 1; 6067c478bd9Sstevel@tonic-gate break; 6077c478bd9Sstevel@tonic-gate } 6087c478bd9Sstevel@tonic-gate } 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate if (found) { 6117c478bd9Sstevel@tonic-gate (void) strcpy(opp->oprom_array, bootdev_variables[i]); 6127c478bd9Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE; 6137c478bd9Sstevel@tonic-gate if (ioctl(prom_fd, OPROMGETOPT, opp) < 0) { 6147c478bd9Sstevel@tonic-gate prom_close(prom_fd); 6157c478bd9Sstevel@tonic-gate return (DEVFS_NOTSUP); 6167c478bd9Sstevel@tonic-gate } 6177c478bd9Sstevel@tonic-gate } else { 6187c478bd9Sstevel@tonic-gate prom_close(prom_fd); 6197c478bd9Sstevel@tonic-gate return (DEVFS_NOTSUP); 6207c478bd9Sstevel@tonic-gate } 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate /* save the old copy in case we fail */ 6237c478bd9Sstevel@tonic-gate if ((save_bootdev = strdup(opp->oprom_array)) == NULL) { 6247c478bd9Sstevel@tonic-gate prom_close(prom_fd); 6257c478bd9Sstevel@tonic-gate return (DEVFS_NOMEM); 6267c478bd9Sstevel@tonic-gate } 6277c478bd9Sstevel@tonic-gate /* set up the new value of boot-device */ 6287c478bd9Sstevel@tonic-gate (void) strcpy(opp->oprom_array, bootdev_variables[i]); 6297c478bd9Sstevel@tonic-gate valbuf = opp->oprom_array + strlen(opp->oprom_array) + 1; 6307c478bd9Sstevel@tonic-gate (void) strcpy(valbuf, bootdev); 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate opp->oprom_size = strlen(valbuf) + strlen(opp->oprom_array) + 2; 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate if (ioctl(prom_fd, OPROMSETOPT, opp) < 0) { 6357c478bd9Sstevel@tonic-gate free(save_bootdev); 6367c478bd9Sstevel@tonic-gate prom_close(prom_fd); 6377c478bd9Sstevel@tonic-gate return (DEVFS_ERR); 6387c478bd9Sstevel@tonic-gate } 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate /* 6417c478bd9Sstevel@tonic-gate * now read it back to make sure it took 6427c478bd9Sstevel@tonic-gate */ 6437c478bd9Sstevel@tonic-gate (void) strcpy(opp->oprom_array, bootdev_variables[i]); 6447c478bd9Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE; 6457c478bd9Sstevel@tonic-gate if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) { 6467c478bd9Sstevel@tonic-gate if (_prom_strcmp(opp->oprom_array, bootdev) == 0) { 6477c478bd9Sstevel@tonic-gate /* success */ 6487c478bd9Sstevel@tonic-gate free(save_bootdev); 6497c478bd9Sstevel@tonic-gate prom_close(prom_fd); 6507c478bd9Sstevel@tonic-gate return (0); 6517c478bd9Sstevel@tonic-gate } 6527c478bd9Sstevel@tonic-gate /* deal with setting it to "" */ 6537c478bd9Sstevel@tonic-gate if ((strlen(bootdev) == 0) && (opp->oprom_size == 0)) { 6547c478bd9Sstevel@tonic-gate /* success */ 6557c478bd9Sstevel@tonic-gate free(save_bootdev); 6567c478bd9Sstevel@tonic-gate prom_close(prom_fd); 6577c478bd9Sstevel@tonic-gate return (0); 6587c478bd9Sstevel@tonic-gate } 6597c478bd9Sstevel@tonic-gate } 6607c478bd9Sstevel@tonic-gate /* 6617c478bd9Sstevel@tonic-gate * something did not take - write out the old value and 6627c478bd9Sstevel@tonic-gate * hope that we can restore things... 6637c478bd9Sstevel@tonic-gate * 6647c478bd9Sstevel@tonic-gate * unfortunately, there is no way for us to differentiate 6657c478bd9Sstevel@tonic-gate * whether we exceeded the maximum number of characters 6667c478bd9Sstevel@tonic-gate * allowable. The limit varies from prom rev to prom 6677c478bd9Sstevel@tonic-gate * rev, and on some proms, when the limit is 6687c478bd9Sstevel@tonic-gate * exceeded, whatever was in the 6697c478bd9Sstevel@tonic-gate * boot-device variable becomes unreadable. 6707c478bd9Sstevel@tonic-gate * 6717c478bd9Sstevel@tonic-gate * so if we fail, we will assume we ran out of room. If we 6727c478bd9Sstevel@tonic-gate * not able to restore the original setting, then we will 6737c478bd9Sstevel@tonic-gate * return DEVFS_ERR instead. 6747c478bd9Sstevel@tonic-gate */ 6757c478bd9Sstevel@tonic-gate ret = DEVFS_LIMIT; 6767c478bd9Sstevel@tonic-gate (void) strcpy(opp->oprom_array, bootdev_variables[i]); 6777c478bd9Sstevel@tonic-gate valbuf = opp->oprom_array + strlen(opp->oprom_array) + 1; 6787c478bd9Sstevel@tonic-gate (void) strcpy(valbuf, save_bootdev); 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate opp->oprom_size = strlen(valbuf) + strlen(opp->oprom_array) + 2; 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate if (ioctl(prom_fd, OPROMSETOPT, opp) < 0) { 6837c478bd9Sstevel@tonic-gate ret = DEVFS_ERR; 6847c478bd9Sstevel@tonic-gate } 6857c478bd9Sstevel@tonic-gate free(save_bootdev); 6867c478bd9Sstevel@tonic-gate prom_close(prom_fd); 6877c478bd9Sstevel@tonic-gate return (ret); 6887c478bd9Sstevel@tonic-gate } 6897c478bd9Sstevel@tonic-gate /* 6907c478bd9Sstevel@tonic-gate * retrieve the current value for boot-device 6917c478bd9Sstevel@tonic-gate */ 6927c478bd9Sstevel@tonic-gate static int 6937c478bd9Sstevel@tonic-gate get_boot_dev_var(struct openpromio *opp) 6947c478bd9Sstevel@tonic-gate { 6957c478bd9Sstevel@tonic-gate int prom_fd; 6967c478bd9Sstevel@tonic-gate int i; 6977c478bd9Sstevel@tonic-gate char *bootdev_variables[] = { 6987c478bd9Sstevel@tonic-gate "boot-device", 6997c478bd9Sstevel@tonic-gate "bootdev", 7007c478bd9Sstevel@tonic-gate "boot-from", 7017c478bd9Sstevel@tonic-gate NULL 7027c478bd9Sstevel@tonic-gate }; 7037c478bd9Sstevel@tonic-gate int found = 0; 7047c478bd9Sstevel@tonic-gate int *ip = (int *)((void *)opp->oprom_array); 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate /* query the prom */ 7077c478bd9Sstevel@tonic-gate prom_fd = prom_open(O_RDONLY); 7087c478bd9Sstevel@tonic-gate if (prom_fd < 0) { 7097c478bd9Sstevel@tonic-gate return (prom_fd); 7107c478bd9Sstevel@tonic-gate } 7117c478bd9Sstevel@tonic-gate 7127c478bd9Sstevel@tonic-gate /* get the diagnostic-mode? property */ 7137c478bd9Sstevel@tonic-gate (void) strcpy(opp->oprom_array, "diagnostic-mode?"); 7147c478bd9Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE; 7157c478bd9Sstevel@tonic-gate if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) { 7167c478bd9Sstevel@tonic-gate if ((opp->oprom_size > 0) && 7177c478bd9Sstevel@tonic-gate (strcmp(opp->oprom_array, "true") == 0)) { 7187c478bd9Sstevel@tonic-gate prom_close(prom_fd); 7197c478bd9Sstevel@tonic-gate return (DEVFS_ERR); 7207c478bd9Sstevel@tonic-gate } 7217c478bd9Sstevel@tonic-gate } 7227c478bd9Sstevel@tonic-gate /* get the diag-switch? property */ 7237c478bd9Sstevel@tonic-gate (void) strcpy(opp->oprom_array, "diag-switch?"); 7247c478bd9Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE; 7257c478bd9Sstevel@tonic-gate if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) { 7267c478bd9Sstevel@tonic-gate if ((opp->oprom_size > 0) && 7277c478bd9Sstevel@tonic-gate (strcmp(opp->oprom_array, "true") == 0)) { 7287c478bd9Sstevel@tonic-gate prom_close(prom_fd); 7297c478bd9Sstevel@tonic-gate return (DEVFS_ERR); 7307c478bd9Sstevel@tonic-gate } 7317c478bd9Sstevel@tonic-gate } 7327c478bd9Sstevel@tonic-gate /* 7337c478bd9Sstevel@tonic-gate * look for one of the following properties in order: 7347c478bd9Sstevel@tonic-gate * boot-device 7357c478bd9Sstevel@tonic-gate * bootdev 7367c478bd9Sstevel@tonic-gate * boot-from 7377c478bd9Sstevel@tonic-gate * 7387c478bd9Sstevel@tonic-gate * Use the first one that we find. 7397c478bd9Sstevel@tonic-gate */ 7407c478bd9Sstevel@tonic-gate *ip = 0; 7417c478bd9Sstevel@tonic-gate opp->oprom_size = MAXPROPSIZE; 7427c478bd9Sstevel@tonic-gate while ((opp->oprom_size != 0) && (!found)) { 7437c478bd9Sstevel@tonic-gate opp->oprom_size = MAXPROPSIZE; 7447c478bd9Sstevel@tonic-gate if (ioctl(prom_fd, OPROMNXTOPT, opp) < 0) { 7457c478bd9Sstevel@tonic-gate break; 7467c478bd9Sstevel@tonic-gate } 7477c478bd9Sstevel@tonic-gate for (i = 0; bootdev_variables[i] != NULL; i++) { 7487c478bd9Sstevel@tonic-gate if (strcmp(opp->oprom_array, bootdev_variables[i]) 7497c478bd9Sstevel@tonic-gate == 0) { 7507c478bd9Sstevel@tonic-gate found = 1; 7517c478bd9Sstevel@tonic-gate break; 7527c478bd9Sstevel@tonic-gate } 7537c478bd9Sstevel@tonic-gate } 7547c478bd9Sstevel@tonic-gate } 7557c478bd9Sstevel@tonic-gate if (found) { 7567c478bd9Sstevel@tonic-gate (void) strcpy(opp->oprom_array, bootdev_variables[i]); 7577c478bd9Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE; 7587c478bd9Sstevel@tonic-gate if (ioctl(prom_fd, OPROMGETOPT, opp) < 0) { 7597c478bd9Sstevel@tonic-gate prom_close(prom_fd); 7607c478bd9Sstevel@tonic-gate return (DEVFS_ERR); 7617c478bd9Sstevel@tonic-gate } 7627c478bd9Sstevel@tonic-gate /* boot-device exists but contains nothing */ 7637c478bd9Sstevel@tonic-gate if (opp->oprom_size == 0) { 7647c478bd9Sstevel@tonic-gate *opp->oprom_array = '\0'; 7657c478bd9Sstevel@tonic-gate } 7667c478bd9Sstevel@tonic-gate } else { 7677c478bd9Sstevel@tonic-gate prom_close(prom_fd); 7687c478bd9Sstevel@tonic-gate return (DEVFS_NOTSUP); 7697c478bd9Sstevel@tonic-gate } 7707c478bd9Sstevel@tonic-gate prom_close(prom_fd); 7717c478bd9Sstevel@tonic-gate return (0); 7727c478bd9Sstevel@tonic-gate } 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate #ifndef __sparc 7757c478bd9Sstevel@tonic-gate static FILE * 7767c478bd9Sstevel@tonic-gate open_diskmap(void) 7777c478bd9Sstevel@tonic-gate { 7787c478bd9Sstevel@tonic-gate FILE *fp; 7797c478bd9Sstevel@tonic-gate char cmd[PATH_MAX]; 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate /* make sure we have a map file */ 7827c478bd9Sstevel@tonic-gate fp = fopen(GRUBDISK_MAP, "r"); 7837c478bd9Sstevel@tonic-gate if (fp == NULL) { 7847c478bd9Sstevel@tonic-gate (void) snprintf(cmd, sizeof (cmd), 7857c478bd9Sstevel@tonic-gate "%s > /dev/null", CREATE_DISKMAP); 7867c478bd9Sstevel@tonic-gate (void) system(cmd); 7877c478bd9Sstevel@tonic-gate fp = fopen(GRUBDISK_MAP, "r"); 7887c478bd9Sstevel@tonic-gate } 7897c478bd9Sstevel@tonic-gate return (fp); 7907c478bd9Sstevel@tonic-gate } 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate static int 7937c478bd9Sstevel@tonic-gate find_x86_boot_device(struct openpromio *opp) 7947c478bd9Sstevel@tonic-gate { 7957c478bd9Sstevel@tonic-gate int ret = DEVFS_ERR; 7967c478bd9Sstevel@tonic-gate char *cp, line[MAXVALSIZE + 6]; 7977c478bd9Sstevel@tonic-gate FILE *file; 7987c478bd9Sstevel@tonic-gate 7997c478bd9Sstevel@tonic-gate file = open_diskmap(); 8007c478bd9Sstevel@tonic-gate if (file == NULL) 8017c478bd9Sstevel@tonic-gate return (DEVFS_ERR); 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate while (fgets(line, MAXVALSIZE + 6, file)) { 8047c478bd9Sstevel@tonic-gate if (strncmp(line, "0 ", 2) != 0) 8057c478bd9Sstevel@tonic-gate continue; 8067c478bd9Sstevel@tonic-gate /* drop new-line */ 8077c478bd9Sstevel@tonic-gate line[strlen(line) - 1] = '\0'; 8087c478bd9Sstevel@tonic-gate /* 8097c478bd9Sstevel@tonic-gate * an x86 BIOS only boots a disk, not a partition 8107c478bd9Sstevel@tonic-gate * or a slice, so hard-code :q (p0) 8117c478bd9Sstevel@tonic-gate */ 8127c478bd9Sstevel@tonic-gate cp = strchr(line + 2, ' '); 8137c478bd9Sstevel@tonic-gate if (cp == NULL) 8147c478bd9Sstevel@tonic-gate break; 8157c478bd9Sstevel@tonic-gate (void) snprintf(opp->oprom_array, MAXVALSIZE, 8167c478bd9Sstevel@tonic-gate "%s:q", cp + 1); 8177c478bd9Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE; 8187c478bd9Sstevel@tonic-gate ret = 0; 8197c478bd9Sstevel@tonic-gate break; 8207c478bd9Sstevel@tonic-gate } 8217c478bd9Sstevel@tonic-gate (void) fclose(file); 8227c478bd9Sstevel@tonic-gate return (ret); 8237c478bd9Sstevel@tonic-gate } 8247c478bd9Sstevel@tonic-gate #endif /* ndef __sparc */ 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate /* 8277c478bd9Sstevel@tonic-gate * retrieve the list of entries in the boot-device configuration 8287c478bd9Sstevel@tonic-gate * variable. An array of boot_dev structs will be created, one entry 8297c478bd9Sstevel@tonic-gate * for each device name in the boot-device variable. Each entry 8307c478bd9Sstevel@tonic-gate * in the array will contain the logical device representation of the 8317c478bd9Sstevel@tonic-gate * boot-device entry, if any. 8327c478bd9Sstevel@tonic-gate * 8337c478bd9Sstevel@tonic-gate * default_root. if set, is used to locate logical device entries in 8347c478bd9Sstevel@tonic-gate * directories other than /dev 8357c478bd9Sstevel@tonic-gate */ 8367c478bd9Sstevel@tonic-gate int 8377c478bd9Sstevel@tonic-gate devfs_bootdev_get_list(const char *default_root, 8387c478bd9Sstevel@tonic-gate struct boot_dev ***bootdev_list) 8397c478bd9Sstevel@tonic-gate { 8407c478bd9Sstevel@tonic-gate Oppbuf oppbuf; 8417c478bd9Sstevel@tonic-gate struct openpromio *opp = &(oppbuf.opp); 8427c478bd9Sstevel@tonic-gate int i; 8437c478bd9Sstevel@tonic-gate struct boot_dev **tmp_list; 8447c478bd9Sstevel@tonic-gate 8457c478bd9Sstevel@tonic-gate if (default_root == NULL) { 8467c478bd9Sstevel@tonic-gate default_root = ""; 8477c478bd9Sstevel@tonic-gate } else if (*default_root != '/') { 8487c478bd9Sstevel@tonic-gate return (DEVFS_INVAL); 8497c478bd9Sstevel@tonic-gate } 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate if (bootdev_list == NULL) { 8527c478bd9Sstevel@tonic-gate return (DEVFS_INVAL); 8537c478bd9Sstevel@tonic-gate } 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate /* get the boot-device variable */ 8567c478bd9Sstevel@tonic-gate #if defined(sparc) 8577c478bd9Sstevel@tonic-gate i = get_boot_dev_var(opp); 8587c478bd9Sstevel@tonic-gate #else 8597c478bd9Sstevel@tonic-gate i = find_x86_boot_device(opp); 8607c478bd9Sstevel@tonic-gate #endif 8617c478bd9Sstevel@tonic-gate if (i < 0) { 8627c478bd9Sstevel@tonic-gate return (i); 8637c478bd9Sstevel@tonic-gate } 8647c478bd9Sstevel@tonic-gate /* now try to translate each entry to a logical device. */ 8657c478bd9Sstevel@tonic-gate i = process_bootdev(opp->oprom_array, default_root, &tmp_list); 8667c478bd9Sstevel@tonic-gate if (i == 0) { 8677c478bd9Sstevel@tonic-gate *bootdev_list = tmp_list; 8687c478bd9Sstevel@tonic-gate return (0); 8697c478bd9Sstevel@tonic-gate } else { 8707c478bd9Sstevel@tonic-gate return (i); 8717c478bd9Sstevel@tonic-gate } 8727c478bd9Sstevel@tonic-gate } 8737c478bd9Sstevel@tonic-gate 8747c478bd9Sstevel@tonic-gate /* 8757c478bd9Sstevel@tonic-gate * loop thru the list of entries in a boot-device configuration 8767c478bd9Sstevel@tonic-gate * variable. 8777c478bd9Sstevel@tonic-gate */ 8787c478bd9Sstevel@tonic-gate static int 8797c478bd9Sstevel@tonic-gate process_bootdev(const char *bootdevice, const char *default_root, 8807c478bd9Sstevel@tonic-gate struct boot_dev ***list) 8817c478bd9Sstevel@tonic-gate { 8827c478bd9Sstevel@tonic-gate int i; 8837c478bd9Sstevel@tonic-gate char *entry, *ptr; 8847c478bd9Sstevel@tonic-gate char prom_path[MAXPATHLEN]; 8857c478bd9Sstevel@tonic-gate char ret_buf[MAXPATHLEN]; 8867c478bd9Sstevel@tonic-gate struct boot_dev **bootdev_array; 8877c478bd9Sstevel@tonic-gate int num_entries = 0; 8887c478bd9Sstevel@tonic-gate int found = 0; 8897c478bd9Sstevel@tonic-gate int vers; 8907c478bd9Sstevel@tonic-gate 8917c478bd9Sstevel@tonic-gate if ((entry = (char *)malloc(strlen(bootdevice) + 1)) == NULL) { 8927c478bd9Sstevel@tonic-gate return (DEVFS_NOMEM); 8937c478bd9Sstevel@tonic-gate } 8947c478bd9Sstevel@tonic-gate /* count the number of entries */ 8957c478bd9Sstevel@tonic-gate (void) strcpy(entry, bootdevice); 8967c478bd9Sstevel@tonic-gate for (ptr = strtok(entry, " "); ptr != NULL; 8977c478bd9Sstevel@tonic-gate ptr = strtok(NULL, " ")) { 8987c478bd9Sstevel@tonic-gate num_entries++; 8997c478bd9Sstevel@tonic-gate } 9007c478bd9Sstevel@tonic-gate (void) strcpy(entry, bootdevice); 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate bootdev_array = (struct boot_dev **) 9037c478bd9Sstevel@tonic-gate calloc((size_t)num_entries + 1, sizeof (struct boot_dev *)); 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate if (bootdev_array == NULL) { 9067c478bd9Sstevel@tonic-gate free(entry); 9077c478bd9Sstevel@tonic-gate return (DEVFS_NOMEM); 9087c478bd9Sstevel@tonic-gate } 9097c478bd9Sstevel@tonic-gate 9107c478bd9Sstevel@tonic-gate vers = prom_obp_vers(); 9117c478bd9Sstevel@tonic-gate if (vers < 0) { 9127c478bd9Sstevel@tonic-gate free(entry); 9137c478bd9Sstevel@tonic-gate return (vers); 9147c478bd9Sstevel@tonic-gate } 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate /* for each entry in boot-device, do... */ 9177c478bd9Sstevel@tonic-gate for (ptr = strtok(entry, " "), i = 0; ptr != NULL; 9187c478bd9Sstevel@tonic-gate ptr = strtok(NULL, " "), i++) { 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate if ((bootdev_array[i] = alloc_bootdev(ptr)) == NULL) { 9217c478bd9Sstevel@tonic-gate devfs_bootdev_free_list(bootdev_array); 9227c478bd9Sstevel@tonic-gate free(entry); 9237c478bd9Sstevel@tonic-gate return (DEVFS_NOMEM); 9247c478bd9Sstevel@tonic-gate } 9257c478bd9Sstevel@tonic-gate 926b6f77fefSas158974 /* 927b6f77fefSas158974 * prom boot-device may be aliased, so we need to do 928b6f77fefSas158974 * the necessary prom alias to dev translation. 929b6f77fefSas158974 */ 930b6f77fefSas158974 if (*ptr != '/') { 931b6f77fefSas158974 if (alias_to_prom_dev(ptr, prom_path) < 0) { 932b6f77fefSas158974 continue; 933b6f77fefSas158974 } 934b6f77fefSas158974 } else { 9357c478bd9Sstevel@tonic-gate (void) strcpy(prom_path, ptr); 936b6f77fefSas158974 } 937b6f77fefSas158974 9387c478bd9Sstevel@tonic-gate /* now we have a prom device path - convert to a devfs name */ 9397c478bd9Sstevel@tonic-gate if (devfs_prom_to_dev_name(prom_path, ret_buf) < 0) { 9407c478bd9Sstevel@tonic-gate continue; 9417c478bd9Sstevel@tonic-gate } 942b6f77fefSas158974 9437c478bd9Sstevel@tonic-gate /* append any default minor names necessary */ 9447c478bd9Sstevel@tonic-gate if (process_minor_name(ret_buf, default_root) < 0) { 9457c478bd9Sstevel@tonic-gate continue; 9467c478bd9Sstevel@tonic-gate } 9477c478bd9Sstevel@tonic-gate found = 1; 948b6f77fefSas158974 9497c478bd9Sstevel@tonic-gate /* 9507c478bd9Sstevel@tonic-gate * store the physical device path for now - when 9517c478bd9Sstevel@tonic-gate * we are all done with the entries, we will convert 9527c478bd9Sstevel@tonic-gate * these to their logical device name equivalents 9537c478bd9Sstevel@tonic-gate */ 9547c478bd9Sstevel@tonic-gate bootdev_array[i]->bootdev_trans[0] = strdup(ret_buf); 9557c478bd9Sstevel@tonic-gate } 9567c478bd9Sstevel@tonic-gate /* 9577c478bd9Sstevel@tonic-gate * Convert all of the boot-device entries that translated to a 9587c478bd9Sstevel@tonic-gate * physical device path in /devices to a logical device path 9597c478bd9Sstevel@tonic-gate * in /dev (note that there may be several logical device paths 9607c478bd9Sstevel@tonic-gate * associated with a single physical device path - return them all 9617c478bd9Sstevel@tonic-gate */ 9627c478bd9Sstevel@tonic-gate if (found) { 9637c478bd9Sstevel@tonic-gate if (devfs_phys_to_logical(bootdev_array, num_entries, 9647c478bd9Sstevel@tonic-gate default_root) < 0) { 9657c478bd9Sstevel@tonic-gate devfs_bootdev_free_list(bootdev_array); 9667c478bd9Sstevel@tonic-gate bootdev_array = NULL; 9677c478bd9Sstevel@tonic-gate } 9687c478bd9Sstevel@tonic-gate } 9697c478bd9Sstevel@tonic-gate free(entry); 9707c478bd9Sstevel@tonic-gate *list = bootdev_array; 9717c478bd9Sstevel@tonic-gate return (0); 9727c478bd9Sstevel@tonic-gate } 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate /* 9757c478bd9Sstevel@tonic-gate * We may get a device path from the prom that has no minor name 9767c478bd9Sstevel@tonic-gate * information included in it. Since this device name will not 9777c478bd9Sstevel@tonic-gate * correspond directly to a physical device in /devices, we do our 9787c478bd9Sstevel@tonic-gate * best to append what the default minor name should be and try this. 9797c478bd9Sstevel@tonic-gate * 9807c478bd9Sstevel@tonic-gate * For sparc: we append slice 0 (:a). 9817c478bd9Sstevel@tonic-gate * For x86: we append fdisk partition 0 (:q). 9827c478bd9Sstevel@tonic-gate */ 9837c478bd9Sstevel@tonic-gate static int 9847c478bd9Sstevel@tonic-gate process_minor_name(char *dev_path, const char *root) 9857c478bd9Sstevel@tonic-gate { 9867c478bd9Sstevel@tonic-gate char *cp; 9877c478bd9Sstevel@tonic-gate #if defined(sparc) 9887c478bd9Sstevel@tonic-gate const char *default_minor_name = "a"; 9897c478bd9Sstevel@tonic-gate #else 9907c478bd9Sstevel@tonic-gate const char *default_minor_name = "q"; 9917c478bd9Sstevel@tonic-gate #endif 9927c478bd9Sstevel@tonic-gate int n; 9937c478bd9Sstevel@tonic-gate struct stat stat_buf; 9947c478bd9Sstevel@tonic-gate char path[MAXPATHLEN]; 9957c478bd9Sstevel@tonic-gate 9967c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s%s", root, DEVICES, dev_path); 9977c478bd9Sstevel@tonic-gate /* 9987c478bd9Sstevel@tonic-gate * if the device file already exists as given to us, there 9997c478bd9Sstevel@tonic-gate * is nothing to do but return. 10007c478bd9Sstevel@tonic-gate */ 10017c478bd9Sstevel@tonic-gate if (stat(path, &stat_buf) == 0) { 10027c478bd9Sstevel@tonic-gate return (0); 10037c478bd9Sstevel@tonic-gate } 10047c478bd9Sstevel@tonic-gate /* 10057c478bd9Sstevel@tonic-gate * if there is no ':' after the last '/' character, or if there is 10067c478bd9Sstevel@tonic-gate * a ':' with no specifier, append the default segment specifier 10077c478bd9Sstevel@tonic-gate * ; if there is a ':' followed by a digit, this indicates 10087c478bd9Sstevel@tonic-gate * a partition number (which does not map into the /devices name 10097c478bd9Sstevel@tonic-gate * space), so strip the number and replace it with the letter 10107c478bd9Sstevel@tonic-gate * that represents the partition index 10117c478bd9Sstevel@tonic-gate */ 10127c478bd9Sstevel@tonic-gate if ((cp = strrchr(dev_path, '/')) != NULL) { 10137c478bd9Sstevel@tonic-gate if ((cp = strchr(cp, ':')) == NULL) { 10147c478bd9Sstevel@tonic-gate (void) strcat(dev_path, ":"); 10157c478bd9Sstevel@tonic-gate (void) strcat(dev_path, default_minor_name); 10167c478bd9Sstevel@tonic-gate } else if (*++cp == '\0') { 10177c478bd9Sstevel@tonic-gate (void) strcat(dev_path, default_minor_name); 10187c478bd9Sstevel@tonic-gate } else if (isdigit(*cp)) { 10197c478bd9Sstevel@tonic-gate n = atoi(cp); 10207c478bd9Sstevel@tonic-gate /* make sure to squash the digit */ 10217c478bd9Sstevel@tonic-gate *cp = '\0'; 10227c478bd9Sstevel@tonic-gate switch (n) { 10237c478bd9Sstevel@tonic-gate case 0: (void) strcat(dev_path, "q"); 10247c478bd9Sstevel@tonic-gate break; 10257c478bd9Sstevel@tonic-gate case 1: (void) strcat(dev_path, "r"); 10267c478bd9Sstevel@tonic-gate break; 10277c478bd9Sstevel@tonic-gate case 2: (void) strcat(dev_path, "s"); 10287c478bd9Sstevel@tonic-gate break; 10297c478bd9Sstevel@tonic-gate case 3: (void) strcat(dev_path, "t"); 10307c478bd9Sstevel@tonic-gate break; 10317c478bd9Sstevel@tonic-gate case 4: (void) strcat(dev_path, "u"); 10327c478bd9Sstevel@tonic-gate break; 10337c478bd9Sstevel@tonic-gate default: (void) strcat(dev_path, "a"); 10347c478bd9Sstevel@tonic-gate break; 10357c478bd9Sstevel@tonic-gate } 10367c478bd9Sstevel@tonic-gate } 10377c478bd9Sstevel@tonic-gate } 10387c478bd9Sstevel@tonic-gate /* 10397c478bd9Sstevel@tonic-gate * see if we can find something now. 10407c478bd9Sstevel@tonic-gate */ 10417c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s%s", root, DEVICES, dev_path); 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate if (stat(path, &stat_buf) == 0) { 10447c478bd9Sstevel@tonic-gate return (0); 10457c478bd9Sstevel@tonic-gate } else { 10467c478bd9Sstevel@tonic-gate return (-1); 10477c478bd9Sstevel@tonic-gate } 10487c478bd9Sstevel@tonic-gate } 10497c478bd9Sstevel@tonic-gate 10507c478bd9Sstevel@tonic-gate /* 10517c478bd9Sstevel@tonic-gate * for each entry in bootdev_array, convert the physical device 10527c478bd9Sstevel@tonic-gate * representation of the boot-device entry to one or more logical device 10537c478bd9Sstevel@tonic-gate * entries. We use the hammer method - walk through the logical device 10547c478bd9Sstevel@tonic-gate * name space looking for matches (/dev). We use nftw to do this. 10557c478bd9Sstevel@tonic-gate */ 10567c478bd9Sstevel@tonic-gate static int 10577c478bd9Sstevel@tonic-gate devfs_phys_to_logical(struct boot_dev **bootdev_array, const int array_size, 10587c478bd9Sstevel@tonic-gate const char *default_root) 10597c478bd9Sstevel@tonic-gate { 10607c478bd9Sstevel@tonic-gate int walk_flags = FTW_PHYS | FTW_MOUNT; 10617c478bd9Sstevel@tonic-gate char *full_path; 10627c478bd9Sstevel@tonic-gate struct name_list *list; 10637c478bd9Sstevel@tonic-gate int count, i; 10647c478bd9Sstevel@tonic-gate char **dev_name_array; 10657c478bd9Sstevel@tonic-gate size_t default_root_len; 10667c478bd9Sstevel@tonic-gate char *dev_dir = DEV; 10677c478bd9Sstevel@tonic-gate int len; 10687c478bd9Sstevel@tonic-gate 10697c478bd9Sstevel@tonic-gate if (array_size < 0) { 10707c478bd9Sstevel@tonic-gate return (-1); 10717c478bd9Sstevel@tonic-gate } 10727c478bd9Sstevel@tonic-gate 10737c478bd9Sstevel@tonic-gate if (bootdev_array == NULL) { 10747c478bd9Sstevel@tonic-gate return (-1); 10757c478bd9Sstevel@tonic-gate } 10767c478bd9Sstevel@tonic-gate if (default_root == NULL) { 10777c478bd9Sstevel@tonic-gate return (-1); 10787c478bd9Sstevel@tonic-gate } 10797c478bd9Sstevel@tonic-gate default_root_len = strlen(default_root); 10807c478bd9Sstevel@tonic-gate if ((default_root_len != 0) && (*default_root != '/')) { 10817c478bd9Sstevel@tonic-gate return (-1); 10827c478bd9Sstevel@tonic-gate } 1083b6f77fefSas158974 10847c478bd9Sstevel@tonic-gate /* short cut for an empty array */ 10857c478bd9Sstevel@tonic-gate if (*bootdev_array == NULL) { 10867c478bd9Sstevel@tonic-gate return (0); 10877c478bd9Sstevel@tonic-gate } 10887c478bd9Sstevel@tonic-gate 10897c478bd9Sstevel@tonic-gate /* tell nftw where to start (default: /dev) */ 10907c478bd9Sstevel@tonic-gate len = default_root_len + strlen(dev_dir) + 1; 10917c478bd9Sstevel@tonic-gate if ((full_path = (char *)malloc(len)) == NULL) { 10927c478bd9Sstevel@tonic-gate return (-1); 10937c478bd9Sstevel@tonic-gate } 1094b6f77fefSas158974 10957c478bd9Sstevel@tonic-gate /* 10967c478bd9Sstevel@tonic-gate * if the default root path is terminated with a /, we have to 10977c478bd9Sstevel@tonic-gate * make sure we don't end up with one too many slashes in the 10987c478bd9Sstevel@tonic-gate * path we are building. 10997c478bd9Sstevel@tonic-gate */ 11007c478bd9Sstevel@tonic-gate if ((default_root_len > (size_t)0) && 11017c478bd9Sstevel@tonic-gate (default_root[default_root_len - 1] == '/')) { 11027c478bd9Sstevel@tonic-gate (void) snprintf(full_path, len, "%s%s", default_root, 11037c478bd9Sstevel@tonic-gate &dev_dir[1]); 11047c478bd9Sstevel@tonic-gate } else { 11057c478bd9Sstevel@tonic-gate (void) snprintf(full_path, len, "%s%s", default_root, dev_dir); 11067c478bd9Sstevel@tonic-gate } 11077c478bd9Sstevel@tonic-gate 11087c478bd9Sstevel@tonic-gate /* 11097c478bd9Sstevel@tonic-gate * we need to muck with global data to make nftw work 11107c478bd9Sstevel@tonic-gate * so single thread access 11117c478bd9Sstevel@tonic-gate */ 11127c478bd9Sstevel@tonic-gate (void) mutex_lock(&dev_lists_lk); 11137c478bd9Sstevel@tonic-gate 11147c478bd9Sstevel@tonic-gate /* 11157c478bd9Sstevel@tonic-gate * set the global vars bootdev_list and dev_list for use by nftw 11167c478bd9Sstevel@tonic-gate * dev_list is an array of lists - one for each boot-device 11177c478bd9Sstevel@tonic-gate * entry. The nftw function will create a list of logical device 11187c478bd9Sstevel@tonic-gate * entries for each boot-device and put all of the lists in 11197c478bd9Sstevel@tonic-gate * dev_list. 11207c478bd9Sstevel@tonic-gate */ 11217c478bd9Sstevel@tonic-gate dev_list = (struct name_list **) 11227c478bd9Sstevel@tonic-gate calloc(array_size, sizeof (struct name_list *)); 11237c478bd9Sstevel@tonic-gate if (dev_list == NULL) { 11247c478bd9Sstevel@tonic-gate free(full_path); 11257c478bd9Sstevel@tonic-gate (void) mutex_unlock(&dev_lists_lk); 11267c478bd9Sstevel@tonic-gate return (-1); 11277c478bd9Sstevel@tonic-gate } 11287c478bd9Sstevel@tonic-gate bootdev_list = bootdev_array; 11297c478bd9Sstevel@tonic-gate 11307c478bd9Sstevel@tonic-gate if (nftw(full_path, check_logical_dev, FT_DEPTH, walk_flags) == -1) { 11317c478bd9Sstevel@tonic-gate bootdev_list = NULL; 11327c478bd9Sstevel@tonic-gate free(full_path); 11337c478bd9Sstevel@tonic-gate for (i = 0; i < array_size; i++) { 11347c478bd9Sstevel@tonic-gate free_name_list(dev_list[i], 1); 11357c478bd9Sstevel@tonic-gate } 11367c478bd9Sstevel@tonic-gate /* don't free dev_list here because it's been handed off */ 11377c478bd9Sstevel@tonic-gate dev_list = NULL; 11387c478bd9Sstevel@tonic-gate (void) mutex_unlock(&dev_lists_lk); 11397c478bd9Sstevel@tonic-gate return (-1); 11407c478bd9Sstevel@tonic-gate } 1141b6f77fefSas158974 11427c478bd9Sstevel@tonic-gate /* 11437c478bd9Sstevel@tonic-gate * now we have a filled in dev_list. So for each logical device 11447c478bd9Sstevel@tonic-gate * list in dev_list, count the number of entries in the list, 11457c478bd9Sstevel@tonic-gate * create an array of strings of logical devices, and save in the 11467c478bd9Sstevel@tonic-gate * corresponding boot_dev structure. 11477c478bd9Sstevel@tonic-gate */ 11487c478bd9Sstevel@tonic-gate for (i = 0; i < array_size; i++) { 11497c478bd9Sstevel@tonic-gate /* get the next list */ 11507c478bd9Sstevel@tonic-gate list = dev_list[i]; 11517c478bd9Sstevel@tonic-gate count = 0; 11527c478bd9Sstevel@tonic-gate 11537c478bd9Sstevel@tonic-gate /* count the number of entries in the list */ 11547c478bd9Sstevel@tonic-gate while (list != NULL) { 11557c478bd9Sstevel@tonic-gate count++; 11567c478bd9Sstevel@tonic-gate list = list->next; 11577c478bd9Sstevel@tonic-gate } 11587c478bd9Sstevel@tonic-gate if ((dev_name_array = 11597c478bd9Sstevel@tonic-gate (char **)malloc((count + 1) * sizeof (char *))) 11607c478bd9Sstevel@tonic-gate == NULL) { 11617c478bd9Sstevel@tonic-gate continue; 11627c478bd9Sstevel@tonic-gate } 11637c478bd9Sstevel@tonic-gate list = dev_list[i]; 11647c478bd9Sstevel@tonic-gate count = 0; 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate /* fill in the array */ 11677c478bd9Sstevel@tonic-gate while (list != NULL) { 11687c478bd9Sstevel@tonic-gate dev_name_array[count] = list->name; 11697c478bd9Sstevel@tonic-gate count++; 11707c478bd9Sstevel@tonic-gate list = list->next; 11717c478bd9Sstevel@tonic-gate } 1172b6f77fefSas158974 11737c478bd9Sstevel@tonic-gate /* 11747c478bd9Sstevel@tonic-gate * null terminate the array 11757c478bd9Sstevel@tonic-gate */ 11767c478bd9Sstevel@tonic-gate dev_name_array[count] = NULL; 1177b6f77fefSas158974 if ((bootdev_array[i] != NULL) && (bootdev_array[i]-> 1178b6f77fefSas158974 bootdev_trans[0] != NULL)) { 11797c478bd9Sstevel@tonic-gate free(bootdev_array[i]->bootdev_trans[0]); 11807c478bd9Sstevel@tonic-gate } 1181b6f77fefSas158974 if (bootdev_array[i] != NULL) { 11827c478bd9Sstevel@tonic-gate free(bootdev_array[i]->bootdev_trans); 11837c478bd9Sstevel@tonic-gate bootdev_array[i]->bootdev_trans = dev_name_array; 11847c478bd9Sstevel@tonic-gate } 1185b6f77fefSas158974 } 11867c478bd9Sstevel@tonic-gate bootdev_list = NULL; 11877c478bd9Sstevel@tonic-gate free(full_path); 11887c478bd9Sstevel@tonic-gate for (i = 0; i < array_size; i++) { 11897c478bd9Sstevel@tonic-gate free_name_list(dev_list[i], 0); 11907c478bd9Sstevel@tonic-gate } 11917c478bd9Sstevel@tonic-gate free(dev_list); 11927c478bd9Sstevel@tonic-gate dev_list = NULL; 11937c478bd9Sstevel@tonic-gate (void) mutex_unlock(&dev_lists_lk); 11947c478bd9Sstevel@tonic-gate return (0); 11957c478bd9Sstevel@tonic-gate } 11967c478bd9Sstevel@tonic-gate /* 11977c478bd9Sstevel@tonic-gate * nftw function 11987c478bd9Sstevel@tonic-gate * for a logical dev entry, it walks the list of boot-devices and 11997c478bd9Sstevel@tonic-gate * sees if there are any matches. If so, it saves the logical device 12007c478bd9Sstevel@tonic-gate * name off in the appropriate list in dev_list 12017c478bd9Sstevel@tonic-gate */ 12027c478bd9Sstevel@tonic-gate /* ARGSUSED */ 12037c478bd9Sstevel@tonic-gate static int 12047c478bd9Sstevel@tonic-gate check_logical_dev(const char *node, const struct stat *node_stat, int flags, 12057c478bd9Sstevel@tonic-gate struct FTW *ftw_info) 12067c478bd9Sstevel@tonic-gate { 12077c478bd9Sstevel@tonic-gate char link_buf[MAXPATHLEN]; 12087c478bd9Sstevel@tonic-gate int link_buf_len; 12097c478bd9Sstevel@tonic-gate char *name; 12107c478bd9Sstevel@tonic-gate struct name_list *dev; 12117c478bd9Sstevel@tonic-gate char *physdev; 12127c478bd9Sstevel@tonic-gate int i; 12137c478bd9Sstevel@tonic-gate 12147c478bd9Sstevel@tonic-gate if (flags != FTW_SL) { 12157c478bd9Sstevel@tonic-gate return (0); 12167c478bd9Sstevel@tonic-gate } 12177c478bd9Sstevel@tonic-gate 12187c478bd9Sstevel@tonic-gate if ((link_buf_len = readlink(node, (void *)link_buf, MAXPATHLEN)) 12197c478bd9Sstevel@tonic-gate == -1) { 12207c478bd9Sstevel@tonic-gate return (0); 12217c478bd9Sstevel@tonic-gate } 12227c478bd9Sstevel@tonic-gate link_buf[link_buf_len] = '\0'; 12237c478bd9Sstevel@tonic-gate if ((name = strstr(link_buf, DEVICES)) == NULL) { 12247c478bd9Sstevel@tonic-gate return (0); 12257c478bd9Sstevel@tonic-gate } 12267c478bd9Sstevel@tonic-gate name = (char *)(name + strlen(DEVICES)); 12277c478bd9Sstevel@tonic-gate 12287c478bd9Sstevel@tonic-gate for (i = 0; bootdev_list[i] != NULL; i++) { 12297c478bd9Sstevel@tonic-gate if (bootdev_list[i]->bootdev_trans[0] == NULL) { 12307c478bd9Sstevel@tonic-gate continue; 12317c478bd9Sstevel@tonic-gate } 12327c478bd9Sstevel@tonic-gate /* 12337c478bd9Sstevel@tonic-gate * compare the contents of the link with the physical 12347c478bd9Sstevel@tonic-gate * device representation of this boot device 12357c478bd9Sstevel@tonic-gate */ 12367c478bd9Sstevel@tonic-gate physdev = bootdev_list[i]->bootdev_trans[0]; 12377c478bd9Sstevel@tonic-gate if ((strcmp(name, physdev) == 0) && 12387c478bd9Sstevel@tonic-gate (strlen(name) == strlen(physdev))) { 12397c478bd9Sstevel@tonic-gate if ((dev = (struct name_list *) 12407c478bd9Sstevel@tonic-gate malloc(sizeof (struct name_list))) == NULL) { 12417c478bd9Sstevel@tonic-gate return (-1); 12427c478bd9Sstevel@tonic-gate } 12437c478bd9Sstevel@tonic-gate if ((dev->name = strdup(node)) == NULL) { 12447c478bd9Sstevel@tonic-gate free(dev); 12457c478bd9Sstevel@tonic-gate return (-1); 12467c478bd9Sstevel@tonic-gate } 12477c478bd9Sstevel@tonic-gate if (dev_list[i] == NULL) { 12487c478bd9Sstevel@tonic-gate dev_list[i] = dev; 12497c478bd9Sstevel@tonic-gate dev_list[i]->next = NULL; 12507c478bd9Sstevel@tonic-gate } else { 12517c478bd9Sstevel@tonic-gate dev->next = dev_list[i]; 12527c478bd9Sstevel@tonic-gate dev_list[i] = dev; 12537c478bd9Sstevel@tonic-gate } 12547c478bd9Sstevel@tonic-gate } 12557c478bd9Sstevel@tonic-gate } 12567c478bd9Sstevel@tonic-gate return (0); 12577c478bd9Sstevel@tonic-gate } 12587c478bd9Sstevel@tonic-gate 12597c478bd9Sstevel@tonic-gate /* 12607c478bd9Sstevel@tonic-gate * frees a list of boot_dev struct pointers 12617c478bd9Sstevel@tonic-gate */ 12627c478bd9Sstevel@tonic-gate void 12637c478bd9Sstevel@tonic-gate devfs_bootdev_free_list(struct boot_dev **array) 12647c478bd9Sstevel@tonic-gate { 12657c478bd9Sstevel@tonic-gate int i = 0; 12667c478bd9Sstevel@tonic-gate int j; 12677c478bd9Sstevel@tonic-gate 12687c478bd9Sstevel@tonic-gate if (array == NULL) { 12697c478bd9Sstevel@tonic-gate return; 12707c478bd9Sstevel@tonic-gate } 12717c478bd9Sstevel@tonic-gate 12727c478bd9Sstevel@tonic-gate while (array[i] != NULL) { 12737c478bd9Sstevel@tonic-gate free(array[i]->bootdev_element); 12747c478bd9Sstevel@tonic-gate j = 0; 12757c478bd9Sstevel@tonic-gate while (array[i]->bootdev_trans[j] != NULL) { 12767c478bd9Sstevel@tonic-gate free(array[i]->bootdev_trans[j++]); 12777c478bd9Sstevel@tonic-gate } 12787c478bd9Sstevel@tonic-gate free(array[i]->bootdev_trans); 12797c478bd9Sstevel@tonic-gate free(array[i]); 12807c478bd9Sstevel@tonic-gate i++; 12817c478bd9Sstevel@tonic-gate } 12827c478bd9Sstevel@tonic-gate free(array); 12837c478bd9Sstevel@tonic-gate } 12847c478bd9Sstevel@tonic-gate /* 12857c478bd9Sstevel@tonic-gate * allocates a boot_dev struct and fills in the bootdev_element portion 12867c478bd9Sstevel@tonic-gate */ 12877c478bd9Sstevel@tonic-gate static struct boot_dev * 12887c478bd9Sstevel@tonic-gate alloc_bootdev(char *entry_name) 12897c478bd9Sstevel@tonic-gate { 12907c478bd9Sstevel@tonic-gate struct boot_dev *entry; 12917c478bd9Sstevel@tonic-gate 12927c478bd9Sstevel@tonic-gate entry = (struct boot_dev *)calloc(1, sizeof (struct boot_dev)); 12937c478bd9Sstevel@tonic-gate 12947c478bd9Sstevel@tonic-gate if (entry == NULL) { 12957c478bd9Sstevel@tonic-gate return (NULL); 12967c478bd9Sstevel@tonic-gate } 12977c478bd9Sstevel@tonic-gate if ((entry->bootdev_element = strdup(entry_name)) == NULL) { 12987c478bd9Sstevel@tonic-gate free(entry); 12997c478bd9Sstevel@tonic-gate return (NULL); 13007c478bd9Sstevel@tonic-gate } 13017c478bd9Sstevel@tonic-gate /* 13027c478bd9Sstevel@tonic-gate * Allocate room for 1 name and a null terminator - the caller of 13037c478bd9Sstevel@tonic-gate * this function will need the first slot right away. 13047c478bd9Sstevel@tonic-gate */ 13057c478bd9Sstevel@tonic-gate if ((entry->bootdev_trans = (char **)calloc(2, sizeof (char *))) 13067c478bd9Sstevel@tonic-gate == NULL) { 13077c478bd9Sstevel@tonic-gate free(entry->bootdev_element); 13087c478bd9Sstevel@tonic-gate free(entry); 13097c478bd9Sstevel@tonic-gate return (NULL); 13107c478bd9Sstevel@tonic-gate } 13117c478bd9Sstevel@tonic-gate return (entry); 13127c478bd9Sstevel@tonic-gate } 13137c478bd9Sstevel@tonic-gate 13147c478bd9Sstevel@tonic-gate /* 13157c478bd9Sstevel@tonic-gate * will come back with a concatenated list of paths 13167c478bd9Sstevel@tonic-gate */ 13177c478bd9Sstevel@tonic-gate int 13187c478bd9Sstevel@tonic-gate devfs_dev_to_prom_names(char *dev_path, char *prom_path, size_t len) 13197c478bd9Sstevel@tonic-gate { 13207c478bd9Sstevel@tonic-gate Oppbuf oppbuf; 13217c478bd9Sstevel@tonic-gate struct openpromio *opp = &(oppbuf.opp); 13227c478bd9Sstevel@tonic-gate int prom_fd; 13237c478bd9Sstevel@tonic-gate int ret = DEVFS_INVAL; 13247c478bd9Sstevel@tonic-gate int i; 13257c478bd9Sstevel@tonic-gate 13267c478bd9Sstevel@tonic-gate if (prom_path == NULL) { 13277c478bd9Sstevel@tonic-gate return (DEVFS_INVAL); 13287c478bd9Sstevel@tonic-gate } 13297c478bd9Sstevel@tonic-gate if (dev_path == NULL) { 13307c478bd9Sstevel@tonic-gate return (DEVFS_INVAL); 13317c478bd9Sstevel@tonic-gate } 13327c478bd9Sstevel@tonic-gate if (strlen(dev_path) >= MAXPATHLEN) 13337c478bd9Sstevel@tonic-gate return (DEVFS_INVAL); 13347c478bd9Sstevel@tonic-gate 13357c478bd9Sstevel@tonic-gate if (*dev_path != '/') 13367c478bd9Sstevel@tonic-gate return (DEVFS_INVAL); 13377c478bd9Sstevel@tonic-gate 13387c478bd9Sstevel@tonic-gate prom_fd = prom_open(O_RDONLY); 13397c478bd9Sstevel@tonic-gate if (prom_fd < 0) { 13407c478bd9Sstevel@tonic-gate return (prom_fd); 13417c478bd9Sstevel@tonic-gate } 13427c478bd9Sstevel@tonic-gate 13437c478bd9Sstevel@tonic-gate /* query the prom */ 13447c478bd9Sstevel@tonic-gate (void) snprintf(opp->oprom_array, MAXVALSIZE, "%s", dev_path); 13457c478bd9Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE; 13467c478bd9Sstevel@tonic-gate 13477c478bd9Sstevel@tonic-gate if (ioctl(prom_fd, OPROMDEV2PROMNAME, opp) == 0) { 13487c478bd9Sstevel@tonic-gate prom_close(prom_fd); 13497c478bd9Sstevel@tonic-gate 13507c478bd9Sstevel@tonic-gate /* return the prom path in prom_path */ 13517c478bd9Sstevel@tonic-gate 13527c478bd9Sstevel@tonic-gate i = len - opp->oprom_size; 13537c478bd9Sstevel@tonic-gate if (i < 0) { 13547c478bd9Sstevel@tonic-gate bcopy(opp->oprom_array, prom_path, len); 13557c478bd9Sstevel@tonic-gate prom_path[len - 1] = NULL; 13567c478bd9Sstevel@tonic-gate return (len); 13577c478bd9Sstevel@tonic-gate } else { 13587c478bd9Sstevel@tonic-gate bcopy(opp->oprom_array, prom_path, len); 13597c478bd9Sstevel@tonic-gate return (opp->oprom_size); 13607c478bd9Sstevel@tonic-gate } 13617c478bd9Sstevel@tonic-gate } 13627c478bd9Sstevel@tonic-gate /* 13637c478bd9Sstevel@tonic-gate * either the prom does not support this ioctl or the argument 13647c478bd9Sstevel@tonic-gate * was invalid. 13657c478bd9Sstevel@tonic-gate */ 13667c478bd9Sstevel@tonic-gate if (errno == ENXIO) { 13677c478bd9Sstevel@tonic-gate ret = DEVFS_NOTSUP; 13687c478bd9Sstevel@tonic-gate } 13697c478bd9Sstevel@tonic-gate prom_close(prom_fd); 13707c478bd9Sstevel@tonic-gate return (ret); 13717c478bd9Sstevel@tonic-gate } 13727c478bd9Sstevel@tonic-gate 13737c478bd9Sstevel@tonic-gate /* 13747c478bd9Sstevel@tonic-gate * Convert a physical or logical device name to a name the prom would 13757c478bd9Sstevel@tonic-gate * understand. Fail if this platform does not support a prom or if 13767c478bd9Sstevel@tonic-gate * the device does not correspond to a valid prom device. 13777c478bd9Sstevel@tonic-gate * dev_path should be the name of a device in the logical or 13787c478bd9Sstevel@tonic-gate * physical device namespace. 13797c478bd9Sstevel@tonic-gate * prom_path is the prom version of the device name 13807c478bd9Sstevel@tonic-gate * prom_path must be large enough to contain the result and is 13817c478bd9Sstevel@tonic-gate * supplied by the user. 13827c478bd9Sstevel@tonic-gate * 13837c478bd9Sstevel@tonic-gate * This routine only supports converting leaf device paths 13847c478bd9Sstevel@tonic-gate */ 13857c478bd9Sstevel@tonic-gate int 13867c478bd9Sstevel@tonic-gate devfs_dev_to_prom_name(char *dev_path, char *prom_path) 13877c478bd9Sstevel@tonic-gate { 13887c478bd9Sstevel@tonic-gate int rval; 13897c478bd9Sstevel@tonic-gate 13907c478bd9Sstevel@tonic-gate rval = devfs_dev_to_prom_names(dev_path, prom_path, MAXPATHLEN); 13917c478bd9Sstevel@tonic-gate 13927c478bd9Sstevel@tonic-gate if (rval < 0) 13937c478bd9Sstevel@tonic-gate return (rval); 13947c478bd9Sstevel@tonic-gate else 13957c478bd9Sstevel@tonic-gate return (0); 13967c478bd9Sstevel@tonic-gate } 13977c478bd9Sstevel@tonic-gate 13987c478bd9Sstevel@tonic-gate /* 13997c478bd9Sstevel@tonic-gate * Use the openprom driver's OPROMPATH2DRV ioctl to convert a devfs 14007c478bd9Sstevel@tonic-gate * path to a driver name. 14017c478bd9Sstevel@tonic-gate * devfs_path - the pathname of interest. This must be the physcical device 14027c478bd9Sstevel@tonic-gate * path with the mount point prefix (ie. /devices) stripped off. 14037c478bd9Sstevel@tonic-gate * drv_buf - user supplied buffer - the driver name will be stored here. 14047c478bd9Sstevel@tonic-gate * 14057c478bd9Sstevel@tonic-gate * If the prom lookup fails, we return the name of the last component in 14067c478bd9Sstevel@tonic-gate * the pathname. This routine is useful for looking up driver names 14077c478bd9Sstevel@tonic-gate * associated with generically named devices. 14087c478bd9Sstevel@tonic-gate * 14097c478bd9Sstevel@tonic-gate * This routine returns driver names that have aliases resolved. 14107c478bd9Sstevel@tonic-gate */ 14117c478bd9Sstevel@tonic-gate int 14127c478bd9Sstevel@tonic-gate devfs_path_to_drv(char *devfs_path, char *drv_buf) 14137c478bd9Sstevel@tonic-gate { 14147c478bd9Sstevel@tonic-gate Oppbuf oppbuf; 14157c478bd9Sstevel@tonic-gate struct openpromio *opp = &(oppbuf.opp); 14167c478bd9Sstevel@tonic-gate char *slash, *colon, *dev_addr; 14177c478bd9Sstevel@tonic-gate char driver_path[MAXPATHLEN]; 14187c478bd9Sstevel@tonic-gate int prom_fd; 14197c478bd9Sstevel@tonic-gate 14207c478bd9Sstevel@tonic-gate if (drv_buf == NULL) { 14217c478bd9Sstevel@tonic-gate return (-1); 14227c478bd9Sstevel@tonic-gate } 14237c478bd9Sstevel@tonic-gate if (devfs_path == NULL) { 14247c478bd9Sstevel@tonic-gate return (-1); 14257c478bd9Sstevel@tonic-gate } 14267c478bd9Sstevel@tonic-gate 14277c478bd9Sstevel@tonic-gate if (strlen(devfs_path) >= MAXPATHLEN) 14287c478bd9Sstevel@tonic-gate return (-1); 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate if (*devfs_path != '/') 14317c478bd9Sstevel@tonic-gate return (-1); 14327c478bd9Sstevel@tonic-gate 14337c478bd9Sstevel@tonic-gate 14347c478bd9Sstevel@tonic-gate /* strip off any minor node info at the end of the path */ 14357c478bd9Sstevel@tonic-gate (void) strcpy(driver_path, devfs_path); 14367c478bd9Sstevel@tonic-gate slash = strrchr(driver_path, '/'); 14377c478bd9Sstevel@tonic-gate if (slash == NULL) 14387c478bd9Sstevel@tonic-gate return (-1); 14397c478bd9Sstevel@tonic-gate colon = strrchr(slash, ':'); 14407c478bd9Sstevel@tonic-gate if (colon != NULL) 14417c478bd9Sstevel@tonic-gate *colon = '\0'; 14427c478bd9Sstevel@tonic-gate 14437c478bd9Sstevel@tonic-gate /* query the prom */ 14447c478bd9Sstevel@tonic-gate if ((prom_fd = prom_open(O_RDONLY)) >= 0) { 14457c478bd9Sstevel@tonic-gate (void) strcpy(opp->oprom_array, driver_path); 14467c478bd9Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE; 14477c478bd9Sstevel@tonic-gate 14487c478bd9Sstevel@tonic-gate if (ioctl(prom_fd, OPROMPATH2DRV, opp) == 0) { 14497c478bd9Sstevel@tonic-gate prom_close(prom_fd); 14507c478bd9Sstevel@tonic-gate /* return the driver name in drv_buf */ 14517c478bd9Sstevel@tonic-gate (void) strcpy(drv_buf, opp->oprom_array); 14527c478bd9Sstevel@tonic-gate return (0); 14537c478bd9Sstevel@tonic-gate } 14547c478bd9Sstevel@tonic-gate prom_close(prom_fd); 14557c478bd9Sstevel@tonic-gate } else if (prom_fd != DEVFS_NOTSUP) 14567c478bd9Sstevel@tonic-gate return (-1); 14577c478bd9Sstevel@tonic-gate /* 14587c478bd9Sstevel@tonic-gate * If we get here, then either: 14597c478bd9Sstevel@tonic-gate * 1. this platform does not support an openprom driver 14607c478bd9Sstevel@tonic-gate * 2. we were asked to look up a device the prom does 14617c478bd9Sstevel@tonic-gate * not know about (e.g. a pseudo device) 14627c478bd9Sstevel@tonic-gate * In this case, we use the last component of the devfs path 14637c478bd9Sstevel@tonic-gate * name and try to derive the driver name 14647c478bd9Sstevel@tonic-gate */ 14657c478bd9Sstevel@tonic-gate 14667c478bd9Sstevel@tonic-gate /* use the last component of devfs_path as the driver name */ 14677c478bd9Sstevel@tonic-gate if ((dev_addr = strrchr(slash, '@')) != NULL) 14687c478bd9Sstevel@tonic-gate *dev_addr = '\0'; 14697c478bd9Sstevel@tonic-gate slash++; 14707c478bd9Sstevel@tonic-gate 14717c478bd9Sstevel@tonic-gate /* use opp->oprom_array as a buffer */ 14727c478bd9Sstevel@tonic-gate (void) strcpy(opp->oprom_array, slash); 14737c478bd9Sstevel@tonic-gate if (devfs_resolve_aliases(opp->oprom_array) == NULL) 14747c478bd9Sstevel@tonic-gate return (-1); 14757c478bd9Sstevel@tonic-gate (void) strcpy(drv_buf, opp->oprom_array); 14767c478bd9Sstevel@tonic-gate return (0); 14777c478bd9Sstevel@tonic-gate } 14787c478bd9Sstevel@tonic-gate 14797c478bd9Sstevel@tonic-gate /* 14807c478bd9Sstevel@tonic-gate * These modctl calls do the equivalent of: 14817c478bd9Sstevel@tonic-gate * ddi_name_to_major() 14827c478bd9Sstevel@tonic-gate * ddi_major_to_name() 14837c478bd9Sstevel@tonic-gate * This results in two things: 14847c478bd9Sstevel@tonic-gate * - the driver name must be a valid one 14857c478bd9Sstevel@tonic-gate * - any driver aliases are resolved. 14867c478bd9Sstevel@tonic-gate * drv is overwritten with the resulting name. 14877c478bd9Sstevel@tonic-gate */ 14887c478bd9Sstevel@tonic-gate char * 14897c478bd9Sstevel@tonic-gate devfs_resolve_aliases(char *drv) 14907c478bd9Sstevel@tonic-gate { 14917c478bd9Sstevel@tonic-gate major_t maj; 14927c478bd9Sstevel@tonic-gate char driver_name[MAXNAMELEN + 1]; 14937c478bd9Sstevel@tonic-gate 14947c478bd9Sstevel@tonic-gate if (drv == NULL) { 14957c478bd9Sstevel@tonic-gate return (NULL); 14967c478bd9Sstevel@tonic-gate } 14977c478bd9Sstevel@tonic-gate 14987c478bd9Sstevel@tonic-gate if (modctl(MODGETMAJBIND, drv, strlen(drv) + 1, &maj) < 0) 14997c478bd9Sstevel@tonic-gate return (NULL); 15007c478bd9Sstevel@tonic-gate else if (modctl(MODGETNAME, driver_name, sizeof (driver_name), &maj) 15017c478bd9Sstevel@tonic-gate < 0) { 15027c478bd9Sstevel@tonic-gate return (NULL); 15037c478bd9Sstevel@tonic-gate } else { 15047c478bd9Sstevel@tonic-gate (void) strcpy(drv, driver_name); 15057c478bd9Sstevel@tonic-gate return (drv); 15067c478bd9Sstevel@tonic-gate } 15077c478bd9Sstevel@tonic-gate } 15087c478bd9Sstevel@tonic-gate 15097c478bd9Sstevel@tonic-gate /* 15107c478bd9Sstevel@tonic-gate * open the openprom device. and verify that we are on an 15117c478bd9Sstevel@tonic-gate * OBP/1275 OF machine. If the prom does not exist, then we 15127c478bd9Sstevel@tonic-gate * return an error 15137c478bd9Sstevel@tonic-gate */ 15147c478bd9Sstevel@tonic-gate static int 15157c478bd9Sstevel@tonic-gate prom_open(int oflag) 15167c478bd9Sstevel@tonic-gate { 15177c478bd9Sstevel@tonic-gate int prom_fd = -1; 15187c478bd9Sstevel@tonic-gate char *promdev = "/dev/openprom"; 15197c478bd9Sstevel@tonic-gate 15207c478bd9Sstevel@tonic-gate while (prom_fd < 0) { 15217c478bd9Sstevel@tonic-gate if ((prom_fd = open(promdev, oflag)) < 0) { 15227c478bd9Sstevel@tonic-gate if (errno == EAGAIN) { 15237c478bd9Sstevel@tonic-gate (void) sleep(5); 15247c478bd9Sstevel@tonic-gate continue; 15257c478bd9Sstevel@tonic-gate } 15267c478bd9Sstevel@tonic-gate if ((errno == ENXIO) || (errno == ENOENT)) { 15277c478bd9Sstevel@tonic-gate return (DEVFS_NOTSUP); 15287c478bd9Sstevel@tonic-gate } 15297c478bd9Sstevel@tonic-gate if ((errno == EPERM) || (errno == EACCES)) { 15307c478bd9Sstevel@tonic-gate return (DEVFS_PERM); 15317c478bd9Sstevel@tonic-gate } 15327c478bd9Sstevel@tonic-gate return (DEVFS_ERR); 15337c478bd9Sstevel@tonic-gate } else 15347c478bd9Sstevel@tonic-gate break; 15357c478bd9Sstevel@tonic-gate } 15367c478bd9Sstevel@tonic-gate if (is_openprom(prom_fd)) 15377c478bd9Sstevel@tonic-gate return (prom_fd); 15387c478bd9Sstevel@tonic-gate else { 15397c478bd9Sstevel@tonic-gate prom_close(prom_fd); 15407c478bd9Sstevel@tonic-gate return (DEVFS_ERR); 15417c478bd9Sstevel@tonic-gate } 15427c478bd9Sstevel@tonic-gate } 15437c478bd9Sstevel@tonic-gate 15447c478bd9Sstevel@tonic-gate static void 15457c478bd9Sstevel@tonic-gate prom_close(int prom_fd) 15467c478bd9Sstevel@tonic-gate { 15477c478bd9Sstevel@tonic-gate (void) close(prom_fd); 15487c478bd9Sstevel@tonic-gate } 15497c478bd9Sstevel@tonic-gate 15507c478bd9Sstevel@tonic-gate /* 15517c478bd9Sstevel@tonic-gate * is this an OBP/1275 OF machine? 15527c478bd9Sstevel@tonic-gate */ 15537c478bd9Sstevel@tonic-gate static int 15547c478bd9Sstevel@tonic-gate is_openprom(int prom_fd) 15557c478bd9Sstevel@tonic-gate { 15567c478bd9Sstevel@tonic-gate Oppbuf oppbuf; 15577c478bd9Sstevel@tonic-gate struct openpromio *opp = &(oppbuf.opp); 15587c478bd9Sstevel@tonic-gate unsigned int i; 15597c478bd9Sstevel@tonic-gate 15607c478bd9Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE; 15617c478bd9Sstevel@tonic-gate if (ioctl(prom_fd, OPROMGETCONS, opp) < 0) 15627c478bd9Sstevel@tonic-gate return (0); 15637c478bd9Sstevel@tonic-gate 15647c478bd9Sstevel@tonic-gate i = (unsigned int)((unsigned char)opp->oprom_array[0]); 15657c478bd9Sstevel@tonic-gate return ((i & OPROMCONS_OPENPROM) == OPROMCONS_OPENPROM); 15667c478bd9Sstevel@tonic-gate } 15677c478bd9Sstevel@tonic-gate 15687c478bd9Sstevel@tonic-gate /* 15697c478bd9Sstevel@tonic-gate * convert a prom device path name to an equivalent physical device 15707c478bd9Sstevel@tonic-gate * path in the kernel. 15717c478bd9Sstevel@tonic-gate */ 15727c478bd9Sstevel@tonic-gate static int 15737c478bd9Sstevel@tonic-gate devfs_prom_to_dev_name(char *prom_path, char *dev_path) 15747c478bd9Sstevel@tonic-gate { 15757c478bd9Sstevel@tonic-gate Oppbuf oppbuf; 15767c478bd9Sstevel@tonic-gate struct openpromio *opp = &(oppbuf.opp); 15777c478bd9Sstevel@tonic-gate int prom_fd; 15787c478bd9Sstevel@tonic-gate int ret = DEVFS_INVAL; 15797c478bd9Sstevel@tonic-gate 15807c478bd9Sstevel@tonic-gate if (dev_path == NULL) { 15817c478bd9Sstevel@tonic-gate return (DEVFS_INVAL); 15827c478bd9Sstevel@tonic-gate } 15837c478bd9Sstevel@tonic-gate if (prom_path == NULL) { 15847c478bd9Sstevel@tonic-gate return (DEVFS_INVAL); 15857c478bd9Sstevel@tonic-gate } 15867c478bd9Sstevel@tonic-gate if (strlen(prom_path) >= MAXPATHLEN) 15877c478bd9Sstevel@tonic-gate return (DEVFS_INVAL); 15887c478bd9Sstevel@tonic-gate 15897c478bd9Sstevel@tonic-gate if (*prom_path != '/') { 15907c478bd9Sstevel@tonic-gate return (DEVFS_INVAL); 15917c478bd9Sstevel@tonic-gate } 15927c478bd9Sstevel@tonic-gate 15937c478bd9Sstevel@tonic-gate /* query the prom */ 15947c478bd9Sstevel@tonic-gate prom_fd = prom_open(O_RDONLY); 15957c478bd9Sstevel@tonic-gate if (prom_fd < 0) { 15967c478bd9Sstevel@tonic-gate return (prom_fd); 15977c478bd9Sstevel@tonic-gate } 15987c478bd9Sstevel@tonic-gate (void) strcpy(opp->oprom_array, prom_path); 15997c478bd9Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE; 16007c478bd9Sstevel@tonic-gate 16017c478bd9Sstevel@tonic-gate if (ioctl(prom_fd, OPROMPROM2DEVNAME, opp) == 0) { 16027c478bd9Sstevel@tonic-gate prom_close(prom_fd); 16037c478bd9Sstevel@tonic-gate /* 16047c478bd9Sstevel@tonic-gate * success 16057c478bd9Sstevel@tonic-gate * return the prom path in prom_path 16067c478bd9Sstevel@tonic-gate */ 16077c478bd9Sstevel@tonic-gate (void) strcpy(dev_path, opp->oprom_array); 16087c478bd9Sstevel@tonic-gate return (0); 16097c478bd9Sstevel@tonic-gate } 16107c478bd9Sstevel@tonic-gate /* 16117c478bd9Sstevel@tonic-gate * either the argument was not a valid name or the openprom 16127c478bd9Sstevel@tonic-gate * driver does not support this ioctl. 16137c478bd9Sstevel@tonic-gate */ 16147c478bd9Sstevel@tonic-gate if (errno == ENXIO) { 16157c478bd9Sstevel@tonic-gate ret = DEVFS_NOTSUP; 16167c478bd9Sstevel@tonic-gate } 16177c478bd9Sstevel@tonic-gate prom_close(prom_fd); 16187c478bd9Sstevel@tonic-gate return (ret); 16197c478bd9Sstevel@tonic-gate } 16207c478bd9Sstevel@tonic-gate /* 16217c478bd9Sstevel@tonic-gate * convert a prom device path to a list of equivalent alias names 16227c478bd9Sstevel@tonic-gate * If there is no alias node, or there are no aliases that correspond 16237c478bd9Sstevel@tonic-gate * to dev, we return empty lists. 16247c478bd9Sstevel@tonic-gate */ 16257c478bd9Sstevel@tonic-gate static int 16267c478bd9Sstevel@tonic-gate prom_dev_to_alias(char *dev, uint_t options, char ***ret_buf) 16277c478bd9Sstevel@tonic-gate { 16287c478bd9Sstevel@tonic-gate struct name_list *exact_list; 16297c478bd9Sstevel@tonic-gate struct name_list *inexact_list; 16307c478bd9Sstevel@tonic-gate struct name_list *list; 16317c478bd9Sstevel@tonic-gate char *ptr; 16327c478bd9Sstevel@tonic-gate char **array; 16337c478bd9Sstevel@tonic-gate int prom_fd; 16347c478bd9Sstevel@tonic-gate int count; 16357c478bd9Sstevel@tonic-gate int vers; 16367c478bd9Sstevel@tonic-gate 16377c478bd9Sstevel@tonic-gate vers = prom_obp_vers(); 16387c478bd9Sstevel@tonic-gate if (vers < 0) { 16397c478bd9Sstevel@tonic-gate return (vers); 16407c478bd9Sstevel@tonic-gate } 16417c478bd9Sstevel@tonic-gate 16427c478bd9Sstevel@tonic-gate if (dev == NULL) { 16437c478bd9Sstevel@tonic-gate return (DEVFS_INVAL); 16447c478bd9Sstevel@tonic-gate } 16457c478bd9Sstevel@tonic-gate 16467c478bd9Sstevel@tonic-gate if (*dev != '/') 16477c478bd9Sstevel@tonic-gate return (DEVFS_INVAL); 16487c478bd9Sstevel@tonic-gate 16497c478bd9Sstevel@tonic-gate if (strlen(dev) >= MAXPATHLEN) 16507c478bd9Sstevel@tonic-gate return (DEVFS_INVAL); 16517c478bd9Sstevel@tonic-gate 16527c478bd9Sstevel@tonic-gate if ((ptr = strchr(dev, ':')) != NULL) { 16537c478bd9Sstevel@tonic-gate if (strchr(ptr, '/') != NULL) 16547c478bd9Sstevel@tonic-gate return (DEVFS_INVAL); 16557c478bd9Sstevel@tonic-gate } 16567c478bd9Sstevel@tonic-gate if (ret_buf == NULL) { 16577c478bd9Sstevel@tonic-gate return (DEVFS_INVAL); 16587c478bd9Sstevel@tonic-gate } 16597c478bd9Sstevel@tonic-gate 16607c478bd9Sstevel@tonic-gate prom_fd = prom_open(O_RDONLY); 16617c478bd9Sstevel@tonic-gate if (prom_fd < 0) { 16627c478bd9Sstevel@tonic-gate return (prom_fd); 16637c478bd9Sstevel@tonic-gate } 16647c478bd9Sstevel@tonic-gate 16657c478bd9Sstevel@tonic-gate (void) prom_srch_aliases_by_def(dev, &exact_list, 16667c478bd9Sstevel@tonic-gate &inexact_list, prom_fd); 16677c478bd9Sstevel@tonic-gate 16687c478bd9Sstevel@tonic-gate prom_close(prom_fd); 16697c478bd9Sstevel@tonic-gate 16707c478bd9Sstevel@tonic-gate if ((options & BOOTDEV_NO_EXACT_ALIAS) != 0) { 16717c478bd9Sstevel@tonic-gate free_name_list(exact_list, 1); 16727c478bd9Sstevel@tonic-gate exact_list = NULL; 16737c478bd9Sstevel@tonic-gate } 16747c478bd9Sstevel@tonic-gate 16757c478bd9Sstevel@tonic-gate if ((options & BOOTDEV_NO_INEXACT_ALIAS) != 0) { 16767c478bd9Sstevel@tonic-gate free_name_list(inexact_list, 1); 16777c478bd9Sstevel@tonic-gate inexact_list = NULL; 16787c478bd9Sstevel@tonic-gate } 16797c478bd9Sstevel@tonic-gate 16807c478bd9Sstevel@tonic-gate count = 0; 16817c478bd9Sstevel@tonic-gate list = exact_list; 16827c478bd9Sstevel@tonic-gate while (list != NULL) { 16837c478bd9Sstevel@tonic-gate list = list->next; 16847c478bd9Sstevel@tonic-gate count++; 16857c478bd9Sstevel@tonic-gate } 16867c478bd9Sstevel@tonic-gate list = inexact_list; 16877c478bd9Sstevel@tonic-gate while (list != NULL) { 16887c478bd9Sstevel@tonic-gate list = list->next; 16897c478bd9Sstevel@tonic-gate count++; 16907c478bd9Sstevel@tonic-gate } 16917c478bd9Sstevel@tonic-gate 16927c478bd9Sstevel@tonic-gate if ((*ret_buf = (char **)malloc((count + 1) * sizeof (char *))) 16937c478bd9Sstevel@tonic-gate == NULL) { 16947c478bd9Sstevel@tonic-gate free_name_list(inexact_list, 1); 16957c478bd9Sstevel@tonic-gate free_name_list(exact_list, 1); 16967c478bd9Sstevel@tonic-gate return (DEVFS_NOMEM); 16977c478bd9Sstevel@tonic-gate } 16987c478bd9Sstevel@tonic-gate 16997c478bd9Sstevel@tonic-gate array = *ret_buf; 17007c478bd9Sstevel@tonic-gate count = 0; 17017c478bd9Sstevel@tonic-gate list = exact_list; 17027c478bd9Sstevel@tonic-gate while (list != NULL) { 17037c478bd9Sstevel@tonic-gate array[count] = list->name; 17047c478bd9Sstevel@tonic-gate list = list->next; 17057c478bd9Sstevel@tonic-gate count++; 17067c478bd9Sstevel@tonic-gate } 17077c478bd9Sstevel@tonic-gate list = inexact_list; 17087c478bd9Sstevel@tonic-gate while (list != NULL) { 17097c478bd9Sstevel@tonic-gate array[count] = list->name; 17107c478bd9Sstevel@tonic-gate list = list->next; 17117c478bd9Sstevel@tonic-gate count++; 17127c478bd9Sstevel@tonic-gate } 17137c478bd9Sstevel@tonic-gate array[count] = NULL; 17147c478bd9Sstevel@tonic-gate free_name_list(inexact_list, 0); 17157c478bd9Sstevel@tonic-gate free_name_list(exact_list, 0); 17167c478bd9Sstevel@tonic-gate 17177c478bd9Sstevel@tonic-gate return (0); 17187c478bd9Sstevel@tonic-gate } 17197c478bd9Sstevel@tonic-gate 17207c478bd9Sstevel@tonic-gate /* 17217c478bd9Sstevel@tonic-gate * determine the version of prom we are running on. 17227c478bd9Sstevel@tonic-gate * Also include any prom revision specific information. 17237c478bd9Sstevel@tonic-gate */ 17247c478bd9Sstevel@tonic-gate static int 17257c478bd9Sstevel@tonic-gate prom_obp_vers(void) 17267c478bd9Sstevel@tonic-gate { 17277c478bd9Sstevel@tonic-gate Oppbuf oppbuf; 17287c478bd9Sstevel@tonic-gate struct openpromio *opp = &(oppbuf.opp); 17297c478bd9Sstevel@tonic-gate int prom_fd; 17307c478bd9Sstevel@tonic-gate static int version = 0; 17317c478bd9Sstevel@tonic-gate 17327c478bd9Sstevel@tonic-gate /* cache version */ 17337c478bd9Sstevel@tonic-gate if (version > 0) { 17347c478bd9Sstevel@tonic-gate return (version); 17357c478bd9Sstevel@tonic-gate } 17367c478bd9Sstevel@tonic-gate 17377c478bd9Sstevel@tonic-gate prom_fd = prom_open(O_RDONLY); 17387c478bd9Sstevel@tonic-gate if (prom_fd < 0) { 17397c478bd9Sstevel@tonic-gate return (prom_fd); 17407c478bd9Sstevel@tonic-gate } 17417c478bd9Sstevel@tonic-gate 17427c478bd9Sstevel@tonic-gate opp->oprom_size = MAXVALSIZE; 17437c478bd9Sstevel@tonic-gate 17447c478bd9Sstevel@tonic-gate if ((ioctl(prom_fd, OPROMGETVERSION, opp)) < 0) { 17457c478bd9Sstevel@tonic-gate prom_close(prom_fd); 17467c478bd9Sstevel@tonic-gate return (DEVFS_ERR); 17477c478bd9Sstevel@tonic-gate } 17487c478bd9Sstevel@tonic-gate prom_close(prom_fd); 17497c478bd9Sstevel@tonic-gate 17507c478bd9Sstevel@tonic-gate version |= OBP_OF; 17517c478bd9Sstevel@tonic-gate 17527c478bd9Sstevel@tonic-gate return (version); 17537c478bd9Sstevel@tonic-gate } 17547c478bd9Sstevel@tonic-gate /* 17557c478bd9Sstevel@tonic-gate * search the aliases node by definition - compile a list of 17567c478bd9Sstevel@tonic-gate * alias names that are both exact and inexact matches. 17577c478bd9Sstevel@tonic-gate */ 17587c478bd9Sstevel@tonic-gate static int 17597c478bd9Sstevel@tonic-gate prom_srch_aliases_by_def(char *promdev_def, struct name_list **exact_list, 17607c478bd9Sstevel@tonic-gate struct name_list **inexact_list, int prom_fd) 17617c478bd9Sstevel@tonic-gate { 17627c478bd9Sstevel@tonic-gate Oppbuf oppbuf; 17637c478bd9Sstevel@tonic-gate Oppbuf propdef_oppbuf; 17647c478bd9Sstevel@tonic-gate struct openpromio *opp = &(oppbuf.opp); 17657c478bd9Sstevel@tonic-gate struct openpromio *propdef_opp = &(propdef_oppbuf.opp); 17667c478bd9Sstevel@tonic-gate int *ip = (int *)((void *)opp->oprom_array); 17677c478bd9Sstevel@tonic-gate int ret; 17687c478bd9Sstevel@tonic-gate struct name_list *inexact_match = *inexact_list = NULL; 17697c478bd9Sstevel@tonic-gate struct name_list *exact_match = *exact_list = NULL; 17707c478bd9Sstevel@tonic-gate char alias_buf[MAXNAMELEN]; 17717c478bd9Sstevel@tonic-gate int found = 0; 17727c478bd9Sstevel@tonic-gate 1773*c279fc79Ssriman bhavanam - Sun Microsystems - Bangalore India if ((ret = prom_find_aliases_node(prom_fd)) < 0) 1774*c279fc79Ssriman bhavanam - Sun Microsystems - Bangalore India return (0); 1775*c279fc79Ssriman bhavanam - Sun Microsystems - Bangalore India 17767c478bd9Sstevel@tonic-gate (void) memset(oppbuf.buf, 0, BUFSIZE); 17777c478bd9Sstevel@tonic-gate opp->oprom_size = MAXPROPSIZE; 17787c478bd9Sstevel@tonic-gate *ip = 0; 17797c478bd9Sstevel@tonic-gate 17807c478bd9Sstevel@tonic-gate if ((ret = ioctl(prom_fd, OPROMNXTPROP, opp)) < 0) 17817c478bd9Sstevel@tonic-gate return (0); 17827c478bd9Sstevel@tonic-gate if (opp->oprom_size == 0) 17837c478bd9Sstevel@tonic-gate return (0); 17847c478bd9Sstevel@tonic-gate 17857c478bd9Sstevel@tonic-gate while ((ret >= 0) && (opp->oprom_size > 0)) { 17867c478bd9Sstevel@tonic-gate (void) strcpy(propdef_opp->oprom_array, opp->oprom_array); 17877c478bd9Sstevel@tonic-gate opp->oprom_size = MAXPROPSIZE; 17887c478bd9Sstevel@tonic-gate propdef_opp->oprom_size = MAXVALSIZE; 17897c478bd9Sstevel@tonic-gate if ((ioctl(prom_fd, OPROMGETPROP, propdef_opp) < 0) || 17907c478bd9Sstevel@tonic-gate (propdef_opp->oprom_size == 0)) { 17917c478bd9Sstevel@tonic-gate ret = ioctl(prom_fd, OPROMNXTPROP, opp); 17927c478bd9Sstevel@tonic-gate continue; 17937c478bd9Sstevel@tonic-gate } 17947c478bd9Sstevel@tonic-gate ret = prom_compare_devs(promdev_def, propdef_opp->oprom_array); 17957c478bd9Sstevel@tonic-gate if (ret == EXACT_MATCH) { 17967c478bd9Sstevel@tonic-gate found++; 17977c478bd9Sstevel@tonic-gate if (insert_alias_list(exact_list, opp->oprom_array) 17987c478bd9Sstevel@tonic-gate != 0) { 17997c478bd9Sstevel@tonic-gate free_name_list(exact_match, 1); 18007c478bd9Sstevel@tonic-gate free_name_list(inexact_match, 1); 18017c478bd9Sstevel@tonic-gate return (-1); 18027c478bd9Sstevel@tonic-gate } 18037c478bd9Sstevel@tonic-gate } 18047c478bd9Sstevel@tonic-gate if (ret == INEXACT_MATCH) { 18057c478bd9Sstevel@tonic-gate found++; 18067c478bd9Sstevel@tonic-gate (void) strcpy(alias_buf, opp->oprom_array); 18077c478bd9Sstevel@tonic-gate options_override(promdev_def, alias_buf); 18087c478bd9Sstevel@tonic-gate if (insert_alias_list(inexact_list, alias_buf) 18097c478bd9Sstevel@tonic-gate != 0) { 18107c478bd9Sstevel@tonic-gate free_name_list(exact_match, 1); 18117c478bd9Sstevel@tonic-gate free_name_list(inexact_match, 1); 18127c478bd9Sstevel@tonic-gate return (-1); 18137c478bd9Sstevel@tonic-gate } 18147c478bd9Sstevel@tonic-gate } 18157c478bd9Sstevel@tonic-gate ret = ioctl(prom_fd, OPROMNXTPROP, opp); 18167c478bd9Sstevel@tonic-gate } 18177c478bd9Sstevel@tonic-gate if (found) { 18187c478bd9Sstevel@tonic-gate return (0); 18197c478bd9Sstevel@tonic-gate } else { 18207c478bd9Sstevel@tonic-gate return (-1); 18217c478bd9Sstevel@tonic-gate } 18227c478bd9Sstevel@tonic-gate } 18237c478bd9Sstevel@tonic-gate 18247c478bd9Sstevel@tonic-gate /* 18257c478bd9Sstevel@tonic-gate * free a list of name_list structs and optionally 18267c478bd9Sstevel@tonic-gate * free the strings they contain. 18277c478bd9Sstevel@tonic-gate */ 18287c478bd9Sstevel@tonic-gate static void 18297c478bd9Sstevel@tonic-gate free_name_list(struct name_list *list, int free_name) 18307c478bd9Sstevel@tonic-gate { 18317c478bd9Sstevel@tonic-gate struct name_list *next = list; 18327c478bd9Sstevel@tonic-gate 18337c478bd9Sstevel@tonic-gate while (next != NULL) { 18347c478bd9Sstevel@tonic-gate list = list->next; 18357c478bd9Sstevel@tonic-gate if (free_name) 18367c478bd9Sstevel@tonic-gate free(next->name); 18377c478bd9Sstevel@tonic-gate free(next); 18387c478bd9Sstevel@tonic-gate next = list; 18397c478bd9Sstevel@tonic-gate } 18407c478bd9Sstevel@tonic-gate } 18417c478bd9Sstevel@tonic-gate 18427c478bd9Sstevel@tonic-gate /* 18437c478bd9Sstevel@tonic-gate * insert a new alias in a list of aliases - the list is sorted 18447c478bd9Sstevel@tonic-gate * in collating order (ignoring anything that comes after the 18457c478bd9Sstevel@tonic-gate * ':' in the name). 18467c478bd9Sstevel@tonic-gate */ 18477c478bd9Sstevel@tonic-gate static int 18487c478bd9Sstevel@tonic-gate insert_alias_list(struct name_list **list, char *alias_name) 18497c478bd9Sstevel@tonic-gate { 18507c478bd9Sstevel@tonic-gate struct name_list *entry = *list; 18517c478bd9Sstevel@tonic-gate struct name_list *new_entry, *prev_entry; 18527c478bd9Sstevel@tonic-gate int ret; 18537c478bd9Sstevel@tonic-gate char *colon1, *colon2; 18547c478bd9Sstevel@tonic-gate 18557c478bd9Sstevel@tonic-gate if ((new_entry = 18567c478bd9Sstevel@tonic-gate (struct name_list *)malloc(sizeof (struct name_list))) 18577c478bd9Sstevel@tonic-gate == NULL) { 18587c478bd9Sstevel@tonic-gate return (-1); 18597c478bd9Sstevel@tonic-gate } 18607c478bd9Sstevel@tonic-gate if ((new_entry->name = strdup(alias_name)) == NULL) { 18617c478bd9Sstevel@tonic-gate free(new_entry); 18627c478bd9Sstevel@tonic-gate return (-1); 18637c478bd9Sstevel@tonic-gate } 18647c478bd9Sstevel@tonic-gate new_entry->next = NULL; 18657c478bd9Sstevel@tonic-gate 18667c478bd9Sstevel@tonic-gate if (entry == NULL) { 18677c478bd9Sstevel@tonic-gate *list = new_entry; 18687c478bd9Sstevel@tonic-gate return (0); 18697c478bd9Sstevel@tonic-gate } 18707c478bd9Sstevel@tonic-gate 18717c478bd9Sstevel@tonic-gate if ((colon1 = strchr(alias_name, ':')) != NULL) { 18727c478bd9Sstevel@tonic-gate *colon1 = '\0'; 18737c478bd9Sstevel@tonic-gate } 18747c478bd9Sstevel@tonic-gate prev_entry = NULL; 18757c478bd9Sstevel@tonic-gate while (entry != NULL) { 18767c478bd9Sstevel@tonic-gate if ((colon2 = strchr(entry->name, ':')) != NULL) { 18777c478bd9Sstevel@tonic-gate *colon2 = '\0'; 18787c478bd9Sstevel@tonic-gate } 18797c478bd9Sstevel@tonic-gate ret = strcmp(alias_name, entry->name); 18807c478bd9Sstevel@tonic-gate if (colon2 != NULL) { 18817c478bd9Sstevel@tonic-gate *colon2 = ':'; 18827c478bd9Sstevel@tonic-gate } 18837c478bd9Sstevel@tonic-gate /* duplicate */ 18847c478bd9Sstevel@tonic-gate if (ret == 0) { 18857c478bd9Sstevel@tonic-gate free(new_entry->name); 18867c478bd9Sstevel@tonic-gate free(new_entry); 18877c478bd9Sstevel@tonic-gate if (colon1 != NULL) { 18887c478bd9Sstevel@tonic-gate *colon1 = ':'; 18897c478bd9Sstevel@tonic-gate } 18907c478bd9Sstevel@tonic-gate return (0); 18917c478bd9Sstevel@tonic-gate } 18927c478bd9Sstevel@tonic-gate if (ret < 0) { 18937c478bd9Sstevel@tonic-gate new_entry->next = entry; 18947c478bd9Sstevel@tonic-gate if (prev_entry == NULL) { 18957c478bd9Sstevel@tonic-gate /* in beginning of list */ 18967c478bd9Sstevel@tonic-gate *list = new_entry; 18977c478bd9Sstevel@tonic-gate } else { 18987c478bd9Sstevel@tonic-gate /* in middle of list */ 18997c478bd9Sstevel@tonic-gate prev_entry->next = new_entry; 19007c478bd9Sstevel@tonic-gate } 19017c478bd9Sstevel@tonic-gate if (colon1 != NULL) { 19027c478bd9Sstevel@tonic-gate *colon1 = ':'; 19037c478bd9Sstevel@tonic-gate } 19047c478bd9Sstevel@tonic-gate return (0); 19057c478bd9Sstevel@tonic-gate } 19067c478bd9Sstevel@tonic-gate prev_entry = entry; 19077c478bd9Sstevel@tonic-gate entry = entry->next; 19087c478bd9Sstevel@tonic-gate } 19097c478bd9Sstevel@tonic-gate /* at end of list */ 19107c478bd9Sstevel@tonic-gate prev_entry->next = new_entry; 19117c478bd9Sstevel@tonic-gate new_entry->next = NULL; 19127c478bd9Sstevel@tonic-gate if (colon1 != NULL) { 19137c478bd9Sstevel@tonic-gate *colon1 = ':'; 19147c478bd9Sstevel@tonic-gate } 19157c478bd9Sstevel@tonic-gate return (0); 19167c478bd9Sstevel@tonic-gate } 19177c478bd9Sstevel@tonic-gate /* 19187c478bd9Sstevel@tonic-gate * append :x to alias_name to override any default minor name options 19197c478bd9Sstevel@tonic-gate */ 19207c478bd9Sstevel@tonic-gate static void 19217c478bd9Sstevel@tonic-gate options_override(char *prom_path, char *alias_name) 19227c478bd9Sstevel@tonic-gate { 19237c478bd9Sstevel@tonic-gate char *colon; 19247c478bd9Sstevel@tonic-gate 19257c478bd9Sstevel@tonic-gate if ((colon = strrchr(alias_name, ':')) != NULL) { 19267c478bd9Sstevel@tonic-gate /* 19277c478bd9Sstevel@tonic-gate * XXX - should alias names in /aliases ever have a 19287c478bd9Sstevel@tonic-gate * : embedded in them? 19297c478bd9Sstevel@tonic-gate * If so we ignore it. 19307c478bd9Sstevel@tonic-gate */ 19317c478bd9Sstevel@tonic-gate *colon = '\0'; 19327c478bd9Sstevel@tonic-gate } 19337c478bd9Sstevel@tonic-gate 19347c478bd9Sstevel@tonic-gate if ((colon = strrchr(prom_path, ':')) != NULL) { 19357c478bd9Sstevel@tonic-gate (void) strcat(alias_name, colon); 19367c478bd9Sstevel@tonic-gate } 19377c478bd9Sstevel@tonic-gate } 19387c478bd9Sstevel@tonic-gate 19397c478bd9Sstevel@tonic-gate /* 19407c478bd9Sstevel@tonic-gate * compare to prom device names. 19417c478bd9Sstevel@tonic-gate * if the device names are not fully qualified. we convert them - 19427c478bd9Sstevel@tonic-gate * we only do this as a last resort though since it requires 19437c478bd9Sstevel@tonic-gate * jumping into the kernel. 19447c478bd9Sstevel@tonic-gate */ 19457c478bd9Sstevel@tonic-gate static int 19467c478bd9Sstevel@tonic-gate prom_compare_devs(char *prom_dev1, char *prom_dev2) 19477c478bd9Sstevel@tonic-gate { 19487c478bd9Sstevel@tonic-gate char *dev1, *dev2; 19497c478bd9Sstevel@tonic-gate char *ptr1, *ptr2; 19507c478bd9Sstevel@tonic-gate char *drvname1, *addrname1, *minorname1; 19517c478bd9Sstevel@tonic-gate char *drvname2, *addrname2, *minorname2; 19527c478bd9Sstevel@tonic-gate char component1[MAXNAMELEN], component2[MAXNAMELEN]; 19537c478bd9Sstevel@tonic-gate char devname1[MAXPATHLEN], devname2[MAXPATHLEN]; 19547c478bd9Sstevel@tonic-gate int unqualified_name = 0; 19557c478bd9Sstevel@tonic-gate int error = EXACT_MATCH; 19567c478bd9Sstevel@tonic-gate int len1, len2; 19577c478bd9Sstevel@tonic-gate char *wildcard = ",0"; 19587c478bd9Sstevel@tonic-gate 19597c478bd9Sstevel@tonic-gate ptr1 = prom_dev1; 19607c478bd9Sstevel@tonic-gate ptr2 = prom_dev2; 19617c478bd9Sstevel@tonic-gate 19627c478bd9Sstevel@tonic-gate if ((ptr1 == NULL) || (*ptr1 != '/')) { 19637c478bd9Sstevel@tonic-gate return (NO_MATCH); 19647c478bd9Sstevel@tonic-gate } 19657c478bd9Sstevel@tonic-gate if ((ptr2 == NULL) || (*ptr2 != '/')) { 19667c478bd9Sstevel@tonic-gate return (NO_MATCH); 19677c478bd9Sstevel@tonic-gate } 19687c478bd9Sstevel@tonic-gate 19697c478bd9Sstevel@tonic-gate /* 19707c478bd9Sstevel@tonic-gate * compare device names one component at a time. 19717c478bd9Sstevel@tonic-gate */ 19727c478bd9Sstevel@tonic-gate while ((ptr1 != NULL) && (ptr2 != NULL)) { 19737c478bd9Sstevel@tonic-gate *ptr1 = *ptr2 = '/'; 19747c478bd9Sstevel@tonic-gate dev1 = ptr1 + 1; 19757c478bd9Sstevel@tonic-gate dev2 = ptr2 + 1; 19767c478bd9Sstevel@tonic-gate if ((ptr1 = strchr(dev1, '/')) != NULL) 19777c478bd9Sstevel@tonic-gate *ptr1 = '\0'; 19787c478bd9Sstevel@tonic-gate if ((ptr2 = strchr(dev2, '/')) != NULL) 19797c478bd9Sstevel@tonic-gate *ptr2 = '\0'; 19807c478bd9Sstevel@tonic-gate 19817c478bd9Sstevel@tonic-gate (void) strcpy(component1, dev1); 19827c478bd9Sstevel@tonic-gate (void) strcpy(component2, dev2); 19837c478bd9Sstevel@tonic-gate 19847c478bd9Sstevel@tonic-gate parse_name(component1, &drvname1, &addrname1, &minorname1); 19857c478bd9Sstevel@tonic-gate parse_name(component2, &drvname2, &addrname2, &minorname2); 19867c478bd9Sstevel@tonic-gate 19877c478bd9Sstevel@tonic-gate if ((drvname1 == NULL) && (addrname1 == NULL)) { 19887c478bd9Sstevel@tonic-gate error = NO_MATCH; 19897c478bd9Sstevel@tonic-gate break; 19907c478bd9Sstevel@tonic-gate } 19917c478bd9Sstevel@tonic-gate 19927c478bd9Sstevel@tonic-gate if ((drvname2 == NULL) && (addrname2 == NULL)) { 19937c478bd9Sstevel@tonic-gate error = NO_MATCH; 19947c478bd9Sstevel@tonic-gate break; 19957c478bd9Sstevel@tonic-gate } 19967c478bd9Sstevel@tonic-gate 19977c478bd9Sstevel@tonic-gate if (_prom_strcmp(drvname1, drvname2) != 0) { 19987c478bd9Sstevel@tonic-gate error = NO_MATCH; 19997c478bd9Sstevel@tonic-gate break; 20007c478bd9Sstevel@tonic-gate } 20017c478bd9Sstevel@tonic-gate 20027c478bd9Sstevel@tonic-gate /* 20037c478bd9Sstevel@tonic-gate * a possible name is driver_name@address. The address 20047c478bd9Sstevel@tonic-gate * portion is optional (i.e. the name is not fully 20057c478bd9Sstevel@tonic-gate * qualified.). We have to deal with the case where 20067c478bd9Sstevel@tonic-gate * the component name is either driver_name or 20077c478bd9Sstevel@tonic-gate * driver_name@address 20087c478bd9Sstevel@tonic-gate */ 20097c478bd9Sstevel@tonic-gate if ((addrname1 == NULL) ^ (addrname2 == NULL)) { 20107c478bd9Sstevel@tonic-gate unqualified_name = 1; 20117c478bd9Sstevel@tonic-gate } else if (addrname1 && 20127c478bd9Sstevel@tonic-gate (_prom_strcmp(addrname1, addrname2) != 0)) { 20137c478bd9Sstevel@tonic-gate /* 20147c478bd9Sstevel@tonic-gate * check to see if appending a ",0" to the 20157c478bd9Sstevel@tonic-gate * shorter address causes a match to occur. 20167c478bd9Sstevel@tonic-gate * If so succeed. 20177c478bd9Sstevel@tonic-gate */ 20187c478bd9Sstevel@tonic-gate len1 = strlen(addrname1); 20197c478bd9Sstevel@tonic-gate len2 = strlen(addrname2); 20207c478bd9Sstevel@tonic-gate if ((len1 < len2) && 20217c478bd9Sstevel@tonic-gate (strncmp(addrname1, addrname2, len1) == 0) && 20227c478bd9Sstevel@tonic-gate (strcmp(wildcard, &addrname2[len1]) == 0)) { 20237c478bd9Sstevel@tonic-gate continue; 20247c478bd9Sstevel@tonic-gate } else if ((len2 < len1) && 20257c478bd9Sstevel@tonic-gate (strncmp(addrname1, addrname2, len2) == 0) && 20267c478bd9Sstevel@tonic-gate (strcmp(wildcard, &addrname1[len2]) == 0)) { 20277c478bd9Sstevel@tonic-gate continue; 20287c478bd9Sstevel@tonic-gate } 20297c478bd9Sstevel@tonic-gate error = NO_MATCH; 20307c478bd9Sstevel@tonic-gate break; 20317c478bd9Sstevel@tonic-gate } 20327c478bd9Sstevel@tonic-gate } 20337c478bd9Sstevel@tonic-gate 20347c478bd9Sstevel@tonic-gate /* 20357c478bd9Sstevel@tonic-gate * if either of the two device paths still has more components, 20367c478bd9Sstevel@tonic-gate * then we do not have a match. 20377c478bd9Sstevel@tonic-gate */ 20387c478bd9Sstevel@tonic-gate if (ptr1 != NULL) { 20397c478bd9Sstevel@tonic-gate *ptr1 = '/'; 20407c478bd9Sstevel@tonic-gate error = NO_MATCH; 20417c478bd9Sstevel@tonic-gate } 20427c478bd9Sstevel@tonic-gate if (ptr2 != NULL) { 20437c478bd9Sstevel@tonic-gate *ptr2 = '/'; 20447c478bd9Sstevel@tonic-gate error = NO_MATCH; 20457c478bd9Sstevel@tonic-gate } 20467c478bd9Sstevel@tonic-gate if (error == NO_MATCH) { 20477c478bd9Sstevel@tonic-gate return (error); 20487c478bd9Sstevel@tonic-gate } 20497c478bd9Sstevel@tonic-gate 20507c478bd9Sstevel@tonic-gate /* 20517c478bd9Sstevel@tonic-gate * OK - we found a possible match but one or more of the 20527c478bd9Sstevel@tonic-gate * path components was not fully qualified (did not have any 20537c478bd9Sstevel@tonic-gate * address information. So we need to convert it to a form 20547c478bd9Sstevel@tonic-gate * that is fully qualified and then compare the resulting 20557c478bd9Sstevel@tonic-gate * strings. 20567c478bd9Sstevel@tonic-gate */ 20577c478bd9Sstevel@tonic-gate if (unqualified_name != 0) { 20587c478bd9Sstevel@tonic-gate if ((devfs_prom_to_dev_name(prom_dev1, devname1) < 0) || 20597c478bd9Sstevel@tonic-gate (devfs_prom_to_dev_name(prom_dev2, devname2) < 0)) { 20607c478bd9Sstevel@tonic-gate return (NO_MATCH); 20617c478bd9Sstevel@tonic-gate } 20627c478bd9Sstevel@tonic-gate if ((dev1 = strrchr(devname1, ':')) != NULL) { 20637c478bd9Sstevel@tonic-gate *dev1 = '\0'; 20647c478bd9Sstevel@tonic-gate } 20657c478bd9Sstevel@tonic-gate if ((dev2 = strrchr(devname2, ':')) != NULL) { 20667c478bd9Sstevel@tonic-gate *dev2 = '\0'; 20677c478bd9Sstevel@tonic-gate } 20687c478bd9Sstevel@tonic-gate if (strcmp(devname1, devname2) != 0) { 20697c478bd9Sstevel@tonic-gate return (NO_MATCH); 20707c478bd9Sstevel@tonic-gate } 20717c478bd9Sstevel@tonic-gate } 20727c478bd9Sstevel@tonic-gate /* 20737c478bd9Sstevel@tonic-gate * the resulting strings matched. If the minorname information 20747c478bd9Sstevel@tonic-gate * matches, then we have an exact match, otherwise an inexact match 20757c478bd9Sstevel@tonic-gate */ 20767c478bd9Sstevel@tonic-gate if (_prom_strcmp(minorname1, minorname2) == 0) { 20777c478bd9Sstevel@tonic-gate return (EXACT_MATCH); 20787c478bd9Sstevel@tonic-gate } else { 20797c478bd9Sstevel@tonic-gate return (INEXACT_MATCH); 20807c478bd9Sstevel@tonic-gate } 20817c478bd9Sstevel@tonic-gate } 20827c478bd9Sstevel@tonic-gate 20837c478bd9Sstevel@tonic-gate /* 20847c478bd9Sstevel@tonic-gate * wrapper or strcmp - deals with null strings. 20857c478bd9Sstevel@tonic-gate */ 20867c478bd9Sstevel@tonic-gate static int 20877c478bd9Sstevel@tonic-gate _prom_strcmp(char *s1, char *s2) 20887c478bd9Sstevel@tonic-gate { 20897c478bd9Sstevel@tonic-gate if ((s1 == NULL) && (s2 == NULL)) 20907c478bd9Sstevel@tonic-gate return (0); 20917c478bd9Sstevel@tonic-gate if ((s1 == NULL) && (s2 != NULL)) { 20927c478bd9Sstevel@tonic-gate return (-1); 20937c478bd9Sstevel@tonic-gate } 20947c478bd9Sstevel@tonic-gate if ((s1 != NULL) && (s2 == NULL)) { 20957c478bd9Sstevel@tonic-gate return (1); 20967c478bd9Sstevel@tonic-gate } 20977c478bd9Sstevel@tonic-gate return (strcmp(s1, s2)); 20987c478bd9Sstevel@tonic-gate } 20997c478bd9Sstevel@tonic-gate /* 21007c478bd9Sstevel@tonic-gate * break device@a,b:minor into components 21017c478bd9Sstevel@tonic-gate */ 21027c478bd9Sstevel@tonic-gate static void 21037c478bd9Sstevel@tonic-gate parse_name(char *name, char **drvname, char **addrname, char **minorname) 21047c478bd9Sstevel@tonic-gate { 21057c478bd9Sstevel@tonic-gate char *cp, ch; 21067c478bd9Sstevel@tonic-gate 21077c478bd9Sstevel@tonic-gate cp = *drvname = name; 21087c478bd9Sstevel@tonic-gate *addrname = *minorname = NULL; 21097c478bd9Sstevel@tonic-gate if (*name == '@') 21107c478bd9Sstevel@tonic-gate *drvname = NULL; 21117c478bd9Sstevel@tonic-gate 21127c478bd9Sstevel@tonic-gate while ((ch = *cp) != '\0') { 21137c478bd9Sstevel@tonic-gate if (ch == '@') 21147c478bd9Sstevel@tonic-gate *addrname = ++cp; 21157c478bd9Sstevel@tonic-gate else if (ch == ':') 21167c478bd9Sstevel@tonic-gate *minorname = ++cp; 21177c478bd9Sstevel@tonic-gate ++cp; 21187c478bd9Sstevel@tonic-gate } 21197c478bd9Sstevel@tonic-gate if (*addrname) { 21207c478bd9Sstevel@tonic-gate *((*addrname)-1) = '\0'; 21217c478bd9Sstevel@tonic-gate } 21227c478bd9Sstevel@tonic-gate if (*minorname) { 21237c478bd9Sstevel@tonic-gate *((*minorname)-1) = '\0'; 21247c478bd9Sstevel@tonic-gate } 21257c478bd9Sstevel@tonic-gate } 21267c478bd9Sstevel@tonic-gate 21277c478bd9Sstevel@tonic-gate /* 2128b6f77fefSas158974 * converts a prom alias to a prom device name. 2129b6f77fefSas158974 * if we find no matching device, then we fail since if were 2130b6f77fefSas158974 * given a valid alias, then by definition, there must be a 2131b6f77fefSas158974 * device pathname associated with it in the /aliases node. 2132b6f77fefSas158974 */ 2133b6f77fefSas158974 static int 2134b6f77fefSas158974 alias_to_prom_dev(char *alias, char *ret_buf) 2135b6f77fefSas158974 { 2136b6f77fefSas158974 char *options_ptr; 2137b6f77fefSas158974 char alias_buf[MAXNAMELEN]; 2138b6f77fefSas158974 char alias_def[MAXPATHLEN]; 2139b6f77fefSas158974 char options[16] = ""; 2140b6f77fefSas158974 int prom_fd = -1; 2141b6f77fefSas158974 int ret; 2142b6f77fefSas158974 int i; 2143b6f77fefSas158974 2144b6f77fefSas158974 if (strchr(alias, '/') != NULL) 2145b6f77fefSas158974 return (DEVFS_INVAL); 2146b6f77fefSas158974 2147b6f77fefSas158974 if (strlen(alias) > (MAXNAMELEN - 1)) 2148b6f77fefSas158974 return (DEVFS_INVAL); 2149b6f77fefSas158974 2150b6f77fefSas158974 if (ret_buf == NULL) { 2151b6f77fefSas158974 return (DEVFS_INVAL); 2152b6f77fefSas158974 } 2153b6f77fefSas158974 2154b6f77fefSas158974 prom_fd = prom_open(O_RDONLY); 2155b6f77fefSas158974 if (prom_fd < 0) { 2156b6f77fefSas158974 return (prom_fd); 2157b6f77fefSas158974 } 2158b6f77fefSas158974 2159b6f77fefSas158974 (void) strlcpy(alias_buf, alias, sizeof (alias_buf)); 2160b6f77fefSas158974 2161b6f77fefSas158974 /* 2162b6f77fefSas158974 * save off any options (minor name info) that is 2163b6f77fefSas158974 * explicitly called out in the alias name 2164b6f77fefSas158974 */ 2165b6f77fefSas158974 if ((options_ptr = strchr(alias_buf, ':')) != NULL) { 2166b6f77fefSas158974 *options_ptr = '\0'; 2167b6f77fefSas158974 (void) strlcpy(options, ++options_ptr, sizeof (options)); 2168b6f77fefSas158974 } 2169b6f77fefSas158974 2170b6f77fefSas158974 *alias_def = '\0'; 2171b6f77fefSas158974 2172b6f77fefSas158974 ret = prom_find_aliases_node(prom_fd); 2173b6f77fefSas158974 if (ret == 0) { 2174b6f77fefSas158974 /* 2175b6f77fefSas158974 * we loop because one alias may define another... we have 2176b6f77fefSas158974 * to work our way down to an actual device definition. 2177b6f77fefSas158974 */ 2178b6f77fefSas158974 for (i = 0; i <= 10; i++) { 2179b6f77fefSas158974 ret = prom_srch_node(prom_fd, alias_buf, alias_def); 2180b6f77fefSas158974 if (ret == -1) { 2181b6f77fefSas158974 break; 2182b6f77fefSas158974 } 2183b6f77fefSas158974 (void) strlcpy(alias_buf, alias_def, 2184b6f77fefSas158974 sizeof (alias_buf)); 2185b6f77fefSas158974 if (*alias_def == '/') { 2186b6f77fefSas158974 break; 2187b6f77fefSas158974 } 2188b6f77fefSas158974 2189b6f77fefSas158974 /* 2190b6f77fefSas158974 * save off any explicit options (minor name info) 2191b6f77fefSas158974 * if none has been encountered yet 2192b6f77fefSas158974 */ 2193b6f77fefSas158974 if (options_ptr == NULL) { 2194b6f77fefSas158974 options_ptr = strchr(alias_buf, ':'); 2195b6f77fefSas158974 if (options_ptr != NULL) { 2196b6f77fefSas158974 *options_ptr = '\0'; 2197b6f77fefSas158974 (void) strlcpy(options, ++options_ptr, 2198b6f77fefSas158974 sizeof (options)); 2199b6f77fefSas158974 } 2200b6f77fefSas158974 } 2201b6f77fefSas158974 } 2202b6f77fefSas158974 } 2203b6f77fefSas158974 prom_close(prom_fd); 2204b6f77fefSas158974 2205b6f77fefSas158974 /* error */ 2206b6f77fefSas158974 if (ret == -1) { 2207b6f77fefSas158974 return (ret); 2208b6f77fefSas158974 } 2209b6f77fefSas158974 221095fa951bSas158974 (void) strlcpy(ret_buf, alias_def, MAXPATHLEN); 2211b6f77fefSas158974 2212b6f77fefSas158974 /* override minor name information */ 2213b6f77fefSas158974 if (options_ptr != NULL) { 2214b6f77fefSas158974 if ((options_ptr = strrchr(ret_buf, ':')) == NULL) { 2215b6f77fefSas158974 (void) strcat(ret_buf, ":"); 2216b6f77fefSas158974 } else { 2217b6f77fefSas158974 *(++options_ptr) = '\0'; 2218b6f77fefSas158974 } 2219b6f77fefSas158974 (void) strcat(ret_buf, options); 2220b6f77fefSas158974 } 2221b6f77fefSas158974 return (0); 2222b6f77fefSas158974 } 2223b6f77fefSas158974 2224b6f77fefSas158974 /* 2225b6f77fefSas158974 * search a prom node for a property name 2226b6f77fefSas158974 */ 2227b6f77fefSas158974 static int 2228b6f77fefSas158974 prom_srch_node(int fd, char *prop_name, char *ret_buf) 2229b6f77fefSas158974 { 2230b6f77fefSas158974 Oppbuf oppbuf; 2231b6f77fefSas158974 struct openpromio *opp = &(oppbuf.opp); 2232b6f77fefSas158974 int *ip = (int *)((void *)opp->oprom_array); 2233b6f77fefSas158974 2234b6f77fefSas158974 (void) memset(oppbuf.buf, 0, BUFSIZE); 2235b6f77fefSas158974 opp->oprom_size = MAXPROPSIZE; 2236b6f77fefSas158974 *ip = 0; 2237b6f77fefSas158974 2238b6f77fefSas158974 if (ioctl(fd, OPROMNXTPROP, opp) < 0) 2239b6f77fefSas158974 return (-1); 2240b6f77fefSas158974 if (opp->oprom_size == 0) 2241b6f77fefSas158974 return (-1); 2242b6f77fefSas158974 2243b6f77fefSas158974 while (strcmp(prop_name, opp->oprom_array) != 0) { 2244b6f77fefSas158974 opp->oprom_size = MAXPROPSIZE; 2245b6f77fefSas158974 if (ioctl(fd, OPROMNXTPROP, opp) < 0) 2246b6f77fefSas158974 return (-1); 2247b6f77fefSas158974 if (opp->oprom_size == 0) 2248b6f77fefSas158974 return (-1); 2249b6f77fefSas158974 } 2250b6f77fefSas158974 opp->oprom_size = MAXVALSIZE; 2251b6f77fefSas158974 if (ioctl(fd, OPROMGETPROP, opp) < 0) 2252b6f77fefSas158974 return (-1); 2253b6f77fefSas158974 2254b6f77fefSas158974 if (opp->oprom_size == 0) 2255b6f77fefSas158974 return (-1); 225695fa951bSas158974 (void) strlcpy(ret_buf, opp->oprom_array, MAXPATHLEN); 2257b6f77fefSas158974 return (0); 2258b6f77fefSas158974 } 2259b6f77fefSas158974 2260b6f77fefSas158974 /* 2261b6f77fefSas158974 * return the aliases node. 2262b6f77fefSas158974 */ 2263b6f77fefSas158974 static int 2264b6f77fefSas158974 prom_find_aliases_node(int fd) 2265b6f77fefSas158974 { 2266b6f77fefSas158974 uint_t child_id; 226795fa951bSas158974 char buf[MAXPATHLEN]; 2268b6f77fefSas158974 2269b6f77fefSas158974 if ((child_id = prom_next_node(fd, 0)) == 0) 2270b6f77fefSas158974 return (-1); 2271b6f77fefSas158974 if ((child_id = prom_child_node(fd, child_id)) == 0) 2272b6f77fefSas158974 return (-1); 2273b6f77fefSas158974 2274b6f77fefSas158974 while (child_id != 0) { 2275b6f77fefSas158974 if (prom_srch_node(fd, "name", buf) == 0) { 2276b6f77fefSas158974 if (strcmp(buf, "aliases") == 0) { 2277b6f77fefSas158974 return (0); 2278b6f77fefSas158974 } 2279b6f77fefSas158974 } 2280b6f77fefSas158974 child_id = prom_next_node(fd, child_id); 2281b6f77fefSas158974 } 2282b6f77fefSas158974 return (-1); 2283b6f77fefSas158974 } 2284b6f77fefSas158974 2285b6f77fefSas158974 /* 2286b6f77fefSas158974 * get sibling 2287b6f77fefSas158974 */ 2288b6f77fefSas158974 static uint_t 2289b6f77fefSas158974 prom_next_node(int fd, uint_t node_id) 2290b6f77fefSas158974 { 2291b6f77fefSas158974 Oppbuf oppbuf; 2292b6f77fefSas158974 struct openpromio *opp = &(oppbuf.opp); 2293b6f77fefSas158974 uint_t *ip = (uint_t *)((void *)opp->oprom_array); 2294b6f77fefSas158974 2295b6f77fefSas158974 (void) memset(oppbuf.buf, 0, BUFSIZE); 2296b6f77fefSas158974 opp->oprom_size = MAXVALSIZE; 2297b6f77fefSas158974 *ip = node_id; 2298b6f77fefSas158974 2299b6f77fefSas158974 if (ioctl(fd, OPROMNEXT, opp) < 0) 2300b6f77fefSas158974 return (0); 2301b6f77fefSas158974 2302b6f77fefSas158974 return (*(uint_t *)((void *)opp->oprom_array)); 2303b6f77fefSas158974 } 2304b6f77fefSas158974 2305b6f77fefSas158974 /* 2306b6f77fefSas158974 * get child 2307b6f77fefSas158974 */ 2308b6f77fefSas158974 static uint_t 2309b6f77fefSas158974 prom_child_node(int fd, uint_t node_id) 2310b6f77fefSas158974 { 2311b6f77fefSas158974 Oppbuf oppbuf; 2312b6f77fefSas158974 struct openpromio *opp = &(oppbuf.opp); 2313b6f77fefSas158974 uint_t *ip = (uint_t *)((void *)opp->oprom_array); 2314b6f77fefSas158974 2315b6f77fefSas158974 (void) memset(oppbuf.buf, 0, BUFSIZE); 2316b6f77fefSas158974 opp->oprom_size = MAXVALSIZE; 2317b6f77fefSas158974 *ip = node_id; 2318b6f77fefSas158974 2319b6f77fefSas158974 if (ioctl(fd, OPROMCHILD, opp) < 0) 2320b6f77fefSas158974 return (0); 2321b6f77fefSas158974 2322b6f77fefSas158974 return (*(uint_t *)((void *)opp->oprom_array)); 2323b6f77fefSas158974 } 2324b6f77fefSas158974 2325b6f77fefSas158974 /* 23267c478bd9Sstevel@tonic-gate * only on sparc for now 23277c478bd9Sstevel@tonic-gate */ 23287c478bd9Sstevel@tonic-gate int 23297c478bd9Sstevel@tonic-gate devfs_bootdev_modifiable(void) 23307c478bd9Sstevel@tonic-gate { 23317c478bd9Sstevel@tonic-gate #if defined(sparc) 23327c478bd9Sstevel@tonic-gate return (0); 23337c478bd9Sstevel@tonic-gate #else 23347c478bd9Sstevel@tonic-gate return (DEVFS_NOTSUP); 23357c478bd9Sstevel@tonic-gate #endif 23367c478bd9Sstevel@tonic-gate } 2337