summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcth <none@none>2007-05-01 05:33:55 -0700
committercth <none@none>2007-05-01 05:33:55 -0700
commitf4da9be01648d6afa604495d9b9956dddeb92a8c (patch)
treee3730f62fe03f317264d5c836fe4e6710acc729f
parent75c7619736838143dd41b3c5c9d7adec4683488f (diff)
downloadillumos-joyent-f4da9be01648d6afa604495d9b9956dddeb92a8c.tar.gz
PSARC 2007/176 path-oriented driver alias
6536151 path-oriented driver alias
-rw-r--r--usr/src/cmd/mdb/common/modules/genunix/devinfo.c36
-rw-r--r--usr/src/cmd/mdb/common/modules/mdb_ks/mdb_ks.c7
-rw-r--r--usr/src/cmd/mdb/i86pc/modules/uppc/uppc.c2
-rw-r--r--usr/src/cmd/modload/add_drv.c15
-rw-r--r--usr/src/cmd/modload/addrem.h12
-rw-r--r--usr/src/cmd/modload/drvsubr.c117
-rw-r--r--usr/src/cmd/modload/errmsg.h9
-rw-r--r--usr/src/cmd/modload/rem_drv.c9
-rw-r--r--usr/src/cmd/modload/update_drv.c20
-rw-r--r--usr/src/uts/common/os/autoconf.c9
-rw-r--r--usr/src/uts/common/os/devcfg.c341
-rw-r--r--usr/src/uts/common/os/modsysfile.c4
-rw-r--r--usr/src/uts/common/os/sunddi.c16
-rw-r--r--usr/src/uts/common/os/swapgeneric.c84
-rw-r--r--usr/src/uts/common/sys/ddi_impldefs.h10
-rw-r--r--usr/src/uts/common/sys/ndi_impldefs.h13
16 files changed, 546 insertions, 158 deletions
diff --git a/usr/src/cmd/mdb/common/modules/genunix/devinfo.c b/usr/src/cmd/mdb/common/modules/genunix/devinfo.c
index adab304cdb..296fa0c414 100644
--- a/usr/src/cmd/mdb/common/modules/genunix/devinfo.c
+++ b/usr/src/cmd/mdb/common/modules/genunix/devinfo.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -1072,7 +1072,7 @@ devinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
char tmpstr[MODMAXNAMELEN];
char nodename[MODMAXNAMELEN];
- char bindname[MODMAXNAMELEN];
+ char bindname[MAXPATHLEN];
int size, length;
struct dev_info devi;
devinfo_node_t din;
@@ -1082,6 +1082,7 @@ devinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{ "DEVICE_OFFLINE", DEVI_DEVICE_OFFLINE, DEVI_DEVICE_OFFLINE },
{ "DEVICE_DOWN", DEVI_DEVICE_DOWN, DEVI_DEVICE_DOWN },
{ "DEVICE_DEGRADED", DEVI_DEVICE_DEGRADED, DEVI_DEVICE_DEGRADED },
+ { "DEVICE_REMOVED", DEVI_DEVICE_REMOVED, DEVI_DEVICE_REMOVED },
{ "BUS_QUIESCED", DEVI_BUS_QUIESCED, DEVI_BUS_QUIESCED },
{ "BUS_DOWN", DEVI_BUS_DOWN, DEVI_BUS_DOWN },
{ "NDI_CONFIG", DEVI_NDI_CONFIG, DEVI_NDI_CONFIG },
@@ -1096,6 +1097,7 @@ devinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{ "S_REPORT", DEVI_S_REPORT, DEVI_S_REPORT },
{ "S_EVADD", DEVI_S_EVADD, DEVI_S_EVADD },
{ "S_EVREMOVE", DEVI_S_EVREMOVE, DEVI_S_EVREMOVE },
+ { "S_NEED_RESET", DEVI_S_NEED_RESET, DEVI_S_NEED_RESET },
{ NULL, 0, 0 }
};
@@ -1105,6 +1107,13 @@ devinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{ "ATTACHED_CHILDREN",
DEVI_ATTACHED_CHILDREN, DEVI_ATTACHED_CHILDREN},
{ "BRANCH_HELD", DEVI_BRANCH_HELD, DEVI_BRANCH_HELD },
+ { "NO_BIND", DEVI_NO_BIND, DEVI_NO_BIND },
+ { "DEVI_REGISTERED_DEVID",
+ DEVI_REGISTERED_DEVID, DEVI_REGISTERED_DEVID },
+ { "PHCI_SIGNALS_VHCI",
+ DEVI_PHCI_SIGNALS_VHCI,
+ DEVI_PHCI_SIGNALS_VHCI },
+ { "REBIND", DEVI_REBIND, DEVI_REBIND },
{ NULL, 0, 0 }
};
@@ -1716,9 +1725,8 @@ binding_hash_entry(uintptr_t addr, uint_t flags, int argc,
{
struct bind bind;
/* Arbitrary lengths based on output format below */
- char name[25] = "???";
- char bind_name[32] = "<null>";
-
+ char name[MAXPATHLEN] = "???";
+ char bind_name[MAXPATHLEN] = "<null>";
if ((flags & DCMD_ADDRSPEC) == NULL)
return (DCMD_USAGE);
@@ -1733,18 +1741,22 @@ binding_hash_entry(uintptr_t addr, uint_t flags, int argc,
}
if (DCMD_HDRSPEC(flags)) {
- mdb_printf("%<u>%-32s %-5s %-?s%</u>\n",
- "NAME", "MAJOR", "NEXT");
+ mdb_printf("%<u>%?s% %-5s %s%</u>\n",
+ "NEXT", "MAJOR", "NAME(S)");
}
if (mdb_readstr(name, sizeof (name), (uintptr_t)bind.b_name) == -1)
mdb_warn("failed to read 'name'");
- /* There may be no binding name for a driver, so this may fail */
- (void) mdb_readstr(bind_name, sizeof (bind_name),
- (uintptr_t)bind.b_bind_name);
-
- mdb_printf("%-32s %3d %?p\n", name, bind.b_num, bind.b_next);
+ /* There may be bind_name, so this may fail */
+ if (mdb_readstr(bind_name, sizeof (bind_name),
+ (uintptr_t)bind.b_bind_name) == -1) {
+ mdb_printf("%?p %5d %s\n",
+ bind.b_next, bind.b_num, name);
+ } else {
+ mdb_printf("%?p %5d %s %s\n",
+ bind.b_next, bind.b_num, name, bind_name);
+ }
return (DCMD_OK);
}
diff --git a/usr/src/cmd/mdb/common/modules/mdb_ks/mdb_ks.c b/usr/src/cmd/mdb/common/modules/mdb_ks/mdb_ks.c
index 869c58c6e0..3d7537a1d6 100644
--- a/usr/src/cmd/mdb/common/modules/mdb_ks/mdb_ks.c
+++ b/usr/src/cmd/mdb/common/modules/mdb_ks/mdb_ks.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -863,8 +863,7 @@ find_mbind(const char *name, uintptr_t *hashtab)
int hashndx;
uintptr_t mb;
struct bind mb_local;
- char node_name[MODMAXNAMELEN + 1];
-
+ char node_name[MAXPATHLEN + 1];
hashndx = nm_hash(name);
mb = hashtab[hashndx];
@@ -944,7 +943,7 @@ int
mdb_devinfo2driver(uintptr_t dip_addr, char *drivername, size_t namebufsize)
{
struct dev_info devinfo;
- char bind_name[MODMAXNAMELEN + 1];
+ char bind_name[MAXPATHLEN + 1];
major_t major;
const char *namestr;
diff --git a/usr/src/cmd/mdb/i86pc/modules/uppc/uppc.c b/usr/src/cmd/mdb/i86pc/modules/uppc/uppc.c
index fee48b58f5..0bd87f8a65 100644
--- a/usr/src/cmd/mdb/i86pc/modules/uppc/uppc.c
+++ b/usr/src/cmd/mdb/i86pc/modules/uppc/uppc.c
@@ -33,7 +33,7 @@ static uint16_t shared_tbl[MAX_ISA_IRQ + 1];
static char *
interrupt_print_bus(uintptr_t dip_addr)
{
- char bind_name[MODMAXNAMELEN + 1];
+ char bind_name[MAXPATHLEN + 1];
struct dev_info dev_info;
if (mdb_vread(&dev_info, sizeof (dev_info), dip_addr) == -1) {
diff --git a/usr/src/cmd/modload/add_drv.c b/usr/src/cmd/modload/add_drv.c
index d40eec2902..62da6d8796 100644
--- a/usr/src/cmd/modload/add_drv.c
+++ b/usr/src/cmd/modload/add_drv.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -525,7 +524,7 @@ update_driver_classes(
{
/* make call to update the classes file */
return (append_to_file(driver_name, classes, driver_classes,
- ' ', "\t"));
+ ' ', "\t", 0));
}
static int
@@ -533,7 +532,8 @@ update_minor_perm(
char *driver_name,
char *perm_list)
{
- return (append_to_file(driver_name, perm_list, minor_perm, ',', ":"));
+ return (append_to_file(driver_name, perm_list, minor_perm,
+ ',', ":", 0));
}
@@ -567,7 +567,8 @@ update_extra_privs(
char *driver_name,
char *privlist)
{
- return (append_to_file(driver_name, privlist, extra_privs, ',', ":"));
+ return (append_to_file(driver_name, privlist, extra_privs,
+ ',', ":", 0));
}
/*
diff --git a/usr/src/cmd/modload/addrem.h b/usr/src/cmd/modload/addrem.h
index e4b70bea10..c1763c760d 100644
--- a/usr/src/cmd/modload/addrem.h
+++ b/usr/src/cmd/modload/addrem.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -125,9 +124,9 @@ extern int check_name_to_major(int);
extern void enter_lock(void);
extern void err_exit(void);
extern void exit_unlock(void);
-extern char *get_entry(char *, char *, char);
+extern char *get_entry(char *, char *, char, int);
extern int build_filenames(char *);
-extern int append_to_file(char *, char *, char *, char, char *);
+extern int append_to_file(char *, char *, char *, char, char *, int);
extern int get_major_no(char *, char *);
extern int get_driver_name(int, char *, char *);
extern int delete_entry(char *, char *, char *, char *);
@@ -139,6 +138,7 @@ extern int update_name_to_major(char *, major_t *, int);
extern int do_the_update(char *, char *);
extern int fill_n2m_array(char *, char **, int *);
extern int aliases_unique(char *);
+extern int aliases_paths_exist(char *);
extern int update_driver_aliases(char *, char *);
extern int unique_driver_name(char *, char *, int *);
extern int unique_drv_alias(char *);
diff --git a/usr/src/cmd/modload/drvsubr.c b/usr/src/cmd/modload/drvsubr.c
index f1fb38add3..37daeaf6f7 100644
--- a/usr/src/cmd/modload/drvsubr.c
+++ b/usr/src/cmd/modload/drvsubr.c
@@ -106,7 +106,8 @@ append_to_file(
char *entry_list,
char *filename,
char list_separator,
- char *entry_separator)
+ char *entry_separator,
+ int quoted)
{
int i, len;
int fpint;
@@ -153,12 +154,16 @@ append_to_file(
line[i] = 0;
current_head = get_entry(previous_head, one_entry,
- list_separator);
+ list_separator, quoted);
previous_head = current_head;
(void) strcpy(line, driver_name);
(void) strcat(line, entry_separator);
+ if (quoted)
+ (void) strcat(line, "\"");
(void) strcat(line, one_entry);
+ if (quoted)
+ (void) strcat(line, "\"");
(void) strcat(line, "\n");
if ((fputs(line, fp)) == EOF) {
@@ -615,16 +620,20 @@ get_name_to_major_entry(int *major_no, char *driver_name, char *file_name)
}
/*
- * given pointer to member n in space separated list, return pointer
- * to member n+1, return member n
+ * Given pointer to begining of member 'n' in a space (or separator)
+ * separated list, return pointer to member 'n+1', and establish member 'n'
+ * in *current_entry. If unquote, then we skip a leading quote and treat
+ * the trailing quote as a separator (and skip).
*/
char *
get_entry(
char *prev_member,
char *current_entry,
- char separator)
+ char separator,
+ int unquote)
{
- char *ptr;
+ char *ptr;
+ int quoted = 0;
ptr = prev_member;
@@ -632,14 +641,25 @@ get_entry(
while (*ptr == '\t' || *ptr == ' ')
ptr++;
- /* read thru the current entry */
- while (*ptr != separator && *ptr != '\0') {
+ /* if unquote skip leading quote */
+ if (unquote && *ptr == '"') {
+ quoted++;
+ ptr++;
+ }
+
+ /* read thru the current entry looking for end, separator, or unquote */
+ while (*ptr &&
+ (*ptr != separator) &&
+ ((separator != ' ') || (*ptr != '\t')) &&
+ (!quoted || (*ptr != '"'))) {
*current_entry++ = *ptr++;
}
*current_entry = '\0';
- if ((separator == ',') && (*ptr == separator))
- ptr++; /* skip over comma */
+ if (separator && (*ptr == separator))
+ ptr++; /* skip over separator */
+ if (quoted && (*ptr == '"'))
+ ptr++; /* skip over trailing quote */
/* skip white space */
while (*ptr == '\t' || *ptr == ' ') {
@@ -1003,7 +1023,7 @@ config_driver(
return (ERROR);
}
current = get_entry(previous,
- cmdline[n++], ' ');
+ cmdline[n++], ' ', 0);
previous = current;
} while (*current != '\0');
@@ -1395,7 +1415,7 @@ check_perm_opts(char *perm_list)
for (i = 0; i <= len; i++)
one_entry[i] = 0;
- current_head = get_entry(previous_head, one_entry, ',');
+ current_head = get_entry(previous_head, one_entry, ',', 0);
previous_head = current_head;
scan_stat = sscanf(one_entry, "%s%s%s%s%s", minor, perm, own,
@@ -1453,7 +1473,7 @@ aliases_unique(char *aliases)
for (i = 0; i <= len; i++)
one_entry[i] = 0;
- current_head = get_entry(previous_head, one_entry, ' ');
+ current_head = get_entry(previous_head, one_entry, ' ', 1);
previous_head = current_head;
if ((unique_driver_name(one_entry, name_to_major,
@@ -1490,14 +1510,66 @@ aliases_unique(char *aliases)
}
+/*
+ * check each alias :
+ * if path-oriented alias, path exists
+ */
+int
+aliases_paths_exist(char *aliases)
+{
+ char *current_head;
+ char *previous_head;
+ char *one_entry;
+ int i, len;
+ char path[MAXPATHLEN];
+ struct stat buf;
+
+ len = strlen(aliases);
+
+ one_entry = calloc(len + 1, 1);
+ if (one_entry == NULL) {
+ (void) fprintf(stderr, gettext(ERR_NO_MEM));
+ return (ERROR);
+ }
+
+ previous_head = aliases;
+
+ do {
+ for (i = 0; i <= len; i++)
+ one_entry[i] = 0;
+
+ current_head = get_entry(previous_head, one_entry, ' ', 1);
+ previous_head = current_head;
+
+ /* if the alias is a path, ensure that the path exists */
+ if (*one_entry != '/')
+ continue;
+ (void) snprintf(path, sizeof (path), "/devices/%s", one_entry);
+ if (stat(path, &buf) == 0)
+ continue;
+
+ /* no device at specified path-oriented alias path */
+ (void) fprintf(stderr, gettext(ERR_PATH_ORIENTED_ALIAS),
+ one_entry);
+ free(one_entry);
+ return (ERROR);
+
+ } while (*current_head != '\0');
+
+ free(one_entry);
+
+ return (NOERR);
+}
+
+
int
update_driver_aliases(
char *driver_name,
char *aliases)
{
/* make call to update the aliases file */
- return (append_to_file(driver_name, aliases, driver_aliases, ' ', " "));
-
+ return (append_to_file(driver_name, aliases, driver_aliases,
+ ' ', " ", 1));
}
@@ -1508,6 +1580,7 @@ unique_drv_alias(char *drv_alias)
char drv[FILENAME_MAX + 1];
char line[MAX_N2M_ALIAS_LINE + 1], *cp;
char alias[FILENAME_MAX + 1];
+ char *a;
int status = NOERR;
fp = fopen(driver_aliases, "r");
@@ -1526,8 +1599,16 @@ unique_drv_alias(char *drv_alias)
(void) fprintf(stderr, gettext(ERR_BAD_LINE),
driver_aliases, line);
+ /* unquote for compare */
+ if ((*alias == '"') &&
+ (*(alias + strlen(alias) - 1) == '"')) {
+ a = &alias[1];
+ alias[strlen(alias) - 1] = '\0';
+ } else
+ a = alias;
+
if ((strcmp(drv_alias, drv) == 0) ||
- (strcmp(drv_alias, alias) == 0)) {
+ (strcmp(drv_alias, a) == 0)) {
(void) fprintf(stderr,
gettext(ERR_ALIAS_IN_USE),
drv_alias);
@@ -1656,7 +1737,7 @@ update_name_to_major(char *driver_name, major_t *major_num, int server)
"%d", is_unique);
if (append_to_file(driver_name, major,
- name_to_major, ' ', " ") == ERROR) {
+ name_to_major, ' ', " ", 0) == ERROR) {
(void) fprintf(stderr,
gettext(ERR_NO_UPDATE),
name_to_major);
@@ -1857,7 +1938,7 @@ int
do_the_update(char *driver_name, char *major_number)
{
return (append_to_file(driver_name, major_number, name_to_major,
- ' ', " "));
+ ' ', " ", 0));
}
/*
diff --git a/usr/src/cmd/modload/errmsg.h b/usr/src/cmd/modload/errmsg.h
index 6412f4d24b..a29f866cd9 100644
--- a/usr/src/cmd/modload/errmsg.h
+++ b/usr/src/cmd/modload/errmsg.h
@@ -56,8 +56,10 @@ extern "C" {
#define ERR_INSTALL_FAIL "Error: Could not install driver (%s).\n"
#define ERR_DRVNAME_TOO_LONG "Error: driver name must not exceed (%d)" \
" characters; driver name too long (%s)\n"
-#define ERR_ALIAS_IN_NAM_MAJ "Alias (%s) already in use as driver name.\n"
-#define ERR_ALIAS_IN_USE "(%s) already in use as a driver or alias.\n"
+#define ERR_ALIAS_IN_NAM_MAJ \
+"Alias (\"%s\") already in use as driver name.\n"
+#define ERR_ALIAS_IN_USE \
+"(\"%s\") already in use as a driver or alias.\n"
#define ERR_CANT_ACCESS_FILE "Cannot access file (%s).\n"
#define ERR_BAD_PATH "Bad syntax for pathname : (%s)\n"
#define ERR_FORK_FAIL "Fork failed; cannot exec : %s\n"
@@ -171,6 +173,9 @@ Use octal escape sequence \"\\040\".\n"
#define ERR_REMDRV_CLEANUP \
"post-rem_drv devfs cleanup for driver %s failed (%d)\n"
+#define ERR_PATH_ORIENTED_ALIAS \
+ "no device at specified path-oriented alias \"%s\"\n"
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/cmd/modload/rem_drv.c b/usr/src/cmd/modload/rem_drv.c
index 189cc5e9d9..761c52b60c 100644
--- a/usr/src/cmd/modload/rem_drv.c
+++ b/usr/src/cmd/modload/rem_drv.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -169,7 +168,7 @@ main(int argc, char *argv[])
(void) sprintf(maj_num, "%d", found);
if (append_to_file(driver_name, maj_num,
- rem_name_to_major, ' ', " ") == ERROR) {
+ rem_name_to_major, ' ', " ", 0) == ERROR) {
(void) fprintf(stderr, gettext(ERR_NO_UPDATE),
rem_name_to_major);
err_exit();
diff --git a/usr/src/cmd/modload/update_drv.c b/usr/src/cmd/modload/update_drv.c
index 6b49f43a5f..8efbc6d7e9 100644
--- a/usr/src/cmd/modload/update_drv.c
+++ b/usr/src/cmd/modload/update_drv.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -270,7 +269,7 @@ main(int argc, char *argv[])
if (priv != NULL) {
(void) append_to_file(driver_name, priv, extra_privs,
- ',', ":");
+ ',', ":", 0);
cleanup_flag |= CLEAN_DRV_PRIV;
}
@@ -306,6 +305,17 @@ main(int argc, char *argv[])
return (error);
}
+ /*
+ * unless force_flag is specified check that
+ * path-oriented aliases we are adding exist
+ */
+ if ((force_flag == 0) &&
+ ((error = aliases_paths_exist(aliases)) == ERROR)) {
+ exit_unlock();
+
+ return (error);
+ }
+
/* update the file */
if ((error = update_driver_aliases(driver_name,
aliases)) == ERROR) {
diff --git a/usr/src/uts/common/os/autoconf.c b/usr/src/uts/common/os/autoconf.c
index 95c236cff6..2adffdd7b0 100644
--- a/usr/src/uts/common/os/autoconf.c
+++ b/usr/src/uts/common/os/autoconf.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -403,8 +402,6 @@ create_devinfo_tree(void)
void
i_ddi_init_root()
{
- extern int i_ndi_make_spec_children(dev_info_t *, uint_t);
-
#ifdef DDI_PROP_DEBUG
(void) ddi_prop_debug(1); /* Enable property debugging */
#endif /* DDI_PROP_DEBUG */
diff --git a/usr/src/uts/common/os/devcfg.c b/usr/src/uts/common/os/devcfg.c
index 9a2b6b745f..5e8eeca828 100644
--- a/usr/src/uts/common/os/devcfg.c
+++ b/usr/src/uts/common/os/devcfg.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -144,6 +144,9 @@ int di_cache_debug = 0;
/* For ddvis, which needs pseudo children under PCI */
int pci_allow_pseudo_children = 0;
+/* Allow path-oriented alias driver binding on driver.conf enumerated nodes */
+int driver_conf_allow_path_alias = 1;
+
/*
* The following switch is for service people, in case a
* 3rd party driver depends on identify(9e) being called.
@@ -187,6 +190,7 @@ ndi_devi_config_obp_args(dev_info_t *parent, char *devnm,
static void i_link_vhci_node(dev_info_t *);
static void ndi_devi_exit_and_wait(dev_info_t *dip,
int circular, clock_t end_time);
+static int ndi_devi_unbind_driver(dev_info_t *dip);
/*
* dev_info cache and node management
@@ -233,9 +237,10 @@ i_ddi_alloc_node(dev_info_t *pdip, char *node_name, pnode_t nodeid,
if ((devi->devi_node_name = i_ddi_strdup(node_name, flag)) == NULL)
goto fail;
+
/* default binding name is node name */
devi->devi_binding_name = devi->devi_node_name;
- devi->devi_major = (major_t)-1; /* unbound by default */
+ devi->devi_major = (major_t)-1; /* unbound by default */
/*
* Make a copy of system property
@@ -369,6 +374,9 @@ i_ddi_free_node(dev_info_t *dip)
if (DEVI(dip)->devi_compat_names)
kmem_free(DEVI(dip)->devi_compat_names,
DEVI(dip)->devi_compat_length);
+ if (DEVI(dip)->devi_rebinding_name)
+ kmem_free(DEVI(dip)->devi_rebinding_name,
+ strlen(DEVI(dip)->devi_rebinding_name) + 1);
ddi_prop_remove_all(dip); /* remove driver properties */
if (devi->devi_sys_prop_ptr)
@@ -573,13 +581,13 @@ link_node(dev_info_t *dip)
* Extending the workaround to IB Nexus/VHCI
* driver also.
*/
- if (strcmp(devi->devi_name, "scsi_vhci") == 0) {
+ if (strcmp(devi->devi_binding_name, "scsi_vhci") == 0) {
/* Add scsi_vhci to beginning of list */
ASSERT((dev_info_t *)parent == top_devinfo);
/* scsi_vhci under rootnex */
devi->devi_sibling = parent->devi_child;
parent->devi_child = devi;
- } else if (strcmp(devi->devi_name, "ib") == 0) {
+ } else if (strcmp(devi->devi_binding_name, "ib") == 0) {
i_link_vhci_node(dip);
} else {
/* Add to end of list */
@@ -732,7 +740,9 @@ unbind_node(dev_info_t *dip)
(void *)dip, ddi_node_name(dip)));
unlink_from_driver_list(dip);
+
DEVI(dip)->devi_major = (major_t)-1;
+ DEVI(dip)->devi_binding_name = DEVI(dip)->devi_node_name;
return (DDI_SUCCESS);
}
@@ -749,6 +759,7 @@ init_node(dev_info_t *dip)
dev_info_t *pdip = ddi_get_parent(dip);
int (*f)(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *);
char *path;
+ major_t major;
ASSERT(i_ddi_node_state(dip) == DS_BOUND);
@@ -789,14 +800,14 @@ init_node(dev_info_t *dip)
ndi_hold_devi(pdip);
- /* check for duplicate nodes */
- if (find_duplicate_child(pdip, dip) != NULL) {
- /* recompute path after initchild for @addr information */
- (void) ddi_pathname(dip, path);
+ /* recompute path after initchild for @addr information */
+ (void) ddi_pathname(dip, path);
+ /* Check for duplicate nodes */
+ if (find_duplicate_child(pdip, dip) != NULL) {
/*
* uninit_node() the duplicate - a successful uninit_node()
- * does a ndi_rele_devi
+ * does a ndi_rele_devi.
*/
if ((error = uninit_node(dip)) != DDI_SUCCESS) {
ndi_rele_devi(pdip);
@@ -811,13 +822,100 @@ init_node(dev_info_t *dip)
}
/*
+ * Check to see if we have a path-oriented driver alias that overrides
+ * the current driver binding. If so, we need to rebind. This check
+ * needs to be delayed until after a successful DDI_CTLOPS_INITCHILD,
+ * so the unit-address is established on the last component of the path.
+ *
+ * NOTE: Allowing a path-oriented alias to change the driver binding
+ * of a driver.conf node results in non-intuitive property behavior.
+ * We provide a tunable (driver_conf_allow_path_alias) to control
+ * this behavior. See uninit_node() for more details.
+ *
+ * NOTE: If you are adding a path-oriented alias for the boot device,
+ * and there is mismatch between OBP and the kernel in regard to
+ * generic name use, like "disk" .vs. "ssd", then you will need
+ * to add a path-oriented alias for both paths.
+ */
+ major = ddi_name_to_major(path);
+ if ((major != (major_t)-1) &&
+ !(devnamesp[major].dn_flags & DN_DRIVER_REMOVED) &&
+ (major != DEVI(dip)->devi_major) &&
+ (ndi_dev_is_persistent_node(dip) || driver_conf_allow_path_alias)) {
+
+ /* Mark node for rebind processing. */
+ mutex_enter(&DEVI(dip)->devi_lock);
+ DEVI(dip)->devi_flags |= DEVI_REBIND;
+ mutex_exit(&DEVI(dip)->devi_lock);
+
+ /*
+ * uninit_node() current binding - a successful uninit_node()
+ * does a ndi_rele_devi.
+ */
+ if ((error = uninit_node(dip)) != DDI_SUCCESS) {
+ ndi_rele_devi(pdip);
+ cmn_err(CE_WARN, "init_node: uninit for rebind "
+ "of node %s failed", path);
+ goto out;
+ }
+
+ /* Unbind: demote the node back to DS_LINKED. */
+ if ((error = ndi_devi_unbind_driver(dip)) != DDI_SUCCESS) {
+ cmn_err(CE_WARN, "init_node: unbind for rebind "
+ "of node %s failed", path);
+ goto out;
+ }
+
+ /* establish rebinding name */
+ if (DEVI(dip)->devi_rebinding_name == NULL)
+ DEVI(dip)->devi_rebinding_name =
+ i_ddi_strdup(path, KM_SLEEP);
+
+ /*
+ * Now that we are demoted and marked for rebind, repromote.
+ * We need to do this in steps, instead of just calling
+ * ddi_initchild, so that we can redo the merge operation
+ * after we are rebound to the path-bound driver.
+ *
+ * Start by rebinding node to the path-bound driver.
+ */
+ if ((error = ndi_devi_bind_driver(dip, 0)) != DDI_SUCCESS) {
+ cmn_err(CE_WARN, "init_node: rebind "
+ "of node %s failed", path);
+ goto out;
+ }
+
+ /*
+ * If the node is not a driver.conf node then merge
+ * driver.conf properties from new path-bound driver.conf.
+ */
+ if (ndi_dev_is_persistent_node(dip))
+ (void) i_ndi_make_spec_children(pdip, 0);
+
+ /*
+ * Now that we have taken care of merge, repromote back
+ * to DS_INITIALIZED.
+ */
+ error = ddi_initchild(pdip, dip);
+ NDI_CONFIG_DEBUG((CE_CONT, "init_node: rebind "
+ "%s 0x%p\n", path, (void *)dip));
+ goto out;
+ }
+
+ /*
* Apply multi-parent/deep-nexus optimization to the new node
*/
DEVI(dip)->devi_instance = e_ddi_assign_instance(dip);
ddi_optimize_dtree(dip);
error = DDI_SUCCESS;
-out: kmem_free(path, MAXPATHLEN);
+out: if (error != DDI_SUCCESS) {
+ /* On failure ensure that DEVI_REBIND is cleared */
+ mutex_enter(&DEVI(dip)->devi_lock);
+ DEVI(dip)->devi_flags &= ~DEVI_REBIND;
+ mutex_exit(&DEVI(dip)->devi_lock);
+ }
+ kmem_free(path, MAXPATHLEN);
return (error);
}
@@ -888,7 +986,33 @@ uninit_node(dev_info_t *dip)
ndi_rele_devi(pdip);
remove_global_props(dip);
- e_ddi_prop_remove_all(dip);
+
+ /*
+ * NOTE: The decision on whether to allow a path-oriented
+ * rebind of a driver.conf enumerated node is made by
+ * init_node() based on driver_conf_allow_path_alias. The
+ * rebind code below prevents deletion of system properties
+ * on driver.conf nodes.
+ *
+ * When driver_conf_allow_path_alias is set, property behavior
+ * on rebound driver.conf file is non-intuitive. For a
+ * driver.conf node, the unit-address properties come from
+ * the driver.conf file as system properties. Removing system
+ * properties from a driver.conf node makes the node
+ * useless (we get node without unit-address properties) - so
+ * we leave system properties in place. The result is a node
+ * where system properties come from the node being rebound,
+ * and global properties come from the driver.conf file
+ * of the driver we are rebinding to. If we could determine
+ * that the path-oriented alias driver.conf file defined a
+ * node at the same unit address, it would be best to use
+ * that node and avoid the non-intuitive property behavior.
+ * Unfortunately, the current "merge" code does not support
+ * this, so we live with the non-intuitive property behavior.
+ */
+ if (!((ndi_dev_is_persistent_node(dip) == 0) &&
+ (DEVI(dip)->devi_flags & DEVI_REBIND)))
+ e_ddi_prop_remove_all(dip);
} else {
NDI_CONFIG_DEBUG((CE_CONT, "uninit_node failed: 0x%p(%s%d)\n",
(void *)dip, ddi_driver_name(dip), ddi_get_instance(dip)));
@@ -1301,6 +1425,7 @@ i_ndi_config_node(dev_info_t *dip, ddi_node_state_t state, uint_t flag)
*/
if ((rv = bind_node(dip)) == DDI_SUCCESS)
i_ddi_set_node_state(dip, DS_BOUND);
+
break;
case DS_BOUND:
/*
@@ -1874,11 +1999,15 @@ i_ddi_devi_attached(dev_info_t *dip)
* By default, name is matched with devi_node_name. The following
* alternative match strategies are supported:
*
- * FIND_NAME_BY_DRIVER: A match on driver name bound to node is conducted.
+ * FIND_NODE_BY_NODENAME: Match on node name - typical use.
+ * FIND_NODE_BY_DRIVER: A match on driver name bound to node is conducted.
* This support is used for support of OBP generic names and
- * for the conversion from driver names to generic names. When
+ * for the conversion from driver names to generic names. When
* more consistency in the generic name environment is achieved
* (and not needed for upgrade) this support can be removed.
+ * FIND_NODE_BY_ADDR: Match on just the addr.
+ * This support is only used/needed during boot to match
+ * a node bound via a path-based driver alias.
*
* If a child is not named (dev_addr == NULL), there are three
* possible actions:
@@ -1887,7 +2016,9 @@ i_ddi_devi_attached(dev_info_t *dip)
* (2) FIND_ADDR_BY_INIT: bring child to DS_INITIALIZED state
* (3) FIND_ADDR_BY_CALLBACK: use a caller-supplied callback function
*/
-#define FIND_NAME_BY_DRIVER 0x01
+#define FIND_NODE_BY_NODENAME 0x01
+#define FIND_NODE_BY_DRIVER 0x02
+#define FIND_NODE_BY_ADDR 0x04
#define FIND_ADDR_BY_INIT 0x10
#define FIND_ADDR_BY_CALLBACK 0x20
@@ -1898,12 +2029,18 @@ find_sibling(dev_info_t *head, char *cname, char *caddr, uint_t flag,
dev_info_t *dip;
char *addr, *buf;
major_t major;
+ uint_t by;
+
+ /* only one way to find a node */
+ by = flag &
+ (FIND_NODE_BY_DRIVER | FIND_NODE_BY_NODENAME | FIND_NODE_BY_ADDR);
+ ASSERT(by && BIT_ONLYONESET(by));
/* only one way to name a node */
ASSERT(((flag & FIND_ADDR_BY_INIT) == 0) ||
((flag & FIND_ADDR_BY_CALLBACK) == 0));
- if (flag & FIND_NAME_BY_DRIVER) {
+ if (by == FIND_NODE_BY_DRIVER) {
major = ddi_name_to_major(cname);
if (major == (major_t)-1)
return (NULL);
@@ -1918,14 +2055,14 @@ find_sibling(dev_info_t *head, char *cname, char *caddr, uint_t flag,
*/
for (dip = head; dip; dip = ddi_get_next_sibling(dip)) {
- if (flag & FIND_NAME_BY_DRIVER) {
- /* match driver major */
- if (DEVI(dip)->devi_major != major)
- continue;
- } else {
+ if (by == FIND_NODE_BY_NODENAME) {
/* match node name */
if (strcmp(cname, DEVI(dip)->devi_node_name) != 0)
continue;
+ } else if (by == FIND_NODE_BY_DRIVER) {
+ /* match driver major */
+ if (DEVI(dip)->devi_major != major)
+ continue;
}
if ((addr = DEVI(dip)->devi_addr) == NULL) {
@@ -1968,7 +2105,8 @@ find_duplicate_child(dev_info_t *pdip, dev_info_t *dip)
char *caddr = DEVI(dip)->devi_addr;
/* search nodes before dip */
- dup = find_sibling(ddi_get_child(pdip), cname, caddr, 0, NULL);
+ dup = find_sibling(ddi_get_child(pdip), cname, caddr,
+ FIND_NODE_BY_NODENAME, NULL);
if (dup != dip)
return (dup);
@@ -1976,7 +2114,7 @@ find_duplicate_child(dev_info_t *pdip, dev_info_t *dip)
* search nodes after dip; normally this is not needed,
*/
return (find_sibling(ddi_get_next_sibling(dip), cname, caddr,
- 0, NULL));
+ FIND_NODE_BY_NODENAME, NULL));
}
/*
@@ -1988,7 +2126,7 @@ find_child_by_callback(dev_info_t *pdip, char *cname, char *caddr,
int (*name_node)(dev_info_t *, char *, int))
{
return (find_sibling(ddi_get_child(pdip), cname, caddr,
- FIND_NAME_BY_DRIVER|FIND_ADDR_BY_CALLBACK, name_node));
+ FIND_NODE_BY_DRIVER|FIND_ADDR_BY_CALLBACK, name_node));
}
/*
@@ -2000,13 +2138,14 @@ find_child_by_name(dev_info_t *pdip, char *cname, char *caddr)
{
dev_info_t *dip;
- /* attempt search without changing state of preceeding siblings */
- dip = find_sibling(ddi_get_child(pdip), cname, caddr, 0, NULL);
+ /* attempt search without changing state of preceding siblings */
+ dip = find_sibling(ddi_get_child(pdip), cname, caddr,
+ FIND_NODE_BY_NODENAME, NULL);
if (dip)
return (dip);
return (find_sibling(ddi_get_child(pdip), cname, caddr,
- FIND_ADDR_BY_INIT, NULL));
+ FIND_NODE_BY_NODENAME|FIND_ADDR_BY_INIT, NULL));
}
/*
@@ -2018,14 +2157,41 @@ find_child_by_driver(dev_info_t *pdip, char *cname, char *caddr)
{
dev_info_t *dip;
- /* attempt search without changing state of preceeding siblings */
+ /* attempt search without changing state of preceding siblings */
dip = find_sibling(ddi_get_child(pdip), cname, caddr,
- FIND_NAME_BY_DRIVER, NULL);
+ FIND_NODE_BY_DRIVER, NULL);
if (dip)
return (dip);
return (find_sibling(ddi_get_child(pdip), cname, caddr,
- FIND_NAME_BY_DRIVER|FIND_ADDR_BY_INIT, NULL));
+ FIND_NODE_BY_DRIVER|FIND_ADDR_BY_INIT, NULL));
+}
+
+/*
+ * Find a child of a given address, invoking initchild to name
+ * unnamed children. cname is the node name.
+ *
+ * NOTE: This function is only used during boot. One would hope that
+ * unique sibling unit-addresses on hardware branches of the tree would
+ * be a requirement to avoid two drivers trying to control the same
+ * piece of hardware. Unfortunately there are some cases where this
+ * situation exists (/ssm@0,0/pci@1c,700000 /ssm@0,0/sghsc@1c,700000).
+ * Until unit-address uniqueness of siblings is guaranteed, use of this
+ * interface for purposes other than boot should be avoided.
+ */
+static dev_info_t *
+find_child_by_addr(dev_info_t *pdip, char *caddr)
+{
+ dev_info_t *dip;
+
+ /* attempt search without changing state of preceding siblings */
+ dip = find_sibling(ddi_get_child(pdip), NULL, caddr,
+ FIND_NODE_BY_ADDR, NULL);
+ if (dip)
+ return (dip);
+
+ return (find_sibling(ddi_get_child(pdip), NULL, caddr,
+ FIND_NODE_BY_ADDR|FIND_ADDR_BY_INIT, NULL));
}
/*
@@ -2425,6 +2591,34 @@ ddi_compatible_driver_major(dev_info_t *dip, char **formp)
if (formp)
*formp = NULL;
+ /*
+ * Highest precedence binding is a path-oriented alias. Since this
+ * requires a 'path', this type of binding occurs via more obtuse
+ * 'rebind'. The need for a path-oriented alias 'rebind' is detected
+ * after a successful DDI_CTLOPS_INITCHILD to another driver: this is
+ * is the first point at which the unit-address (or instance) of the
+ * last component of the path is available (even though the path is
+ * bound to the wrong driver at this point).
+ */
+ if (devi->devi_flags & DEVI_REBIND) {
+ p = devi->devi_rebinding_name;
+ major = ddi_name_to_major(p);
+ if ((major != (major_t)-1) &&
+ !(devnamesp[major].dn_flags & DN_DRIVER_REMOVED)) {
+ if (formp)
+ *formp = p;
+ return (major);
+ }
+
+ /*
+ * If for some reason devi_rebinding_name no longer resolves
+ * to a proper driver then clear DEVI_REBIND.
+ */
+ mutex_enter(&devi->devi_lock);
+ devi->devi_flags &= ~DEVI_REBIND;
+ mutex_exit(&devi->devi_lock);
+ }
+
/* look up compatible property */
(void) lookup_compatible(dip, KM_SLEEP);
compat = (void *)(devi->devi_compat_names);
@@ -3727,6 +3921,38 @@ static int
bind_dip(dev_info_t *dip, void *arg)
{
_NOTE(ARGUNUSED(arg))
+ char *path;
+ major_t major, pmajor;
+
+ /*
+ * If the node is currently bound to the wrong driver, try to unbind
+ * so that we can rebind to the correct driver.
+ */
+ if (i_ddi_node_state(dip) >= DS_BOUND) {
+ major = ddi_compatible_driver_major(dip, NULL);
+ if ((DEVI(dip)->devi_major == major) &&
+ (i_ddi_node_state(dip) >= DS_INITIALIZED)) {
+ /*
+ * Check for a path-oriented driver alias that
+ * takes precedence over current driver binding.
+ */
+ path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
+ (void) ddi_pathname(dip, path);
+ pmajor = ddi_name_to_major(path);
+ if ((pmajor != (major_t)-1) &&
+ !(devnamesp[pmajor].dn_flags & DN_DRIVER_REMOVED))
+ major = pmajor;
+ kmem_free(path, MAXPATHLEN);
+ }
+
+ /* attempt unbind if current driver is incorrect */
+ if ((major != (major_t)-1) &&
+ !(devnamesp[major].dn_flags & DN_DRIVER_REMOVED) &&
+ (major != DEVI(dip)->devi_major))
+ (void) ndi_devi_unbind_driver(dip);
+ }
+
+ /* If unbound, try to bind to a driver */
if (i_ddi_node_state(dip) < DS_BOUND)
(void) ndi_devi_bind_driver(dip, 0);
@@ -3736,6 +3962,9 @@ bind_dip(dev_info_t *dip, void *arg)
void
i_ddi_bind_devs(void)
{
+ /* flush devfs so that ndi_devi_unbind_driver will work when possible */
+ (void) devfs_clean(top_devinfo, NULL, 0);
+
ddi_walk_devs(top_devinfo, bind_dip, (void *)NULL);
}
@@ -4627,6 +4856,7 @@ devi_config_one(dev_info_t *pdip, char *devnm, dev_info_t **cdipp,
{
dev_info_t *vdip = NULL;
char *drivername = NULL;
+ int find_by_addr = 0;
char *name, *addr;
int v_circ, p_circ;
clock_t end_time; /* 60 sec */
@@ -4656,8 +4886,10 @@ devi_config_one(dev_info_t *pdip, char *devnm, dev_info_t **cdipp,
* drivername. This allows an implementation to supply a genericly
* named boot path (disk) and locate drivename nodes (sd).
*/
- if (flags & NDI_PROMNAME)
+ if (flags & NDI_PROMNAME) {
drivername = child_path_to_driver(pdip, name, addr);
+ find_by_addr = 1;
+ }
/*
* Determine end_time: This routine should *not* be called with a
@@ -4698,13 +4930,16 @@ devi_config_one(dev_info_t *pdip, char *devnm, dev_info_t **cdipp,
* Search for child by name, if not found then search
* for a node bound to the drivername driver with the
* specified "@addr". Break out of for(;;) loop if
- * child found.
+ * child found. To support path-oriented aliases
+ * binding on boot-device, we do a search_by_addr too.
*/
again: (void) i_ndi_make_spec_children(pdip, flags);
cdip = find_child_by_name(pdip, name, addr);
if ((cdip == NULL) && drivername)
cdip = find_child_by_driver(pdip,
drivername, addr);
+ if ((cdip == NULL) && find_by_addr)
+ cdip = find_child_by_addr(pdip, addr);
if (cdip)
break;
@@ -4823,7 +5058,7 @@ ndi_devi_config_one(dev_info_t *dip, char *devnm, dev_info_t **dipp, int flags)
}
/*
- * DR usage ((i.e. call with NDI_CONFIG) recursively configures
+ * DR usage (i.e. call with NDI_CONFIG) recursively configures
* grandchildren, performing a BUS_CONFIG_ALL from the node attached
* by the BUS_CONFIG_ONE.
*/
@@ -5585,7 +5820,8 @@ ndi_devi_find(dev_info_t *pdip, char *cname, char *caddr)
return ((dev_info_t *)NULL);
ndi_devi_enter(pdip, &circ);
- child = find_sibling(ddi_get_child(pdip), cname, caddr, 0, NULL);
+ child = find_sibling(ddi_get_child(pdip), cname, caddr,
+ FIND_NODE_BY_NODENAME, NULL);
ndi_devi_exit(pdip, circ);
return (child);
}
@@ -5611,7 +5847,8 @@ ndi_devi_findchild(dev_info_t *pdip, char *devname)
return ((dev_info_t *)NULL);
}
- child = find_sibling(ddi_get_child(pdip), cname, caddr, 0, NULL);
+ child = find_sibling(ddi_get_child(pdip), cname, caddr,
+ FIND_NODE_BY_NODENAME, NULL);
kmem_free(devstr, strlen(devname)+1);
return (child);
}
@@ -5671,7 +5908,16 @@ path_to_major(char *path)
dev_info_t *dip;
char *p, *q;
pnode_t nodeid;
- major_t maj;
+ major_t major;
+
+ /* check for path-oriented alias */
+ major = ddi_name_to_major(path);
+ if ((major != (major_t)-1) &&
+ !(devnamesp[major].dn_flags & DN_DRIVER_REMOVED)) {
+ NDI_CONFIG_DEBUG((CE_NOTE, "path_to_major: %s path bound %s\n",
+ path, ddi_major_to_name(major)));
+ return (major);
+ }
/*
* Get the nodeid of the given pathname, if such a mapping exists.
@@ -5702,11 +5948,11 @@ path_to_major(char *path)
NDI_CONFIG_DEBUG((CE_NOTE, "path_to_major: %s bound to %s\n",
path, p));
- maj = ddi_name_to_major(p);
+ major = ddi_name_to_major(p);
- ndi_rele_devi(dip); /* release node held during walk */
+ ndi_rele_devi(dip); /* release e_ddi_nodeid_to_dip hold */
- return (maj);
+ return (major);
}
/*
@@ -6837,25 +7083,10 @@ i_ddi_di_cache_invalidate(int kmflag)
static void
i_bind_vhci_node(dev_info_t *dip)
{
- char *node_name;
-
- node_name = i_ddi_strdup(ddi_node_name(dip), KM_SLEEP);
- i_ddi_set_binding_name(dip, node_name);
- DEVI(dip)->devi_major = ddi_name_to_major(node_name);
+ DEVI(dip)->devi_major = ddi_name_to_major(ddi_node_name(dip));
i_ddi_set_node_state(dip, DS_BOUND);
}
-
-static void
-i_free_vhci_bind_name(dev_info_t *dip)
-{
- if (DEVI(dip)->devi_binding_name) {
- kmem_free(DEVI(dip)->devi_binding_name,
- sizeof (ddi_node_name(dip)));
- }
-}
-
-
static char vhci_node_addr[2];
static int
@@ -6938,7 +7169,6 @@ ndi_devi_config_vhci(char *drvname, int flags)
i_ddi_add_devimap(dip);
i_bind_vhci_node(dip);
if (i_init_vhci_node(dip) == -1) {
- i_free_vhci_bind_name(dip);
ndi_rele_devi(dip);
(void) ndi_devi_free(dip);
return (NULL);
@@ -6951,7 +7181,6 @@ ndi_devi_config_vhci(char *drvname, int flags)
if (devi_attach(dip, DDI_ATTACH) != DDI_SUCCESS) {
cmn_err(CE_CONT, "Could not attach %s driver", drvname);
e_ddi_free_instance(dip, vhci_node_addr);
- i_free_vhci_bind_name(dip);
ndi_rele_devi(dip);
(void) ndi_devi_free(dip);
return (NULL);
diff --git a/usr/src/uts/common/os/modsysfile.c b/usr/src/uts/common/os/modsysfile.c
index d1538a3f9d..690491d8ba 100644
--- a/usr/src/uts/common/os/modsysfile.c
+++ b/usr/src/uts/common/os/modsysfile.c
@@ -2147,8 +2147,8 @@ make_aliases(struct bind **bhash)
} state;
struct _buf *file;
- char tokbuf[MAXNAMELEN];
- char drvbuf[MAXNAMELEN];
+ char tokbuf[MAXPATHLEN];
+ char drvbuf[MAXPATHLEN];
token_t token;
major_t major;
int done = 0;
diff --git a/usr/src/uts/common/os/sunddi.c b/usr/src/uts/common/os/sunddi.c
index 8c6bcefe06..e9fd930d22 100644
--- a/usr/src/uts/common/os/sunddi.c
+++ b/usr/src/uts/common/os/sunddi.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -6350,10 +6350,22 @@ ddi_deviname(dev_info_t *dip, char *name)
return (name);
}
- if (i_ddi_node_state(dip) < DS_INITIALIZED) {
+ if (i_ddi_node_state(dip) < DS_BOUND) {
addrname = &none;
} else {
+ /*
+ * Use ddi_get_name_addr() without checking state so we get
+ * a unit-address if we are called after ddi_set_name_addr()
+ * by nexus DDI_CTL_INITCHILD code, but before completing
+ * node promotion to DS_INITIALIZED. We currently have
+ * two situations where we are called in this state:
+ * o For framework processing of a path-oriented alias.
+ * o If a SCSA nexus driver calls ddi_devid_register()
+ * from it's tran_tgt_init(9E) implementation.
+ */
addrname = ddi_get_name_addr(dip);
+ if (addrname == NULL)
+ addrname = &none;
}
if (*addrname == '\0') {
diff --git a/usr/src/uts/common/os/swapgeneric.c b/usr/src/uts/common/os/swapgeneric.c
index b1c9d5e7b0..72ea7572e7 100644
--- a/usr/src/uts/common/os/swapgeneric.c
+++ b/usr/src/uts/common/os/swapgeneric.c
@@ -20,7 +20,7 @@
*/
/* ONC_PLUS EXTRACT START */
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -718,16 +718,34 @@ load_boot_driver(char *drv)
* For a given instance, load that driver and its parents
*/
static int
-load_parent_drivers(dev_info_t *dip)
+load_parent_drivers(dev_info_t *dip, char *path)
{
int rval = 0;
+ major_t major = (major_t)-1;
char *drv;
+ char *p;
while (dip) {
- drv = ddi_get_name(dip);
+ /* check for path-oriented alias */
+ if (path)
+ major = ddi_name_to_major(path);
+ else
+ major = (major_t)-1;
+
+ if (major != (major_t)-1)
+ drv = ddi_major_to_name(major);
+ else
+ drv = ddi_binding_name(dip);
+
if (load_boot_driver(drv) != 0)
rval = -1;
+
dip = ddi_get_parent(dip);
+ if (path) {
+ p = strrchr(path, '/');
+ if (p)
+ *p = 0;
+ }
}
return (rval);
@@ -741,14 +759,21 @@ load_parent_drivers(dev_info_t *dip)
static int
load_bootpath_drivers(char *bootpath)
{
- dev_info_t *dip;
+ dev_info_t *dip;
+ char *pathcopy;
+ int pathcopy_len;
+ int rval;
+ char *p;
if (bootpath == NULL || *bootpath == 0)
return (-1);
BMDPRINTF(("load_bootpath_drivers: %s\n", bootpath));
- dip = path_to_devinfo(bootpath);
+ pathcopy = i_ddi_strdup(bootpath, KM_SLEEP);
+ pathcopy_len = strlen(pathcopy) + 1;
+
+ dip = path_to_devinfo(pathcopy);
#if defined(__i386) || defined(__amd64)
/*
@@ -758,44 +783,40 @@ load_bootpath_drivers(char *bootpath)
* which we go ahead and load here.
*/
if (dip == NULL) {
- char *pathcopy, *leaf, *p;
- int len, rval;
-
- len = strlen(bootpath) + 1;
- pathcopy = kmem_zalloc(len, KM_SLEEP);
- (void) strcpy(pathcopy, bootpath);
+ char *leaf;
/*
- * Work backward to the last slash to build the
- * full path of the parent of the boot device
+ * Find last slash to build the full path to the
+ * parent of the leaf boot device
*/
- for (p = pathcopy + len - 2; *p != '/'; p--)
- ;
+ p = strrchr(pathcopy, '/');
*p++ = 0;
/*
* Now isolate the driver name of the leaf device
*/
- for (leaf = p; *p && *p != '@'; p++)
- ;
+ leaf = p;
+ p = strchr(leaf, '@');
*p = 0;
BMDPRINTF(("load_bootpath_drivers: parent=%s leaf=%s\n",
- pathcopy, leaf));
+ bootpath, leaf));
dip = path_to_devinfo(pathcopy);
-
- rval = load_boot_driver(leaf);
- kmem_free(pathcopy, len);
- if (rval == -1)
- return (NULL);
-
+ if (leaf) {
+ rval = load_boot_driver(leaf, NULL);
+ if (rval == -1) {
+ kmem_free(pathcopy, pathcopy_len);
+ return (NULL);
+ }
+ }
}
#endif
if (dip == NULL) {
cmn_err(CE_WARN, "can't bind driver for boot path <%s>",
bootpath);
+ kmem_free(pathcopy, pathcopy_len);
return (NULL);
}
@@ -811,10 +832,21 @@ load_bootpath_drivers(char *bootpath)
if (netboot_over_ib(bootpath) &&
modloadonly("drv", "ibd") == -1) {
cmn_err(CE_CONT, "ibd: cannot load platform driver\n");
+ kmem_free(pathcopy, pathcopy_len);
return (NULL);
}
- return (load_parent_drivers(dip));
+ /* get rid of minor node at end of copy (if not already done above) */
+ p = strrchr(pathcopy, '/');
+ if (p) {
+ p = strchr(p, ':');
+ if (p)
+ *p = 0;
+ }
+
+ rval = load_parent_drivers(dip, pathcopy);
+ kmem_free(pathcopy, pathcopy_len);
+ return (rval);
}
@@ -866,7 +898,7 @@ load_boot_platform_modules(char *drv)
}
} else {
while (dip) {
- if (load_parent_drivers(dip) != 0)
+ if (load_parent_drivers(dip, NULL) != 0)
rval = -1;
dip = ddi_get_next(dip);
}
diff --git a/usr/src/uts/common/sys/ddi_impldefs.h b/usr/src/uts/common/sys/ddi_impldefs.h
index 0a1bcf9cde..3b99c60997 100644
--- a/usr/src/uts/common/sys/ddi_impldefs.h
+++ b/usr/src/uts/common/sys/ddi_impldefs.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -80,7 +80,10 @@ struct dev_info {
struct dev_info *devi_child; /* my child list head */
struct dev_info *devi_sibling; /* next element on my level */
- char *devi_binding_name; /* name used to bind driver */
+ char *devi_binding_name; /* name used to bind driver: */
+ /* shared storage, points to */
+ /* devi_node_name, devi_compat_names */
+ /* or devi_rebinding_name */
char *devi_addr; /* address part of name */
@@ -189,6 +192,8 @@ struct dev_info {
void *devi_nex_pm; /* nexus PM private */
char *devi_addr_buf; /* buffer for devi_addr */
+
+ char *devi_rebinding_name; /* binding_name of rebind */
};
#define DEVI(dev_info_type) ((struct dev_info *)(dev_info_type))
@@ -497,6 +502,7 @@ void i_devi_exit(dev_info_t *, uint_t c_mask, int has_lock);
#define DEVI_NO_BIND 0x00000010 /* prevent driver binding */
#define DEVI_REGISTERED_DEVID 0x00000020 /* device registered a devid */
#define DEVI_PHCI_SIGNALS_VHCI 0x00000040 /* pHCI ndi_devi_exit signals vHCI */
+#define DEVI_REBIND 0x00000080 /* post initchild driver rebind */
#define DEVI_BUSY_CHANGING(dip) (DEVI(dip)->devi_flags & DEVI_BUSY)
#define DEVI_BUSY_OWNED(dip) (DEVI_BUSY_CHANGING(dip) && \
diff --git a/usr/src/uts/common/sys/ndi_impldefs.h b/usr/src/uts/common/sys/ndi_impldefs.h
index 2f36500d01..0d450e2db0 100644
--- a/usr/src/uts/common/sys/ndi_impldefs.h
+++ b/usr/src/uts/common/sys/ndi_impldefs.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 1998-2003 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -126,6 +125,12 @@ void i_ndi_set_node_attributes(dev_info_t *, int);
*/
void i_ndi_set_nodeid(dev_info_t *, int);
+/*
+ * Make driver.conf children.
+ * (Intended for the ddi framework use only.)
+ */
+int i_ndi_make_spec_children(dev_info_t *, uint_t);
+
#ifdef __cplusplus
}
#endif