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