diff options
-rw-r--r-- | usr/src/cmd/devfsadm/audio_link.c | 29 | ||||
-rw-r--r-- | usr/src/cmd/devfsadm/devfsadm.c | 133 | ||||
-rw-r--r-- | usr/src/cmd/devfsadm/devfsadm.h | 7 | ||||
-rw-r--r-- | usr/src/cmd/devfsadm/port_link.c | 13 | ||||
-rw-r--r-- | usr/src/lib/libdevinfo/devinfo.c | 92 | ||||
-rw-r--r-- | usr/src/lib/libdevinfo/libdevinfo.h | 7 | ||||
-rw-r--r-- | usr/src/lib/libdevinfo/mapfile-vers | 4 | ||||
-rw-r--r-- | usr/src/uts/common/fs/devfs/devfs_subr.c | 20 | ||||
-rw-r--r-- | usr/src/uts/common/io/devinfo.c | 67 | ||||
-rw-r--r-- | usr/src/uts/common/os/devcfg.c | 451 | ||||
-rw-r--r-- | usr/src/uts/common/os/inst_sync.c | 14 | ||||
-rw-r--r-- | usr/src/uts/common/os/instance.c | 195 | ||||
-rw-r--r-- | usr/src/uts/common/sys/ddi_impldefs.h | 7 | ||||
-rw-r--r-- | usr/src/uts/common/sys/devinfo_impl.h | 21 | ||||
-rw-r--r-- | usr/src/uts/common/sys/instance.h | 25 | ||||
-rw-r--r-- | usr/src/uts/common/sys/sunddi.h | 39 | ||||
-rw-r--r-- | usr/src/uts/sun4v/os/fillsysinfo.c | 142 |
17 files changed, 1130 insertions, 136 deletions
diff --git a/usr/src/cmd/devfsadm/audio_link.c b/usr/src/cmd/devfsadm/audio_link.c index fbac4a5cd0..42a9aa5cd7 100644 --- a/usr/src/cmd/devfsadm/audio_link.c +++ b/usr/src/cmd/devfsadm/audio_link.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <regex.h> @@ -41,7 +40,7 @@ extern int system_labeled; -static void check_audio_link(char *secondary_link, +static void check_audio_link(di_node_t anynode, char *secondary_link, const char *primary_link_format); static int audio_process(di_minor_t minor, di_node_t node); @@ -99,12 +98,22 @@ static devfsadm_remove_t audio_remove_cbt[] = { DEVFSADM_REMOVE_INIT_V0(audio_remove_cbt); +static di_node_t anynode; + +int +minor_init(void) +{ + anynode = DI_NODE_NIL; + return (DEVFSADM_SUCCESS); +} + int minor_fini(void) { - check_audio_link("audio", "sound/%d"); - check_audio_link("audioctl", "sound/%dctl"); - check_audio_link("dsp", "dsp%d"); + check_audio_link(anynode, "audio", "sound/%d"); + check_audio_link(anynode, "audioctl", "sound/%dctl"); + check_audio_link(anynode, "dsp", "dsp%d"); + anynode = DI_NODE_NIL; return (DEVFSADM_SUCCESS); } @@ -144,6 +153,7 @@ sndstat_process(di_minor_t minor, di_node_t node) char *mn; mn = di_minor_name(minor); + anynode = node; /* * "Special" handling for /dev/sndstat and /dev/mixer. @@ -184,6 +194,7 @@ audio_process(di_minor_t minor, di_node_t node) if (system_labeled) flags = DA_ADD|DA_AUDIO; + anynode = node; mn = di_minor_name(minor); if ((tmp = di_devfs_path(node)) == NULL) { @@ -300,14 +311,14 @@ audio_process(di_minor_t minor, di_node_t node) } static void -check_audio_link(char *secondary, const char *primary_format) +check_audio_link(di_node_t anynode, char *secondary, const char *primary_format) { char primary[PATH_MAX + 1]; int i; int flags = 0; /* if link is present, return */ - if (devfsadm_link_valid(secondary) == DEVFSADM_TRUE) { + if (devfsadm_link_valid(anynode, secondary) == DEVFSADM_TRUE) { return; } @@ -316,7 +327,7 @@ check_audio_link(char *secondary, const char *primary_format) for (i = 0; i < MAX_AUDIO_LINK; i++) { (void) sprintf(primary, primary_format, i); - if (devfsadm_link_valid(primary) == DEVFSADM_TRUE) { + if (devfsadm_link_valid(anynode, primary) == DEVFSADM_TRUE) { /* we read link to get it to the master "real" link */ (void) devfsadm_secondary_link(secondary, primary, flags); diff --git a/usr/src/cmd/devfsadm/devfsadm.c b/usr/src/cmd/devfsadm/devfsadm.c index 523924b3c4..31be6bfd6c 100644 --- a/usr/src/cmd/devfsadm/devfsadm.c +++ b/usr/src/cmd/devfsadm/devfsadm.c @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -251,6 +250,8 @@ static syseventq_t *syseventq_front; static syseventq_t *syseventq_back; static void process_syseventq(); +static di_node_t devi_root_node = DI_NODE_NIL; + int main(int argc, char *argv[]) { @@ -1040,6 +1041,7 @@ devi_tree_walk(struct dca_impl *dcip, int flags, char *ev_subclass) flush_path_to_inst(); dcip->dci_arg = &mlist; + devi_root_node = node; /* protected by lock_dev() */ vprint(CHATTY_MID, "walking device tree\n"); @@ -1064,6 +1066,7 @@ devi_tree_walk(struct dca_impl *dcip, int flags, char *ev_subclass) update_devdb = 0; } + devi_root_node = DI_NODE_NIL; /* protected by lock_dev() */ di_fini(node); } @@ -2720,6 +2723,7 @@ create_link_common(char *devlink, char *contents, int *exists) /* Database is not updated when file_mods == FALSE */ if (file_mods == FALSE) { + /* we want *actual* link contents so no alias redirection */ linksize = readlink(devlink, checkcontents, PATH_MAX); if (linksize > 0) { checkcontents[linksize] = '\0'; @@ -2786,6 +2790,13 @@ create_link_common(char *devlink, char *contents, int *exists) case READ_LINK: + /* + * If there is redirection, new phys path + * and old phys path will not match and the + * link will be created with new phys path + * which is what we want. So we want real + * contents. + */ linksize = readlink(devlink, checkcontents, PATH_MAX); if (linksize >= 0) { checkcontents[linksize] = '\0'; @@ -2867,9 +2878,13 @@ set_logindev_perms(char *devlink) * minor node using a snapshot on the physical path */ (void) resolve_link(devlink, NULL, NULL, &devfs_path, 0); + /* + * We dont need redirection here - the actual link contents + * whether "alias" or "current" are fine + */ if (devfs_path) { di_node_t node; - char *drv = NULL; + char *drv; struct driver_list *list; char *p; @@ -2887,6 +2902,7 @@ set_logindev_perms(char *devlink) node = di_init(pwd_buf, DINFOMINOR); + drv = NULL; if (node) { drv = di_driver_name(node); @@ -2894,7 +2910,6 @@ set_logindev_perms(char *devlink) vprint(FILES_MID, "%s: driver is %s\n", devlink, drv); } - di_fini(node); } /* search thru the driver list specified in logindevperm */ list = newdev->ldev_driver_list; @@ -2915,6 +2930,7 @@ set_logindev_perms(char *devlink) } } free(devfs_path); + di_fini(node); } else { return; } @@ -3126,20 +3142,31 @@ devfsadm_rm_work(char *file, int recurse, int file_type) vprint(REMOVE_MID, "%s%s\n", fcn, file); - /* TYPE_LINK split into multiple if's due to excessive indentations */ - if (file_type == TYPE_LINK) { - (void) strcpy(newfile, dev_dir); - (void) strcat(newfile, "/"); - (void) strcat(newfile, file); + /* + * Note: we don't remove /devices (non-links) entries because they are + * covered by devfs. + */ + if (file_type != TYPE_LINK) { + return; } - if ((file_type == TYPE_LINK) && (recurse == TRUE) && + /* split into multiple if's due to excessive indentations */ + (void) strcpy(newfile, dev_dir); + (void) strcat(newfile, "/"); + (void) strcat(newfile, file); + + /* + * we dont care about the content of the symlink, so + * redirection is not needed. + */ + if ((recurse == TRUE) && ((linksize = readlink(newfile, contents, PATH_MAX)) > 0)) { contents[linksize] = '\0'; - if (is_minor_node(contents, &ptr) == DEVFSADM_TRUE) { - devfsadm_rm_work(++ptr, FALSE, TYPE_DEVICES); - } else { + /* + * recurse if link points to another link + */ + if (is_minor_node(contents, &ptr) != DEVFSADM_TRUE) { if (strncmp(contents, DEV "/", strlen(DEV) + 1) == 0) { devfsadm_rm_work(&contents[strlen(DEV) + 1], TRUE, TYPE_LINK); @@ -3158,21 +3185,14 @@ devfsadm_rm_work(char *file, int recurse, int file_type) } } - if (file_type == TYPE_LINK) { - vprint(VERBOSE_MID, DEVFSADM_UNLINK, newfile); - if (file_mods == TRUE) { - rm_link_from_cache(file); - s_unlink(newfile); - rm_parent_dir_if_empty(newfile); - invalidate_enumerate_cache(); - (void) di_devlink_rm_link(devlink_cache, file); - } + vprint(VERBOSE_MID, DEVFSADM_UNLINK, newfile); + if (file_mods == TRUE) { + rm_link_from_cache(file); + s_unlink(newfile); + rm_parent_dir_if_empty(newfile); + invalidate_enumerate_cache(); + (void) di_devlink_rm_link(devlink_cache, file); } - - /* - * Note: we don't remove /devices entries because they are - * covered by devfs. - */ } void @@ -3284,6 +3304,9 @@ rm_parent_dir_if_empty(char *pathname) * dir_re, and then it searches all links in that cache looking for * any link whose contents match "valid_link_contents" with a corresponding link * which does not match "valid_link". Any such matches are stale and removed. + * + * This happens outside the context of a "reparenting" so we dont need + * redirection. */ void devfsadm_rm_stale_links(char *dir_re, char *valid_link, di_node_t node, @@ -3421,6 +3444,10 @@ build_devlink_list(char *devlink, void *data) (void) strcpy(newlink, devlink); do { + /* + * None of the consumers of this function need redirection + * so this readlink gets the "current" contents + */ linksize = readlink(newlink, contents, PATH_MAX); if (linksize <= 0) { /* @@ -4429,6 +4456,10 @@ matching_dev(char *devpath, void *data) if (nfphash_lookup(devpath + norm_len) != NULL) return; + /* + * Dangling check will work whether "alias" or "current" + * so no need to redirect. + */ if (resolve_link(devpath, NULL, NULL, NULL, 1) == TRUE) { if (call_minor_init(cleanup_data->rm->modptr) == DEVFSADM_FAILURE) { @@ -4456,9 +4487,10 @@ matching_dev(char *devpath, void *data) } int -devfsadm_read_link(char *link, char **devfs_path) +devfsadm_read_link(di_node_t anynode, char *link, char **devfs_path) { char devlink[PATH_MAX]; + char *path; *devfs_path = NULL; @@ -4468,16 +4500,20 @@ devfsadm_read_link(char *link, char **devfs_path) (void) strcat(devlink, link); /* We *don't* want a stat of the /devices node */ - (void) resolve_link(devlink, NULL, NULL, devfs_path, 0); + path = NULL; + (void) resolve_link(devlink, NULL, NULL, &path, 0); + /* redirect if alias to current */ + *devfs_path = di_alias2curr(anynode, path); + free(path); return (*devfs_path ? DEVFSADM_SUCCESS : DEVFSADM_FAILURE); } int -devfsadm_link_valid(char *link) +devfsadm_link_valid(di_node_t anynode, char *link) { struct stat sb; - char devlink[PATH_MAX + 1], *contents = NULL; + char devlink[PATH_MAX + 1], *contents, *raw_contents; int rv, type; int instance = 0; @@ -4490,15 +4526,24 @@ devfsadm_link_valid(char *link) return (DEVFSADM_FALSE); } - contents = NULL; + raw_contents = NULL; type = 0; - if (resolve_link(devlink, &contents, &type, NULL, 1) == TRUE) { + if (resolve_link(devlink, &raw_contents, &type, NULL, 1) == TRUE) { rv = DEVFSADM_FALSE; } else { rv = DEVFSADM_TRUE; } /* + * resolve alias paths for primary links + */ + contents = raw_contents; + if (type == DI_PRIMARY_LINK) { + contents = di_alias2curr(anynode, raw_contents); + free(raw_contents); + } + + /* * The link exists. Add it to the database */ (void) di_devlink_add_link(devlink_cache, link, contents, type); @@ -4524,6 +4569,7 @@ devfsadm_link_valid(char *link) * TRUE if dangling * FALSE if not or if caller doesn't care * Caller is assumed to have initialized pointer contents to NULL + * */ static int resolve_link(char *devpath, char **content_p, int *type_p, char **devfs_path, @@ -4537,6 +4583,10 @@ resolve_link(char *devpath, char **content_p, int *type_p, char **devfs_path, int rv = TRUE; struct stat sb; + /* + * This routine will return the "raw" contents. It is upto the + * the caller to redirect "alias" to "current" (or vice versa) + */ linksize = readlink(devpath, contents, PATH_MAX); if (linksize <= 0) { @@ -5639,6 +5689,7 @@ create_cached_numeral(char *path, numeral_set_t *setp, char *numeral_id, numeral_t *np; int linksize; struct stat sb; + char *contents; const char *fcn = "create_cached_numeral"; assert(index >= 0 && index < setp->re_count); @@ -5692,14 +5743,21 @@ create_cached_numeral(char *path, numeral_set_t *setp, char *numeral_id, linkbuf[linksize] = '\0'; /* + * redirect alias path to current path + * devi_root_node is protected by lock_dev() + */ + contents = di_alias2curr(devi_root_node, linkbuf); + + /* * the following just points linkptr to the root of the /devices * node if it is a minor node, otherwise, to the first char of * linkbuf if it is a link. */ - (void) is_minor_node(linkbuf, &linkptr); + (void) is_minor_node(contents, &linkptr); cmp_str = alloc_cmp_str(linkptr, &rules[index]); if (cmp_str == NULL) { + free(contents); return; } @@ -5713,6 +5771,8 @@ create_cached_numeral(char *path, numeral_set_t *setp, char *numeral_id, np->next = setp->headnumeral; setp->headnumeral = np; + + free(contents); } @@ -5832,6 +5892,11 @@ devfsadm_copy_file(const char *file, const struct stat *stat, return (DEVFSADM_SUCCESS); } } else if ((stat->st_mode & S_IFMT) == S_IFLNK) { + /* + * No need to redirect alias paths. We want a + * true copy. The system on first boot after install + * will redirect paths + */ if ((bytes = readlink(file, linkcontents, PATH_MAX)) == -1) { err_print(READLINK_FAILED, fcn, file, strerror(errno)); return (DEVFSADM_SUCCESS); diff --git a/usr/src/cmd/devfsadm/devfsadm.h b/usr/src/cmd/devfsadm/devfsadm.h index ce26e43375..3d801f66db 100644 --- a/usr/src/cmd/devfsadm/devfsadm.h +++ b/usr/src/cmd/devfsadm/devfsadm.h @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _DEVFSADM_H @@ -212,7 +211,7 @@ typedef struct enumerate_file { int devfsadm_noupdate(void); const char *devfsadm_root_path(void); -int devfsadm_link_valid(char *link); +int devfsadm_link_valid(di_node_t anynode, char *link); int devfsadm_mklink(char *link, di_node_t node, di_minor_t minor, int flags); int devfsadm_secondary_link(char *link, char *primary_link, int flags); void devfsadm_rm_link(char *file); @@ -241,7 +240,7 @@ int disk_enumerate_int(char *devfs_path, int index, char **buf, */ int devfsadm_enumerate_char_start(char *devfs_path, int index, char **buf, devfsadm_enumerate_t rules[], int nrules, char *start); -int devfsadm_read_link(char *link, char **devfs_path); +int devfsadm_read_link(di_node_t node, char *link, char **devfs_path); char *s_strdup(const char *ptr); /* Private interface between reserve subsystm and disks link generator */ diff --git a/usr/src/cmd/devfsadm/port_link.c b/usr/src/cmd/devfsadm/port_link.c index 415b711fe5..70579acbbc 100644 --- a/usr/src/cmd/devfsadm/port_link.c +++ b/usr/src/cmd/devfsadm/port_link.c @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <unistd.h> @@ -419,7 +418,7 @@ out: * NULL otherwise */ static char * -check_compat_ports(char *phys_path, char *minor) +check_compat_ports(di_node_t node, char *phys_path, char *minor) { char portid = *minor; char port[PATH_MAX]; @@ -429,7 +428,7 @@ check_compat_ports(char *phys_path, char *minor) return (NULL); (void) snprintf(port, sizeof (port), "term/%c", portid); - if (devfsadm_read_link(port, &devfs_path) == DEVFSADM_SUCCESS && + if (devfsadm_read_link(node, port, &devfs_path) == DEVFSADM_SUCCESS && portcmp(devfs_path, phys_path) != 0) { free(devfs_path); return (NULL); @@ -438,7 +437,7 @@ check_compat_ports(char *phys_path, char *minor) free(devfs_path); (void) snprintf(port, sizeof (port), "cua/%c", portid); - if (devfsadm_read_link(port, &devfs_path) == DEVFSADM_SUCCESS && + if (devfsadm_read_link(node, port, &devfs_path) == DEVFSADM_SUCCESS && portcmp(devfs_path, phys_path) != 0) { free(devfs_path); return (NULL); @@ -500,7 +499,7 @@ onbrd_port_create(di_minor_t minor, di_node_t node) buf = NULL; #ifdef __i386 - buf = check_compat_ports(p_path, minor_name); + buf = check_compat_ports(node, p_path, minor_name); #endif /* @@ -562,7 +561,7 @@ onbrd_dialout_create(di_minor_t minor, di_node_t node) buf = NULL; #ifdef __i386 - buf = check_compat_ports(p_path, mn); + buf = check_compat_ports(node, p_path, mn); #endif /* diff --git a/usr/src/lib/libdevinfo/devinfo.c b/usr/src/lib/libdevinfo/devinfo.c index e9c3e18375..1222707c36 100644 --- a/usr/src/lib/libdevinfo/devinfo.c +++ b/usr/src/lib/libdevinfo/devinfo.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -3696,8 +3695,53 @@ di_walk_lnode(di_node_t root, uint_t flag, void *arg, return (0); } -di_node_t -di_lookup_node(di_node_t root, char *devfspath) +static char * +alias_to_curr(di_node_t anynode, char *devfspath, di_node_t *nodep) +{ + caddr_t pa; + struct di_all *all; + struct di_alias *di_alias; + di_node_t node; + char *curr; + char *cp; + char *alias; + di_off_t off; + char buf[MAXPATHLEN]; + + *nodep = NULL; + + assert(anynode != DI_NODE_NIL); + + pa = (caddr_t)anynode - DI_NODE(anynode)->self; + all = DI_ALL(pa); + + di_alias = NULL; + for (off = all->aliases; off > 0; off = di_alias->next) { + di_alias = DI_ALIAS(pa + off); + alias = di_alias->alias; + if (strncmp(devfspath, alias, strlen(alias)) == 0) { + cp = devfspath + strlen(alias); + node = DI_NODE(pa + di_alias->curroff); + assert(node != DI_NODE_NIL); + if (*cp == '\0') { + *nodep = node; + return (NULL); + } else if (*cp == '/') { + curr = di_devfs_path(node); + (void) snprintf(buf, sizeof (buf), "%s%s", + curr, cp); + di_devfs_path_free(curr); + curr = strdup(buf); + return (curr); + } + } + } + + return (NULL); +} + +static di_node_t +di_lookup_node_impl(di_node_t root, char *devfspath) { struct di_all *dap; di_node_t node; @@ -3785,6 +3829,46 @@ di_lookup_node(di_node_t root, char *devfspath) return (node); } +di_node_t +di_lookup_node(di_node_t root, char *devfspath) +{ + di_node_t node; + char *curr; + + node = di_lookup_node_impl(root, devfspath); + if (node != DI_NODE_NIL) { + return (node); + } + + /* node is already set to DI_NODE_NIL */ + curr = alias_to_curr(root, devfspath, &node); + if (curr == NULL) { + /* node may or may node be DI_NODE_NIL */ + return (node); + } + + node = di_lookup_node_impl(root, curr); + + free(curr); + + return (node); +} + +char * +di_alias2curr(di_node_t anynode, char *alias) +{ + di_node_t currnode = DI_NODE_NIL; + char *curr = alias_to_curr(anynode, alias, &currnode); + + if (curr == NULL && currnode != DI_NODE_NIL) { + return (di_devfs_path(currnode)); + } else if (curr == NULL) { + return (strdup(alias)); + } + + return (curr); +} + di_path_t di_lookup_path(di_node_t root, char *devfspath) { diff --git a/usr/src/lib/libdevinfo/libdevinfo.h b/usr/src/lib/libdevinfo/libdevinfo.h index 7789edd60a..8f685a1524 100644 --- a/usr/src/lib/libdevinfo/libdevinfo.h +++ b/usr/src/lib/libdevinfo/libdevinfo.h @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _LIBDEVINFO_H @@ -559,6 +558,10 @@ extern char *di_dim_path_devices(di_dim_t, extern char *di_dim_path_dev(di_dim_t, char *drv_name, int instance, char *minor_name); +/* + * Alias related exported interfaces + */ +char *di_alias2curr(di_node_t anynode, char *alias); #ifdef __cplusplus } diff --git a/usr/src/lib/libdevinfo/mapfile-vers b/usr/src/lib/libdevinfo/mapfile-vers index bfad2642f2..368feea35d 100644 --- a/usr/src/lib/libdevinfo/mapfile-vers +++ b/usr/src/lib/libdevinfo/mapfile-vers @@ -19,8 +19,7 @@ # CDDL HEADER END # # -# Copyright 2010 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # # @@ -39,6 +38,7 @@ SUNW_1.4 { global: + di_alias2curr; di_path_bus_addr; di_path_client_devfs_path; di_path_client_next_path; diff --git a/usr/src/uts/common/fs/devfs/devfs_subr.c b/usr/src/uts/common/fs/devfs/devfs_subr.c index 23c3e1cfb7..8273bced8e 100644 --- a/usr/src/uts/common/fs/devfs/devfs_subr.c +++ b/usr/src/uts/common/fs/devfs/devfs_subr.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -1094,6 +1093,23 @@ founddv: goto notfound; } + ASSERT(devi); + + /* Check if this is a path alias */ + if (ddi_aliases_present == B_TRUE && ddi_get_parent(devi) != pdevi) { + char *curr = kmem_alloc(MAXPATHLEN, KM_SLEEP); + + (void) ddi_pathname(devi, curr); + + vp = NULL; + if (devfs_lookupname(curr, NULL, &vp) == 0 && vp) { + dv = VTODV(vp); + kmem_free(curr, MAXPATHLEN); + goto found; + } + kmem_free(curr, MAXPATHLEN); + } + /* * If we configured a hidden node, consider it notfound. */ diff --git a/usr/src/uts/common/io/devinfo.c b/usr/src/uts/common/io/devinfo.c index 490d7fc28e..84a48e086e 100644 --- a/usr/src/uts/common/io/devinfo.c +++ b/usr/src/uts/common/io/devinfo.c @@ -20,8 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -767,12 +766,13 @@ di_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) #endif /* Copyin ioctl args, store in the snapshot. */ - if (copyinstr((void *)arg, all->root_path, + if (copyinstr((void *)arg, all->req_path, sizeof (((struct dinfo_io *)(NULL))->root_path), &size) != 0) { di_freemem(st); (void) di_setstate(st, IOC_IDLE); return (EFAULT); } + (void) strcpy(all->root_path, all->req_path); off += size; /* real length of root_path */ if ((st->command & DINFOCLEANUP) && !DEVICES_FILES_CLEANABLE(st)) { @@ -1295,6 +1295,44 @@ di_key_cmp(mod_hash_key_t key1, mod_hash_key_t key2) } } +static void +di_copy_aliases(struct di_state *st, alias_pair_t *apair, di_off_t *offp) +{ + di_off_t off; + struct di_all *all = DI_ALL_PTR(st); + struct di_alias *di_alias; + di_off_t curroff; + dev_info_t *currdip; + size_t size; + + currdip = NULL; + if (resolve_pathname(apair->pair_alias, &currdip, NULL, NULL) != 0) { + return; + } + + if (di_dip_find(st, currdip, &curroff) != 0) { + ndi_rele_devi(currdip); + return; + } + ndi_rele_devi(currdip); + + off = *offp; + size = sizeof (struct di_alias); + size += strlen(apair->pair_alias) + 1; + off = di_checkmem(st, off, size); + di_alias = DI_ALIAS(di_mem_addr(st, off)); + + di_alias->self = off; + di_alias->next = all->aliases; + all->aliases = off; + (void) strcpy(di_alias->alias, apair->pair_alias); + di_alias->curroff = curroff; + + off += size; + + *offp = off; +} + /* * This is the main function that takes a snapshot */ @@ -1308,11 +1346,24 @@ di_snapshot(struct di_state *st) int plen; char *path; vnode_t *vp; + int i; all = DI_ALL_PTR(st); dcmn_err((CE_CONT, "Taking a snapshot of devinfo tree...\n")); /* + * Translate requested root path if an alias and snap-root != "/" + */ + if (ddi_aliases_present == B_TRUE && strcmp(all->root_path, "/") != 0) { + /* If there is no redirected alias, use root_path as is */ + rootnode = ddi_alias_redirect(all->root_path); + if (rootnode) { + (void) ddi_pathname(rootnode, all->root_path); + goto got_root; + } + } + + /* * Verify path before entrusting it to e_ddi_hold_devi_by_path because * some platforms have OBP bugs where executing the NDI_PROMNAME code * path against an invalid path results in panic. The lookupnameat @@ -1341,6 +1392,7 @@ di_snapshot(struct di_state *st) return (0); } +got_root: (void) snprintf(buf, sizeof (buf), "devinfo registered dips (statep=%p)", (void *)st); @@ -1391,6 +1443,15 @@ di_snapshot(struct di_state *st) off = di_getlink_data(off, st); } + all->aliases = 0; + if (ddi_aliases_present == B_FALSE) + goto done; + + for (i = 0; i < ddi_aliases.dali_num_pairs; i++) { + di_copy_aliases(st, &(ddi_aliases.dali_alias_pairs[i]), &off); + } + +done: /* * Free up hash tables */ diff --git a/usr/src/uts/common/os/devcfg.c b/usr/src/uts/common/os/devcfg.c index b303223563..38f6e3725b 100644 --- a/usr/src/uts/common/os/devcfg.c +++ b/usr/src/uts/common/os/devcfg.c @@ -55,14 +55,14 @@ #include <sys/sunldi.h> #include <sys/sunldi_impl.h> #include <sys/bootprops.h> +#include <sys/varargs.h> +#include <sys/modhash.h> +#include <sys/instance.h> #if defined(__amd64) && !defined(__xpv) #include <sys/iommulib.h> #endif -/* XXX remove before putback */ -boolean_t ddi_err_panic = B_TRUE; - #ifdef DEBUG int ddidebug = DDI_AUDIT; #else @@ -170,10 +170,18 @@ int mtc_off; /* turn off mt config */ int quiesce_debug = 0; +boolean_t ddi_aliases_present = B_FALSE; +ddi_alias_t ddi_aliases; +uint_t tsd_ddi_redirect; + +#define DDI_ALIAS_HASH_SIZE (2700) + static kmem_cache_t *ddi_node_cache; /* devinfo node cache */ static devinfo_log_header_t *devinfo_audit_log; /* devinfo log */ static int devinfo_log_size; /* size in pages */ +boolean_t ddi_err_panic = B_FALSE; + static int lookup_compatible(dev_info_t *, uint_t); static char *encode_composite_string(char **, uint_t, size_t *, uint_t); static void link_to_driver_list(dev_info_t *); @@ -209,6 +217,10 @@ static void i_ddi_check_retire(dev_info_t *dip); static void quiesce_one_device(dev_info_t *, void *); +dev_info_t *ddi_alias_redirect(char *alias); +char *ddi_curr_redirect(char *currpath); + + /* * dev_info cache and node management */ @@ -5485,21 +5497,30 @@ again: (void) i_ndi_make_spec_children(pdip, flags); * an entire branch. */ int -ndi_devi_config_one(dev_info_t *dip, char *devnm, dev_info_t **dipp, int flags) +ndi_devi_config_one(dev_info_t *pdip, char *devnm, dev_info_t **dipp, int flags) { int error; int (*f)(); + char *nmdup; + int duplen; int branch_event = 0; + ASSERT(pdip); + ASSERT(devnm); ASSERT(dipp); - ASSERT(i_ddi_devi_attached(dip)); + ASSERT(i_ddi_devi_attached(pdip)); NDI_CONFIG_DEBUG((CE_CONT, "ndi_devi_config_one: par = %s%d (%p), child = %s\n", - ddi_driver_name(dip), ddi_get_instance(dip), (void *)dip, devnm)); + ddi_driver_name(pdip), ddi_get_instance(pdip), + (void *)pdip, devnm)); + + *dipp = NULL; - if (pm_pre_config(dip, devnm) != DDI_SUCCESS) + if (pm_pre_config(pdip, devnm) != DDI_SUCCESS) { + cmn_err(CE_WARN, "preconfig failed: %s", devnm); return (NDI_FAILURE); + } if ((flags & (NDI_NO_EVENT | NDI_BRANCH_EVENT_OP)) == 0 && (flags & NDI_CONFIG)) { @@ -5507,17 +5528,47 @@ ndi_devi_config_one(dev_info_t *dip, char *devnm, dev_info_t **dipp, int flags) branch_event = 1; } - if ((DEVI(dip)->devi_ops->devo_bus_ops == NULL) || - (DEVI(dip)->devi_ops->devo_bus_ops->busops_rev < BUSO_REV_5) || - (f = DEVI(dip)->devi_ops->devo_bus_ops->bus_config) == NULL) { - error = devi_config_one(dip, devnm, dipp, flags, 0); + nmdup = strdup(devnm); + duplen = strlen(devnm) + 1; + + if ((DEVI(pdip)->devi_ops->devo_bus_ops == NULL) || + (DEVI(pdip)->devi_ops->devo_bus_ops->busops_rev < BUSO_REV_5) || + (f = DEVI(pdip)->devi_ops->devo_bus_ops->bus_config) == NULL) { + error = devi_config_one(pdip, devnm, dipp, flags, 0); } else { /* call bus_config entry point */ - error = (*f)(dip, flags, BUS_CONFIG_ONE, (void *)devnm, dipp); + error = (*f)(pdip, flags, BUS_CONFIG_ONE, (void *)devnm, dipp); + } + + if (error) { + *dipp = NULL; + } + + /* + * if we fail to lookup and this could be an alias, lookup currdip + * To prevent recursive lookups into the same hash table, only + * do the currdip lookups once the hash table init is complete. + * Use tsd so that redirection doesn't recurse + */ + if (error) { + char *alias = kmem_alloc(MAXPATHLEN, KM_NOSLEEP); + if (alias == NULL) { + ddi_err(DER_PANIC, pdip, "alias alloc failed: %s", + nmdup); + } + (void) ddi_pathname(pdip, alias); + (void) strlcat(alias, "/", MAXPATHLEN); + (void) strlcat(alias, nmdup, MAXPATHLEN); + + *dipp = ddi_alias_redirect(alias); + error = (*dipp ? NDI_SUCCESS : NDI_FAILURE); + + kmem_free(alias, MAXPATHLEN); } + kmem_free(nmdup, duplen); - if (error || (flags & NDI_CONFIG) == 0) { - pm_post_config(dip, devnm); + if (error || !(flags & NDI_CONFIG)) { + pm_post_config(pdip, devnm); return (error); } @@ -5529,7 +5580,7 @@ ndi_devi_config_one(dev_info_t *dip, char *devnm, dev_info_t **dipp, int flags) ASSERT(*dipp); error = devi_config_common(*dipp, flags, DDI_MAJOR_T_NONE); - pm_post_config(dip, devnm); + pm_post_config(pdip, devnm); if (branch_event) (void) i_log_devfs_branch_add(*dipp); @@ -5537,7 +5588,6 @@ ndi_devi_config_one(dev_info_t *dip, char *devnm, dev_info_t **dipp, int flags) return (error); } - /* * Enumerate and attach a child specified by name 'devnm'. * Called during configure the OBP options. This configures @@ -8553,6 +8603,375 @@ i_ddi_check_retire(dev_info_t *dip) mdi_phci_retire_finalize(dip, phci_only, &constraint); } + +#define VAL_ALIAS(array, x) (strlen(array[x].pair_alias)) +#define VAL_CURR(array, x) (strlen(array[x].pair_curr)) +#define SWAP(array, x, y) \ +{ \ + alias_pair_t tmpair = array[x]; \ + array[x] = array[y]; \ + array[y] = tmpair; \ +} + +static int +partition_curr(alias_pair_t *array, int start, int end) +{ + int i = start - 1; + int j = end + 1; + int pivot = start; + + for (;;) { + do { + j--; + } while (VAL_CURR(array, j) > VAL_CURR(array, pivot)); + + do { + i++; + } while (VAL_CURR(array, i) < VAL_CURR(array, pivot)); + + if (i < j) + SWAP(array, i, j) + else + return (j); + } +} + +static int +partition_aliases(alias_pair_t *array, int start, int end) +{ + int i = start - 1; + int j = end + 1; + int pivot = start; + + for (;;) { + do { + j--; + } while (VAL_ALIAS(array, j) > VAL_ALIAS(array, pivot)); + + do { + i++; + } while (VAL_ALIAS(array, i) < VAL_ALIAS(array, pivot)); + + if (i < j) + SWAP(array, i, j) + else + return (j); + } +} +static void +sort_alias_pairs(alias_pair_t *array, int start, int end) +{ + int mid; + + if (start < end) { + mid = partition_aliases(array, start, end); + sort_alias_pairs(array, start, mid); + sort_alias_pairs(array, mid + 1, end); + } +} + +static void +sort_curr_pairs(alias_pair_t *array, int start, int end) +{ + int mid; + + if (start < end) { + mid = partition_curr(array, start, end); + sort_curr_pairs(array, start, mid); + sort_curr_pairs(array, mid + 1, end); + } +} + +static void +create_sorted_pairs(plat_alias_t *pali, int npali) +{ + int i; + int j; + int k; + int count; + + count = 0; + for (i = 0; i < npali; i++) { + count += pali[i].pali_naliases; + } + + ddi_aliases.dali_alias_pairs = kmem_zalloc( + (sizeof (alias_pair_t)) * count, KM_NOSLEEP); + if (ddi_aliases.dali_alias_pairs == NULL) { + cmn_err(CE_PANIC, "alias path-pair alloc failed"); + /*NOTREACHED*/ + } + + ddi_aliases.dali_curr_pairs = kmem_zalloc( + (sizeof (alias_pair_t)) * count, KM_NOSLEEP); + if (ddi_aliases.dali_curr_pairs == NULL) { + cmn_err(CE_PANIC, "curr path-pair alloc failed"); + /*NOTREACHED*/ + } + + for (i = 0, k = 0; i < npali; i++) { + for (j = 0; j < pali[i].pali_naliases; j++, k++) { + ddi_aliases.dali_alias_pairs[k].pair_curr = + ddi_aliases.dali_curr_pairs[k].pair_curr = + pali[i].pali_current; + ddi_aliases.dali_alias_pairs[k].pair_alias = + ddi_aliases.dali_curr_pairs[k].pair_alias = + pali[i].pali_aliases[j]; + } + } + + ASSERT(k == count); + + ddi_aliases.dali_num_pairs = count; + + /* Now sort the array based on length of pair_alias */ + sort_alias_pairs(ddi_aliases.dali_alias_pairs, 0, count - 1); + sort_curr_pairs(ddi_aliases.dali_curr_pairs, 0, count - 1); +} + +void +ddi_register_aliases(plat_alias_t *pali, uint64_t npali) +{ + + ASSERT((pali == NULL) ^ (npali != 0)); + + if (npali == 0) { + ddi_err(DER_PANIC, NULL, "npali == 0"); + /*NOTREACHED*/ + } + + if (ddi_aliases_present == B_TRUE) { + ddi_err(DER_PANIC, NULL, "multiple init"); + /*NOTREACHED*/ + } + + ddi_aliases.dali_alias_TLB = mod_hash_create_strhash( + "ddi-alias-tlb", DDI_ALIAS_HASH_SIZE, mod_hash_null_valdtor); + if (ddi_aliases.dali_alias_TLB == NULL) { + ddi_err(DER_PANIC, NULL, "alias TLB hash alloc failed"); + /*NOTREACHED*/ + } + + ddi_aliases.dali_curr_TLB = mod_hash_create_strhash( + "ddi-curr-tlb", DDI_ALIAS_HASH_SIZE, mod_hash_null_valdtor); + if (ddi_aliases.dali_curr_TLB == NULL) { + ddi_err(DER_PANIC, NULL, "curr TLB hash alloc failed"); + /*NOTREACHED*/ + } + + create_sorted_pairs(pali, npali); + + tsd_create(&tsd_ddi_redirect, NULL); + + ddi_aliases_present = B_TRUE; +} + +static dev_info_t * +path_to_dip(char *path) +{ + dev_info_t *currdip; + int error; + char *pdup; + + pdup = ddi_strdup(path, KM_NOSLEEP); + if (pdup == NULL) { + cmn_err(CE_PANIC, "path strdup failed: %s", path); + /*NOTREACHED*/ + } + + error = resolve_pathname(pdup, &currdip, NULL, NULL); + + kmem_free(pdup, strlen(path) + 1); + + return (error ? NULL : currdip); +} + +dev_info_t * +ddi_alias_to_currdip(char *alias, int i) +{ + alias_pair_t *pair; + char *curr; + dev_info_t *currdip = NULL; + char *aliasdup; + int len; + + pair = &(ddi_aliases.dali_alias_pairs[i]); + len = strlen(pair->pair_alias); + + curr = NULL; + aliasdup = ddi_strdup(alias, KM_NOSLEEP); + if (aliasdup == NULL) { + cmn_err(CE_PANIC, "aliasdup alloc failed"); + /*NOTREACHED*/ + } + + if (strncmp(alias, pair->pair_alias, len) != 0) + goto out; + + if (alias[len] != '/' && alias[len] != '\0') + goto out; + + + curr = kmem_alloc(MAXPATHLEN, KM_NOSLEEP); + if (curr == NULL) { + cmn_err(CE_PANIC, "curr alloc failed"); + /*NOTREACHED*/ + } + (void) strlcpy(curr, pair->pair_curr, MAXPATHLEN); + if (alias[len] == '/') { + (void) strlcat(curr, "/", MAXPATHLEN); + (void) strlcat(curr, &alias[len + 1], MAXPATHLEN); + } + + currdip = path_to_dip(curr); + +out: + if (currdip) { + (void) mod_hash_insert(ddi_aliases.dali_alias_TLB, + (mod_hash_key_t)aliasdup, (mod_hash_val_t)curr); + } else { + (void) mod_hash_insert(ddi_aliases.dali_alias_TLB, + (mod_hash_key_t)aliasdup, (mod_hash_val_t)NULL); + if (curr) + kmem_free(curr, MAXPATHLEN); + } + + return (currdip); +} + +char * +ddi_curr_to_alias(char *curr, int i) +{ + alias_pair_t *pair; + char *alias; + char *currdup; + int len; + + pair = &(ddi_aliases.dali_curr_pairs[i]); + + len = strlen(pair->pair_curr); + + alias = NULL; + + currdup = ddi_strdup(curr, KM_NOSLEEP); + if (currdup == NULL) { + cmn_err(CE_PANIC, "currdup alloc failed"); + /*NOTREACHED*/ + } + + if (strncmp(curr, pair->pair_curr, len) != 0) + goto out; + + if (curr[len] != '/' && curr[len] != '\0') + goto out; + + alias = kmem_alloc(MAXPATHLEN, KM_NOSLEEP); + if (alias == NULL) { + cmn_err(CE_PANIC, "alias alloc failed"); + /*NOTREACHED*/ + } + + (void) strlcpy(alias, pair->pair_alias, MAXPATHLEN); + if (curr[len] == '/') { + (void) strlcat(alias, "/", MAXPATHLEN); + (void) strlcat(alias, &curr[len + 1], MAXPATHLEN); + } + + if (e_ddi_path_to_instance(alias) == NULL) { + kmem_free(alias, MAXPATHLEN); + alias = NULL; + } + +out: + (void) mod_hash_insert(ddi_aliases.dali_curr_TLB, + (mod_hash_key_t)currdup, (mod_hash_val_t)alias); + + return (alias); +} + +dev_info_t * +ddi_alias_redirect(char *alias) +{ + char *curr; + char *aliasdup; + dev_info_t *currdip; + int i; + + if (ddi_aliases_present == B_FALSE) + return (NULL); + + if (tsd_get(tsd_ddi_redirect)) + return (NULL); + + (void) tsd_set(tsd_ddi_redirect, (void *)1); + + ASSERT(ddi_aliases.dali_alias_TLB); + ASSERT(ddi_aliases.dali_alias_pairs); + + curr = NULL; + if (mod_hash_find(ddi_aliases.dali_alias_TLB, + (mod_hash_key_t)alias, (mod_hash_val_t *)&curr) == 0) { + currdip = curr ? path_to_dip(curr) : NULL; + goto out; + } + + aliasdup = ddi_strdup(alias, KM_NOSLEEP); + if (aliasdup == NULL) { + cmn_err(CE_PANIC, "aliasdup alloc failed"); + /*NOTREACHED*/ + } + + /* The TLB has no translation, do it the hard way */ + currdip = NULL; + for (i = ddi_aliases.dali_num_pairs - 1; i >= 0; i--) { + currdip = ddi_alias_to_currdip(alias, i); + if (currdip) + break; + } +out: + (void) tsd_set(tsd_ddi_redirect, NULL); + + return (currdip); +} + +char * +ddi_curr_redirect(char *curr) +{ + char *alias; + int i; + + if (ddi_aliases_present == B_FALSE) + return (NULL); + + if (tsd_get(tsd_ddi_redirect)) + return (NULL); + + (void) tsd_set(tsd_ddi_redirect, (void *)1); + + ASSERT(ddi_aliases.dali_curr_TLB); + ASSERT(ddi_aliases.dali_curr_pairs); + + alias = NULL; + if (mod_hash_find(ddi_aliases.dali_curr_TLB, + (mod_hash_key_t)curr, (mod_hash_val_t *)&alias) == 0) { + goto out; + } + + + /* The TLB has no translation, do it the slow way */ + alias = NULL; + for (i = ddi_aliases.dali_num_pairs - 1; i >= 0; i--) { + alias = ddi_curr_to_alias(curr, i); + if (alias) + break; + } + +out: + (void) tsd_set(tsd_ddi_redirect, NULL); + + return (alias); +} + void ddi_err(ddi_err_t ade, dev_info_t *rdip, const char *fmt, ...) { diff --git a/usr/src/uts/common/os/inst_sync.c b/usr/src/uts/common/os/inst_sync.c index b0f3b11d85..92a24cb703 100644 --- a/usr/src/uts/common/os/inst_sync.c +++ b/usr/src/uts/common/os/inst_sync.c @@ -19,12 +19,9 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * Syscall to write out the instance number data structures to * stable storage. @@ -123,12 +120,18 @@ _fini(void) static int in_write_instance(struct vnode *vp); +static int inst_sync_disable = 0; + static int in_sync_sys(char *pathname, uint_t flags) { struct vnode *vp; int error; + /* For debugging/testing */ + if (inst_sync_disable) + return (0); + /* * We must have sufficient privilege to do this, since we lock critical * data structures whilst we're doing it .. @@ -294,6 +297,9 @@ in_walktree(in_node_t *np, char *this) for (error = 0; np; np = np->in_sibling) { + if (np->in_drivers == NULL) + continue; + if (np->in_unit_addr[0] == '\0') (void) sprintf(this, "/%s", np->in_node_name); else diff --git a/usr/src/uts/common/os/instance.c b/usr/src/uts/common/os/instance.c index 6d4bc8de3f..163ca4c480 100644 --- a/usr/src/uts/common/os/instance.c +++ b/usr/src/uts/common/os/instance.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -48,6 +47,9 @@ #include <sys/modctl.h> #include <sys/console.h> #include <sys/cladm.h> +#include <sys/sysmacros.h> +#include <sys/crc32.h> + static void in_preassign_instance(void); static void i_log_devfs_instance_mod(void); @@ -71,8 +73,12 @@ static int in_pathin(char *cp, int instance, char *bname, struct bind **args); static int in_next_instance_block(major_t, int); static int in_next_instance(major_t); +#pragma weak plat_ioaliases_init + + /* external functions */ extern char *i_binding_to_drv_name(char *bname); +extern void plat_ioaliases_init(void); /* * This plus devnames defines the entire software state of the instance world. @@ -87,7 +93,7 @@ typedef struct in_softstate { kmutex_t ins_serial; kcondvar_t ins_serial_cv; int ins_busy; - char ins_dirty; /* need flush */ + boolean_t ins_dirty; /* instance info needs flush */ } in_softstate_t; static in_softstate_t e_ddi_inst_state; @@ -106,7 +112,7 @@ static in_softstate_t e_ddi_inst_state; * IN_PROVISIONAL: When a node is assigned an instance number in * e_ddi_assign_instance(), its state is set to IN_PROVISIONAL. * Subsequently, the framework will always call either - * e_ddi_keep_instance() which makes the node IN_PERMANENT, + * e_ddi_keep_instance() which makes the node IN_PERMANENT * or e_ddi_free_instance(), which deletes the node. * IN_PERMANENT: * If e_ddi_keep_instance() is called on an IN_PROVISIONAL node, @@ -123,6 +129,7 @@ static char *instance_file_backup = INSTANCE_FILE INSTANCE_FILE_SUFFIX; #define PTI_NOT_FOUND 1 #define PTI_REBUILD 2 + /* * Path to instance file magic string used for first time boot after * an install. If this is the first string in the file we will @@ -151,6 +158,12 @@ e_ddi_instance_init(void) e_ddi_enter_instance(); /* + * Init the ioaliases if the platform supports it + */ + if (&plat_ioaliases_init) + plat_ioaliases_init(); + + /* * Create the root node, instance zallocs to 0. * The name and address of this node never get examined, we always * start searching with its first child. @@ -192,6 +205,12 @@ e_ddi_instance_init(void) break; case PTI_REBUILD: + /* + * path_to_inst has magic str requesting a create + * Convert boot to reconfig boot to ensure /dev is + * in sync with new path_to_inst. + */ + boothowto |= RB_RECONFIG; cmn_err(CE_CONT, "?Using default device instance data\n"); break; @@ -486,7 +505,7 @@ in_assign_instance_block(dev_info_t *dip) /* notify devfsadmd to sync of path_to_inst file */ mutex_enter(&e_ddi_inst_state.ins_serial); i_log_devfs_instance_mod(); - e_ddi_inst_state.ins_dirty = 1; + e_ddi_inst_state.ins_dirty = B_TRUE; mutex_exit(&e_ddi_inst_state.ins_serial); return (1); } @@ -549,19 +568,38 @@ e_ddi_assign_instance(dev_info_t *dip) ASSERT(np == in_devwalk(dip, &ap, NULL)); /* + * Link the devinfo node and in_node_t + */ + if (DEVI(dip)->devi_in_node || np->in_devi) { + ddi_err(DER_MODE, dip, "devinfo and instance node (%p) " + "interlink fields are not NULL", (void *)np); + } + DEVI(dip)->devi_in_node = np; + np->in_devi = dip; + + /* * Look for driver entry, allocate one if not found */ bname = (char *)ddi_driver_name(dip); dp = in_drvwalk(np, bname); if (dp == NULL) { - dp = in_alloc_drv(bname); - ASSERT(dp != NULL); - major = ddi_driver_major(dip); - ASSERT(major != DDI_MAJOR_T_NONE); - in_endrv(np, dp); - in_set_instance(dip, dp, major); - dp->ind_state = IN_PROVISIONAL; - in_hashdrv(dp); + + if (ddi_aliases_present == B_TRUE) { + e_ddi_borrow_instance(dip, np); + } + + if ((dp = in_drvwalk(np, bname)) == NULL) { + dp = in_alloc_drv(bname); + ASSERT(dp != NULL); + major = ddi_driver_major(dip); + ASSERT(major != DDI_MAJOR_T_NONE); + in_endrv(np, dp); + in_set_instance(dip, dp, major); + dp->ind_state = IN_PROVISIONAL; + in_hashdrv(dp); + } else { + dp->ind_state = IN_BORROWED; + } } ret = dp->ind_instance; @@ -738,11 +776,26 @@ e_ddi_free_instance(dev_info_t *dip, char *addr) e_ddi_enter_instance(); np = in_devwalk(dip, &ap, addr); ASSERT(np); + + /* + * Break the interlink between dip and np + */ + if (DEVI(dip)->devi_in_node != np || np->in_devi != dip) { + ddi_err(DER_MODE, dip, "devinfo node linked to " + "wrong instance node: %p", (void *)np); + } + DEVI(dip)->devi_in_node = NULL; + np->in_devi = NULL; + dp = in_drvwalk(np, name); ASSERT(dp); if (dp->ind_state == IN_PROVISIONAL) { in_removedrv(dnp, dp); } + if (dp->ind_state == IN_BORROWED) { + dp->ind_state = IN_PERMANENT; + e_ddi_return_instance(dip, addr, np); + } if (np->in_drivers == NULL) { in_removenode(dnp, np, ap); } @@ -785,10 +838,10 @@ e_ddi_keep_instance(dev_info_t *dip) ASSERT(dp); mutex_enter(&e_ddi_inst_state.ins_serial); - if (dp->ind_state == IN_PROVISIONAL) { + if (dp->ind_state == IN_PROVISIONAL || dp->ind_state == IN_BORROWED) { dp->ind_state = IN_PERMANENT; i_log_devfs_instance_mod(); - e_ddi_inst_state.ins_dirty = 1; + e_ddi_inst_state.ins_dirty = B_TRUE; } mutex_exit(&e_ddi_inst_state.ins_serial); e_ddi_exit_instance(); @@ -840,6 +893,7 @@ in_removenode(struct devnames *dnp, in_node_t *mp, in_node_t *ap) in_node_t *np; ASSERT(e_ddi_inst_state.ins_busy); + /* * Assertion: parents are always instantiated by the framework * before their children, destroyed after them @@ -906,6 +960,7 @@ in_devwalk(dev_info_t *dip, in_node_t **ap, char *addr) } np = np->in_sibling; } + return (np); } @@ -930,7 +985,6 @@ in_pathin(char *cp, int instance, char *bname, struct bind **args) cmn_err(CE_WARN, "invalid instance file entry %s %d", cp, instance); - return (0); } @@ -939,11 +993,7 @@ in_pathin(char *cp, int instance, char *bname, struct bind **args) np = in_make_path(cp); ASSERT(np); - if (in_inuse(instance, bname)) { - cmn_err(CE_WARN, - "instance already in use: %s %d", cp, instance); - return (0); - } + dp = in_drvwalk(np, bname); if (dp != NULL) { cmn_err(CE_WARN, @@ -952,6 +1002,13 @@ in_pathin(char *cp, int instance, char *bname, struct bind **args) cp, bname, dp->ind_instance); return (0); } + + if (in_inuse(instance, bname)) { + cmn_err(CE_WARN, + "instance already in use: %s %d", cp, instance); + return (0); + } + dp = in_alloc_drv(bname); in_endrv(np, dp); dp->ind_instance = instance; @@ -975,8 +1032,10 @@ in_make_path(char *path) char *cp, *name, *addr; ASSERT(e_ddi_inst_state.ins_busy); + if (path == NULL || path[0] != '/') return (NULL); + (void) snprintf(buf, sizeof (buf), "%s", path); cp = buf + 1; /* skip over initial '/' in path */ name = in_name_addr(&cp, &addr); @@ -994,7 +1053,8 @@ in_make_path(char *path) name = in_name_addr(&cp, &addr); ap = e_ddi_inst_state.ins_root; - rp = np = e_ddi_inst_state.ins_root->in_child; + np = e_ddi_inst_state.ins_root->in_child; + rp = np; while (name) { while (name && np) { if (in_eqstr(name, np->in_node_name) && @@ -1004,7 +1064,6 @@ in_make_path(char *path) return (np); ap = np; np = np->in_child; - continue; } else { np = np->in_sibling; } @@ -1016,6 +1075,7 @@ in_make_path(char *path) np = NULL; /* can have no children */ name = in_name_addr(&cp, &addr); } + return (rp); } @@ -1378,7 +1438,7 @@ i_log_devfs_instance_mod(void) } void -e_ddi_enter_instance() +e_ddi_enter_instance(void) { mutex_enter(&e_ddi_inst_state.ins_serial); if (e_ddi_inst_state.ins_thread == curthread) @@ -1394,7 +1454,7 @@ e_ddi_enter_instance() } void -e_ddi_exit_instance() +e_ddi_exit_instance(void) { mutex_enter(&e_ddi_inst_state.ins_serial); e_ddi_inst_state.ins_busy--; @@ -1406,19 +1466,19 @@ e_ddi_exit_instance() } int -e_ddi_instance_is_clean() +e_ddi_instance_is_clean(void) { - return (e_ddi_inst_state.ins_dirty == 0); + return (e_ddi_inst_state.ins_dirty == B_FALSE); } void -e_ddi_instance_set_clean() +e_ddi_instance_set_clean(void) { - e_ddi_inst_state.ins_dirty = 0; + e_ddi_inst_state.ins_dirty = B_FALSE; } in_node_t * -e_ddi_instance_root() +e_ddi_instance_root(void) { return (e_ddi_inst_state.ins_root); } @@ -1450,6 +1510,7 @@ in_walk_instances(in_node_t *np, char *path, char *this, break; } } + if (np->in_child) { rval = in_walk_instances(np->in_child, path, next, f, arg); @@ -1480,8 +1541,82 @@ e_ddi_walk_instances(int (*f)(const char *, e_ddi_enter_instance(); root = e_ddi_instance_root(); rval = in_walk_instances(root->in_child, path, path, f, arg); + e_ddi_exit_instance(); kmem_free(path, MAXPATHLEN); return (rval); } + +in_node_t * +e_ddi_path_to_instance(char *path) +{ + in_node_t *np; + + np = in_make_path(path); + if (np && np->in_drivers && np->in_drivers->ind_state == IN_PERMANENT) { + return (np); + } + return (NULL); +} + +void +e_ddi_borrow_instance(dev_info_t *cdip, in_node_t *cnp) +{ + char *alias; + in_node_t *anp; + char *curr = kmem_alloc(MAXPATHLEN, KM_NOSLEEP); + + if (curr == NULL) { + ddi_err(DER_PANIC, cdip, "curr alloc failed"); + /*NOTREACHED*/ + } + + (void) ddi_pathname(cdip, curr); + + if (cnp->in_drivers) { + ddi_err(DER_PANIC, cdip, "cnp has instance: %p", cnp); + /*NOTREACHED*/ + } + + alias = ddi_curr_redirect(curr); + kmem_free(curr, MAXPATHLEN); + + if (alias && (anp = e_ddi_path_to_instance(alias)) != NULL) { + cnp->in_drivers = anp->in_drivers; + anp->in_drivers = NULL; + } +} + +void +e_ddi_return_instance(dev_info_t *cdip, char *addr, in_node_t *cnp) +{ + in_node_t *anp; + char *alias; + char *curr = kmem_alloc(MAXPATHLEN, KM_NOSLEEP); + + if (curr == NULL) { + ddi_err(DER_PANIC, cdip, "alloc of curr failed"); + /*NOTREACHED*/ + } + + (void) ddi_pathname(cdip, curr); + if (addr) { + (void) strlcat(curr, "@", MAXPATHLEN); + (void) strlcat(curr, addr, MAXPATHLEN); + + } + if (cnp->in_drivers == NULL) { + ddi_err(DER_PANIC, cdip, "cnp has no inst: %p", cnp); + /*NOTREACHED*/ + } + + alias = ddi_curr_redirect(curr); + kmem_free(curr, MAXPATHLEN); + + if (alias && (anp = e_ddi_path_to_instance(alias)) != NULL) { + ASSERT(anp->in_drivers == NULL); + anp->in_drivers = cnp->in_drivers; + cnp->in_drivers = NULL; + } +} diff --git a/usr/src/uts/common/sys/ddi_impldefs.h b/usr/src/uts/common/sys/ddi_impldefs.h index 4d6c501ad9..26ab5fd890 100644 --- a/usr/src/uts/common/sys/ddi_impldefs.h +++ b/usr/src/uts/common/sys/ddi_impldefs.h @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _SYS_DDI_IMPLDEFS_H @@ -123,6 +122,8 @@ typedef struct iommulib_unit *iommulib_handle_t; typedef uint8_t ndi_flavor_t; struct ddi_hp_cn_handle; +struct in_node; + struct dev_info { struct dev_info *devi_parent; /* my parent node in tree */ @@ -273,6 +274,8 @@ struct dev_info { /* Owned by hotplug framework */ struct ddi_hp_cn_handle *devi_hp_hdlp; /* hotplug handle list */ + + struct in_node *devi_in_node; /* pointer to devinfo node's in_node_t */ }; #define DEVI(dev_info_type) ((struct dev_info *)(dev_info_type)) diff --git a/usr/src/uts/common/sys/devinfo_impl.h b/usr/src/uts/common/sys/devinfo_impl.h index 411ec3f5e2..22ef3c3f2e 100644 --- a/usr/src/uts/common/sys/devinfo_impl.h +++ b/usr/src/uts/common/sys/devinfo_impl.h @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _SYS_DEVINFO_IMPL_H @@ -123,6 +122,7 @@ extern "C" { #define DI_LNODE(addr) ((struct di_lnode *)((void *)(addr))) #define DI_PRIV_FORMAT(addr) ((struct di_priv_format *)((void *)(addr))) #define DI_HP(addr) ((struct di_hp *)((void *)(addr))) +#define DI_ALIAS(addr) ((struct di_alias *)((void *)(addr))) /* * multipath component definitions: Follows the registered component of @@ -146,17 +146,19 @@ struct di_all { int generation; /* reserved for future use */ uint32_t cache_checksum; /* snapshot checksum */ uint64_t snapshot_time; /* snapshot timestamp */ - di_off_t top_devinfo; + di_off_t top_devinfo; /* actual top devinfo in snapshot */ di_off_t top_vhci_devinfo; di_off_t devnames; di_off_t ppdata_format; /* parent priv data format array */ di_off_t dpdata_format; /* driver priv data format array */ + di_off_t aliases; /* offset to alias tree */ int n_ppdata; /* size of ppdata_format array */ int n_dpdata; /* size of pddata_format array */ int devcnt; /* size of devnames array */ uint_t command; /* same as in di_init() */ uint_t map_size; /* size of the snapshot */ - char root_path[1]; /* path to snapshot root */ + char req_path[MAXPATHLEN]; /* path to requested root */ + char root_path[1]; /* path to actual snapshot root */ }; struct di_devnm { @@ -410,6 +412,17 @@ struct di_priv_data { struct di_priv_format *driver; }; + +/* + * structure for saving alias information + */ +struct di_alias { + di_off_t self; /* make it self addressable */ + di_off_t curroff; /* offset to curr dip's snapshot */ + di_off_t next; /* next alias */ + char alias[1]; /* alias path */ +}; + /* * structure passed in from ioctl */ diff --git a/usr/src/uts/common/sys/instance.h b/usr/src/uts/common/sys/instance.h index 04fe54770d..4e57a9974f 100644 --- a/usr/src/uts/common/sys/instance.h +++ b/usr/src/uts/common/sys/instance.h @@ -19,15 +19,12 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _SYS_INSTANCE_H #define _SYS_INSTANCE_H -#pragma ident "%Z%%M% %I% %E% SMI" - /* * Instance number assignment data structures */ @@ -35,6 +32,7 @@ #include <sys/types.h> #include <sys/param.h> #include <sys/dditypes.h> +#include <sys/list.h> #ifdef __cplusplus extern "C" { @@ -43,6 +41,7 @@ extern "C" { #define INSTANCE_FILE "/etc/path_to_inst" #define INSTANCE_FILE_SUFFIX ".old" + #if defined(_KERNEL) || defined(_KMEMUSER) /* @@ -60,9 +59,10 @@ typedef struct in_node { char *in_node_name; /* devi_node_name of this node */ char *in_unit_addr; /* address part of name */ struct in_node *in_child; /* children of this node */ - struct in_node *in_sibling; /* "peers" of this node */ + struct in_node *in_sibling; /* "peers" of this node */ struct in_drv *in_drivers; /* drivers bound to this node */ struct in_node *in_parent; /* parent of this node */ + dev_info_t *in_devi; /* corresponding devinfo */ } in_node_t; typedef struct in_drv { @@ -84,6 +84,14 @@ typedef struct in_drv { #define IN_PROVISIONAL 0x1 /* provisional instance number assigned */ #define IN_PERMANENT 0x2 /* instance number has been confirmed */ #define IN_UNKNOWN 0x3 /* instance number not yet assigned */ +#define IN_BORROWED 0x4 /* instance number from alias */ + + +/* + * Guard for path to instance file + */ +#define PTI_GUARD "#\n#\tCaution! This file contains critical kernel state\n#\n" + /* * special value for dn_instance @@ -113,7 +121,12 @@ int impl_free_instance(dev_info_t *dip); /* walk the instance tree */ int e_ddi_walk_instances(int (*)(const char *, - in_node_t *, in_drv_t *, void *), void *); + in_node_t *, in_drv_t *, void *), void *); + +/* for DDI-MP */ +in_node_t *e_ddi_path_to_instance(char *path); +void e_ddi_borrow_instance(dev_info_t *cdip, in_node_t *cnp); +void e_ddi_return_instance(dev_info_t *cdip, char *addr, in_node_t *cnp); /* return values from e_ddi_walk_instances callback */ #define INST_WALK_CONTINUE 0 diff --git a/usr/src/uts/common/sys/sunddi.h b/usr/src/uts/common/sys/sunddi.h index fe997d9faf..bfd9cda568 100644 --- a/usr/src/uts/common/sys/sunddi.h +++ b/usr/src/uts/common/sys/sunddi.h @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _SYS_SUNDDI_H @@ -398,10 +397,13 @@ typedef enum { #define DDI_MODEL_NATIVE DATAMODEL_NATIVE #define DDI_MODEL_NONE DATAMODEL_NONE +/* if set to B_TRUE is DER_MODE is equivalent to DERE_PANIC */ +extern boolean_t ddi_err_panic; + /* * Defines for ddi_err(). */ -typedef enum ddi_err { +typedef enum { DER_INVALID = 0, /* must be 0 */ DER_CONT = 1, DER_CONS, @@ -414,10 +416,9 @@ typedef enum ddi_err { DER_DEBUG } ddi_err_t; -/* if set to B_TRUE is DER_MODE is equivalent to DERE_PANIC */ -extern boolean_t ddi_err_panic; extern void ddi_err(ddi_err_t de, dev_info_t *rdip, const char *fmt, ...); + extern char *ddi_strdup(const char *str, int flag); extern char *strdup(const char *str); extern void strfree(char *str); @@ -2248,6 +2249,34 @@ int ddi_cb_unregister(ddi_cb_handle_t hdl); /* Notify DDI of memory added */ void ddi_mem_update(uint64_t addr, uint64_t size); +/* Path alias interfaces */ +typedef struct plat_alias { + char *pali_current; + uint64_t pali_naliases; + char **pali_aliases; +} plat_alias_t; + +typedef struct alias_pair { + char *pair_alias; + char *pair_curr; +} alias_pair_t; + +extern boolean_t ddi_aliases_present; + +typedef struct ddi_alias { + alias_pair_t *dali_alias_pairs; + alias_pair_t *dali_curr_pairs; + int dali_num_pairs; + mod_hash_t *dali_alias_TLB; + mod_hash_t *dali_curr_TLB; +} ddi_alias_t; + +extern ddi_alias_t ddi_aliases; + +void ddi_register_aliases(plat_alias_t *pali, uint64_t npali); +dev_info_t *ddi_alias_redirect(char *alias); +char *ddi_curr_redirect(char *curr); + #endif /* _KERNEL */ #ifdef __cplusplus diff --git a/usr/src/uts/sun4v/os/fillsysinfo.c b/usr/src/uts/sun4v/os/fillsysinfo.c index 3157345818..630bdcd607 100644 --- a/usr/src/uts/sun4v/os/fillsysinfo.c +++ b/usr/src/uts/sun4v/os/fillsysinfo.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <sys/errno.h> @@ -50,6 +49,7 @@ #include <sys/mmu.h> #include <sys/bitmap.h> #include <sys/intreg.h> +#include <sys/instance.h> struct cpu_node cpunodes[NCPU]; @@ -1051,6 +1051,144 @@ init_md_broken(md_t *mdp, mde_cookie_t *cpulist) md_free_scan_dag(mdp, &platlist); } +#define PLAT_MAX_IOALIASES 8 + +static plat_alias_t *plat_ioaliases; +static uint64_t plat_num_ioaliases; + +/* + * split the aliases property into its + * component strings for easy searching. + */ +static void +split_alias(plat_alias_t *pali, char *str) +{ + char *aliasv[PLAT_MAX_IOALIASES], *p; + int i, duplen; + char *dup; + + /* skip leading space */ + str = dup = strdup(str); + duplen = strlen(dup) + 1; + str += strspn(str, " "); + for (i = 0; *str != '\0'; str = p) { + + p = strpbrk(str, " "); + if (p != NULL) { + *p++ = '\0'; + } + + VERIFY(i < PLAT_MAX_IOALIASES); + aliasv[i++] = strdup(str); + if (p == NULL) + break; + p += strspn(p, " "); + } + + kmem_free(dup, duplen); + + if (i == 0) { + pali->pali_naliases = 0; + pali->pali_aliases = NULL; + return; + } + + pali->pali_naliases = i; + pali->pali_aliases = kmem_alloc(i * sizeof (char *), KM_SLEEP); + for (i = 0; i < pali->pali_naliases; i++) { + pali->pali_aliases[i] = aliasv[i]; + } +} + +/* + * retrieve the ioalias info from the MD, + * and init the ioalias struct. + * + * NOTE: Assumes that the ioalias info does not change at runtime + * This routine is invoked only once at boot time. + * + * No lock needed as this is called at boot with a DDI lock held + */ +void +plat_ioaliases_init(void) +{ + md_t *mdp; + mde_cookie_t *ionodes, alinode; + plat_alias_t *pali; + int nio; + int i; + int err; + + mdp = md_get_handle(); + if (mdp == NULL) { + cmn_err(CE_PANIC, "no machine description (MD)"); + /*NOTREACHED*/ + } + + nio = md_alloc_scan_dag(mdp, md_root_node(mdp), + "ioaliases", "fwd", &ionodes); + + + /* not all platforms support aliases */ + if (nio < 1) { + (void) md_fini_handle(mdp); + return; + } + if (nio > 1) { + cmn_err(CE_PANIC, "multiple ioalias nodes in MD"); + /*NOTREACHED*/ + } + + alinode = ionodes[0]; + md_free_scan_dag(mdp, &ionodes); + + nio = md_alloc_scan_dag(mdp, alinode, "ioalias", "fwd", &ionodes); + if (nio <= 0) { + cmn_err(CE_PANIC, "MD alias node has no aliases"); + /*NOTREACHED*/ + } + + plat_num_ioaliases = nio; + plat_ioaliases = pali = kmem_zalloc(nio * sizeof (plat_alias_t), + KM_SLEEP); + + /* + * Each ioalias map will have a composite property of + * aliases and the current valid path. + */ + for (i = 0; i < nio; i++) { + char *str; + + err = md_get_prop_str(mdp, ionodes[i], "current", &str); + if (err != 0) { + cmn_err(CE_PANIC, "malformed ioalias node"); + /*NOTREACHED*/ + } + pali->pali_current = strdup(str); + + err = md_get_prop_str(mdp, ionodes[i], "aliases", &str); + if (err != 0) { + cmn_err(CE_PANIC, "malformed aliases"); + /*NOTREACHED*/ + } + split_alias(pali, str); + pali++; + } + + md_free_scan_dag(mdp, &ionodes); + + /* + * Register the io-aliases array with the DDI framework + * The DDI framework assumes that this array and its contents + * will not change post-register. The DDI framework will + * cache this array and is free to access this array at + * any time without any locks. + */ + ddi_register_aliases(plat_ioaliases, plat_num_ioaliases); + + (void) md_fini_handle(mdp); +} + /* * Number of bits forming a valid context for use in a sun4v TTE and the MMU * context registers. Sun4v defines the minimum default value to be 13 if this |