summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr/src/cmd/devfsadm/audio_link.c29
-rw-r--r--usr/src/cmd/devfsadm/devfsadm.c133
-rw-r--r--usr/src/cmd/devfsadm/devfsadm.h7
-rw-r--r--usr/src/cmd/devfsadm/port_link.c13
-rw-r--r--usr/src/lib/libdevinfo/devinfo.c92
-rw-r--r--usr/src/lib/libdevinfo/libdevinfo.h7
-rw-r--r--usr/src/lib/libdevinfo/mapfile-vers4
-rw-r--r--usr/src/uts/common/fs/devfs/devfs_subr.c20
-rw-r--r--usr/src/uts/common/io/devinfo.c67
-rw-r--r--usr/src/uts/common/os/devcfg.c451
-rw-r--r--usr/src/uts/common/os/inst_sync.c14
-rw-r--r--usr/src/uts/common/os/instance.c195
-rw-r--r--usr/src/uts/common/sys/ddi_impldefs.h7
-rw-r--r--usr/src/uts/common/sys/devinfo_impl.h21
-rw-r--r--usr/src/uts/common/sys/instance.h25
-rw-r--r--usr/src/uts/common/sys/sunddi.h39
-rw-r--r--usr/src/uts/sun4v/os/fillsysinfo.c142
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