Mercurial > illumos > illumos-gate
changeset 3337:d73d4a90c8ad
6442921 /etc/lib/lu/lubootdev -b cannot determine boot-device for SVM encapsulated fibre boot disks
author | as158974 |
---|---|
date | Tue, 26 Dec 2006 11:49:43 -0800 |
parents | 3d776dff7839 |
children | c774aae3d1fe |
files | usr/src/lib/libdevinfo/devfsinfo.c |
diffstat | 1 files changed, 235 insertions(+), 13 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/lib/libdevinfo/devfsinfo.c Mon Dec 25 23:20:44 2006 -0800 +++ b/usr/src/lib/libdevinfo/devfsinfo.c Tue Dec 26 11:49:43 2006 -0800 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -61,7 +60,9 @@ #define MAXPROPSIZE 256 #define MAXVALSIZE (BUFSIZE - MAXPROPSIZE - sizeof (uint_t)) +/* prom_obp_vers() return values */ #define OBP_OF 0x4 /* versions OBP 3.x */ +#define OBP_NO_ALIAS_NODE 0x8 /* No alias node */ /* for nftw call */ #define FT_DEPTH 15 @@ -112,10 +113,15 @@ static int is_openprom(int); static int prom_dev_to_alias(char *dev, uint_t options, char ***ret_buf); +static int alias_to_prom_dev(char *alias, char *ret_buf); static int prom_srch_aliases_by_def(char *, struct name_list **, struct name_list **, int); +static int prom_find_aliases_node(int fd); static int prom_compare_devs(char *prom_dev1, char *prom_dev2); static int _prom_strcmp(char *s1, char *s2); +static int prom_srch_node(int fd, char *prop_name, char *ret_buf); +static uint_t prom_next_node(int fd, uint_t node_id); +static uint_t prom_child_node(int fd, uint_t node_id); static int prom_obp_vers(void); @@ -918,17 +924,29 @@ return (DEVFS_NOMEM); } - (void) strcpy(prom_path, ptr); + /* + * prom boot-device may be aliased, so we need to do + * the necessary prom alias to dev translation. + */ + if (*ptr != '/') { + if (alias_to_prom_dev(ptr, prom_path) < 0) { + continue; + } + } else { + (void) strcpy(prom_path, ptr); + } + /* now we have a prom device path - convert to a devfs name */ if (devfs_prom_to_dev_name(prom_path, ret_buf) < 0) { - continue; + continue; } + /* append any default minor names necessary */ if (process_minor_name(ret_buf, default_root) < 0) { - continue; + continue; } + found = 1; - found = 1; /* * store the physical device path for now - when * we are all done with the entries, we will convert @@ -1063,6 +1081,7 @@ if ((default_root_len != 0) && (*default_root != '/')) { return (-1); } + /* short cut for an empty array */ if (*bootdev_array == NULL) { return (0); @@ -1073,6 +1092,7 @@ if ((full_path = (char *)malloc(len)) == NULL) { return (-1); } + /* * if the default root path is terminated with a /, we have to * make sure we don't end up with one too many slashes in the @@ -1119,6 +1139,7 @@ (void) mutex_unlock(&dev_lists_lk); return (-1); } + /* * now we have a filled in dev_list. So for each logical device * list in dev_list, count the number of entries in the list, @@ -1140,7 +1161,6 @@ == NULL) { continue; } - list = dev_list[i]; count = 0; @@ -1150,16 +1170,19 @@ count++; list = list->next; } + /* * null terminate the array */ dev_name_array[count] = NULL; - - if (bootdev_array[i]->bootdev_trans[0] != NULL) { + if ((bootdev_array[i] != NULL) && (bootdev_array[i]-> + bootdev_trans[0] != NULL)) { free(bootdev_array[i]->bootdev_trans[0]); } - free(bootdev_array[i]->bootdev_trans); - bootdev_array[i]->bootdev_trans = dev_name_array; + if (bootdev_array[i] != NULL) { + free(bootdev_array[i]->bootdev_trans); + bootdev_array[i]->bootdev_trans = dev_name_array; + } } bootdev_list = NULL; free(full_path); @@ -2100,6 +2123,205 @@ } /* + * converts a prom alias to a prom device name. + * if we find no matching device, then we fail since if were + * given a valid alias, then by definition, there must be a + * device pathname associated with it in the /aliases node. + */ +static int +alias_to_prom_dev(char *alias, char *ret_buf) +{ + char *options_ptr; + char alias_buf[MAXNAMELEN]; + char alias_def[MAXPATHLEN]; + char options[16] = ""; + int prom_fd = -1; + int ret; + int found = 0; + int i; + + if (strchr(alias, '/') != NULL) + return (DEVFS_INVAL); + + if (strlen(alias) > (MAXNAMELEN - 1)) + return (DEVFS_INVAL); + + if (ret_buf == NULL) { + return (DEVFS_INVAL); + } + + prom_fd = prom_open(O_RDONLY); + if (prom_fd < 0) { + return (prom_fd); + } + + (void) strlcpy(alias_buf, alias, sizeof (alias_buf)); + + /* + * save off any options (minor name info) that is + * explicitly called out in the alias name + */ + if ((options_ptr = strchr(alias_buf, ':')) != NULL) { + *options_ptr = '\0'; + (void) strlcpy(options, ++options_ptr, sizeof (options)); + } + + *alias_def = '\0'; + + ret = prom_find_aliases_node(prom_fd); + if (ret == 0) { + /* + * we loop because one alias may define another... we have + * to work our way down to an actual device definition. + */ + for (i = 0; i <= 10; i++) { + ret = prom_srch_node(prom_fd, alias_buf, alias_def); + if (ret == -1) { + break; + } + (void) strlcpy(alias_buf, alias_def, + sizeof (alias_buf)); + if (*alias_def == '/') { + break; + } + + /* + * save off any explicit options (minor name info) + * if none has been encountered yet + */ + if (options_ptr == NULL) { + options_ptr = strchr(alias_buf, ':'); + if (options_ptr != NULL) { + *options_ptr = '\0'; + (void) strlcpy(options, ++options_ptr, + sizeof (options)); + } + } + } + } + prom_close(prom_fd); + + /* error */ + if (ret == -1) { + return (ret); + } + + (void) strlcpy(ret_buf, alias_def, strlen(ret_buf) + 1); + + /* override minor name information */ + if (options_ptr != NULL) { + if ((options_ptr = strrchr(ret_buf, ':')) == NULL) { + (void) strcat(ret_buf, ":"); + } else { + *(++options_ptr) = '\0'; + } + (void) strcat(ret_buf, options); + } + return (0); +} + +/* + * search a prom node for a property name + */ +static int +prom_srch_node(int fd, char *prop_name, char *ret_buf) +{ + Oppbuf oppbuf; + struct openpromio *opp = &(oppbuf.opp); + int *ip = (int *)((void *)opp->oprom_array); + + (void) memset(oppbuf.buf, 0, BUFSIZE); + opp->oprom_size = MAXPROPSIZE; + *ip = 0; + + if (ioctl(fd, OPROMNXTPROP, opp) < 0) + return (-1); + if (opp->oprom_size == 0) + return (-1); + + while (strcmp(prop_name, opp->oprom_array) != 0) { + opp->oprom_size = MAXPROPSIZE; + if (ioctl(fd, OPROMNXTPROP, opp) < 0) + return (-1); + if (opp->oprom_size == 0) + return (-1); + } + opp->oprom_size = MAXVALSIZE; + if (ioctl(fd, OPROMGETPROP, opp) < 0) + return (-1); + + if (opp->oprom_size == 0) + return (-1); + (void) strlcpy(ret_buf, opp->oprom_array, strlen(ret_buf) + 1); + return (0); +} + +/* + * return the aliases node. + */ +static int +prom_find_aliases_node(int fd) +{ + uint_t child_id; + char buf[MAXNAMELEN]; + + if ((child_id = prom_next_node(fd, 0)) == 0) + return (-1); + if ((child_id = prom_child_node(fd, child_id)) == 0) + return (-1); + + while (child_id != 0) { + if (prom_srch_node(fd, "name", buf) == 0) { + if (strcmp(buf, "aliases") == 0) { + return (0); + } + } + child_id = prom_next_node(fd, child_id); + } + return (-1); +} + +/* + * get sibling + */ +static uint_t +prom_next_node(int fd, uint_t node_id) +{ + Oppbuf oppbuf; + struct openpromio *opp = &(oppbuf.opp); + uint_t *ip = (uint_t *)((void *)opp->oprom_array); + + (void) memset(oppbuf.buf, 0, BUFSIZE); + opp->oprom_size = MAXVALSIZE; + *ip = node_id; + + if (ioctl(fd, OPROMNEXT, opp) < 0) + return (0); + + return (*(uint_t *)((void *)opp->oprom_array)); +} + +/* + * get child + */ +static uint_t +prom_child_node(int fd, uint_t node_id) +{ + Oppbuf oppbuf; + struct openpromio *opp = &(oppbuf.opp); + uint_t *ip = (uint_t *)((void *)opp->oprom_array); + + (void) memset(oppbuf.buf, 0, BUFSIZE); + opp->oprom_size = MAXVALSIZE; + *ip = node_id; + + if (ioctl(fd, OPROMCHILD, opp) < 0) + return (0); + + return (*(uint_t *)((void *)opp->oprom_array)); +} + +/* * only on sparc for now */ int