summaryrefslogtreecommitdiff
path: root/usr/src/cmd/pcidr
diff options
context:
space:
mode:
authorjohnny <none@none>2005-11-10 12:33:07 -0800
committerjohnny <none@none>2005-11-10 12:33:07 -0800
commit70025d765b044c6d8594bb965a2247a61e991a99 (patch)
treeecf0115912221f8be4400ca9bf4d04802b8e0355 /usr/src/cmd/pcidr
parent4610e4a00999c6d2291b3fc263926b890ec500a5 (diff)
downloadillumos-gate-70025d765b044c6d8594bb965a2247a61e991a99.tar.gz
PSARC 2005/375 PCI Hotplug Extensions for PCIe
PSARC 2002/315 cPCI Autoconfiguration Support 6331880 PCI Hot-Plug Framework Extension for PCIe 6331883 cPCI autoconfiguration support 6326583 PCIE support for X86 6339777 cleanup of references to obsoleted interface, pcihp_cb_ops, in pci/pci_pci nexus (x86) 6341189 assertion panic on Dell PowerEdge 6850 in apic.c: apic_irq_table[irqno]->airq_intin_no != ipin
Diffstat (limited to 'usr/src/cmd/pcidr')
-rwxr-xr-xusr/src/cmd/pcidr/Makefile79
-rwxr-xr-xusr/src/cmd/pcidr/Makefile.com52
-rw-r--r--usr/src/cmd/pcidr/etc/Makefile50
-rw-r--r--usr/src/cmd/pcidr/etc/SUNW,EC_dr,ESC_dr_req,sysevent.conf29
-rwxr-xr-xusr/src/cmd/pcidr/pcidr.c656
-rw-r--r--usr/src/cmd/pcidr/pcidr.h109
-rw-r--r--usr/src/cmd/pcidr/pcidr_common.c351
-rwxr-xr-xusr/src/cmd/pcidr/plugins/Makefile52
-rwxr-xr-xusr/src/cmd/pcidr/plugins/Makefile.targ37
-rwxr-xr-xusr/src/cmd/pcidr/plugins/default/Makefile93
-rw-r--r--usr/src/cmd/pcidr/plugins/default/pcidr_cfga.c330
-rw-r--r--usr/src/cmd/pcidr/plugins/default/pcidr_cfga.h57
-rw-r--r--usr/src/cmd/pcidr/plugins/default/pcidr_plugin.c144
13 files changed, 2039 insertions, 0 deletions
diff --git a/usr/src/cmd/pcidr/Makefile b/usr/src/cmd/pcidr/Makefile
new file mode 100755
index 0000000000..756f10afe6
--- /dev/null
+++ b/usr/src/cmd/pcidr/Makefile
@@ -0,0 +1,79 @@
+#
+# 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.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# cmd/pcidr/Makefile
+#
+
+.PARALLEL:
+#############################################################################
+
+PROGOBJECTS = pcidr.o pcidr_common.o
+PROG = pcidr
+
+SUBDIRS = plugins etc
+
+include $(SRC)/cmd/Makefile.cmd
+include Makefile.com
+#############################################################################
+
+# used by the lint_SRCS rule
+#
+SRCS = $(PROGOBJECTS:%.o=%.c)
+CLOBBERFILES += $(PROGOBJECTS)
+
+LDLIBS += -lnvpair
+LINTFLAGS += -erroff=E_NAME_DEF_NOT_USED2
+
+all := TARGET = all
+install := TARGET = install
+clean := TARGET = clean
+clobber := TARGET = clobber
+lint := TARGET = lint
+
+.KEEP_STATE:
+#############################################################################
+
+all: $(PROG)
+clean:
+clobber:
+install: $(ROOTCMD)
+lint: lint_SRCS
+
+$(ROOTCMD): all
+
+$(PROG): $(PROGOBJECTS)
+ $(LINK.c) -o $(PROG) $(PROGOBJECTS) $(LDLIBS)
+ $(POST_PROCESS)
+
+all clean clobber lint: $(SUBDIRS)
+install: .WAIT $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+FRC:
+
+include $(SRC)/cmd/Makefile.targ
diff --git a/usr/src/cmd/pcidr/Makefile.com b/usr/src/cmd/pcidr/Makefile.com
new file mode 100755
index 0000000000..257987bb10
--- /dev/null
+++ b/usr/src/cmd/pcidr/Makefile.com
@@ -0,0 +1,52 @@
+#
+# 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.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# cmd/pcidr/Makefile.com
+#
+# to be included AFTER cmd/Makefile.cmd or lib/Makefile.lib
+
+TOP = $(SRC)/cmd/pcidr
+INSTALLDIR = /usr/lib/pci
+
+#############################################################################
+### used by macros in Makefile.cmd/lib
+
+HDRDIR = $(TOP)
+HDRS_SH = cd $(HDRDIR); ls *.h
+HDRS = $(HDRS_SH:sh)
+
+ROOTLIBDIR = $(ROOT)/$(INSTALLDIR)
+ROOTCMDDIR = $(ROOTLIBDIR)
+#############################################################################
+
+CPPFLAGS += -D_REENTRANT -I$(HDRDIR)
+
+# Note that LDFLAGS is NOT used in the build rules for shared objects!
+# LDLIBS is limited to -L and -l options; all other options must be added to
+# DYNFLAGS for shared objects
+
+LDLIBS += -lc
diff --git a/usr/src/cmd/pcidr/etc/Makefile b/usr/src/cmd/pcidr/etc/Makefile
new file mode 100644
index 0000000000..fee5fec036
--- /dev/null
+++ b/usr/src/cmd/pcidr/etc/Makefile
@@ -0,0 +1,50 @@
+#
+# 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.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# cmd/pcidr/etc/Makefile
+#
+
+.PARALLEL:
+
+include $(SRC)/cmd/Makefile.cmd
+
+CONF = SUNW,EC_dr,ESC_dr_req,sysevent.conf
+CONFDIR = $(ROOTETC)/sysevent/config
+
+# utilize the predefined install target patterns in cmd/Makefile.targ by
+# overriding ROOTCMDDIR
+#
+ROOTCMDDIR = $(CONFDIR)
+FILEMODE = 0644
+
+.KEEP_STATE:
+
+all clean clobber lint:
+
+install: $(CONF:%=$(CONFDIR)/%)
+
+include $(SRC)/cmd/Makefile.targ
diff --git a/usr/src/cmd/pcidr/etc/SUNW,EC_dr,ESC_dr_req,sysevent.conf b/usr/src/cmd/pcidr/etc/SUNW,EC_dr,ESC_dr_req,sysevent.conf
new file mode 100644
index 0000000000..cb151ebf2a
--- /dev/null
+++ b/usr/src/cmd/pcidr/etc/SUNW,EC_dr,ESC_dr_req,sysevent.conf
@@ -0,0 +1,29 @@
+#
+# 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.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+EC_dr ESC_dr_req SUNW pcie_pci - - - /usr/lib/pci/pcidr class=$class subclass=$subclass publisher=$publisher dr_request_type=$dr_request_type dr_ap_id=$dr_ap_id
diff --git a/usr/src/cmd/pcidr/pcidr.c b/usr/src/cmd/pcidr/pcidr.c
new file mode 100755
index 0000000000..1940f604d2
--- /dev/null
+++ b/usr/src/cmd/pcidr/pcidr.c
@@ -0,0 +1,656 @@
+/*
+ * 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.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/param.h>
+#include <sys/systeminfo.h>
+#include <sys/sysevent/eventdefs.h>
+#include <sys/sysevent/dr.h>
+#include <syslog.h>
+#include <libnvpair.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <sys/stat.h>
+#include <dlfcn.h>
+#include <signal.h>
+#include <pcidr.h>
+
+/*
+ * pcidr takes in arguments of the form specified in the help() routine
+ * including a set of name=value pairs, then looks up a plugin (shared object)
+ * based on <plugin_paths> and however find_plugin() operates. The entry
+ * point of the plugin is <PCIDR_PLUGIN_SYM> and has the type
+ * <pcidr_plugin_t>. Plugins must use the <PCIDR_PLUGIN_PROTO> macro to
+ * define their entry point.
+ *
+ * The name=value arguments are intended to be used as a mechanism to pass
+ * arbitrary sysevent attributes using the macro expansion capability provided
+ * by the syseventd SLM processing sysevent.conf files (i.e. specifying
+ * "$attribute" arguments for the handler in a .conf file entry). They are
+ * converted into an nvlist_t (see libnvpair(3LIB)) by converting the values
+ * of recognized names into appropriate types using pcidr_name2type() and
+ * leaving all others as string types. Because pcidr is used as a sysevent.conf
+ * handler, the format of the value string for non-string attributes in each
+ * name=value argument must match that used by the syseventd macro capability
+ *
+ * The plugin will be passed this (nvlist_t *) along with a (pcidr_opt_t *) arg
+ * for other options. While pcidr does some basic checking of arguments, it
+ * leaves any name=value check (after conversion) up to each plugin. Note
+ * that pcidr_check_attrs() is used by the default plugin and can be used by
+ * any plugin that support the same or a superset of its attributes. If the
+ * default plugin supports additional publishers, it should be updated in
+ * pcidr_check_attrs().
+ *
+ * See help() for an example of how pcidr can be specified in a sysevent.conf
+ * file.
+ */
+
+/*
+ * plugin search paths (searched in order specified);
+ * macros begin MACRO_BEGTOK and end with MACRO_ENDTOK;
+ *
+ * be sure to update parse_path() and its support functions whenever macros
+ * are updated e.g. si_name2cmd(), as well as substring tokens (prefix or
+ * suffix) used to recognize different types of macros e.g. SI_MACRO
+ *
+ * NOTE: if plugin search algorithm is changed starting with find_plugin(),
+ * please update documentation here.
+ *
+ * macros:
+ * SI_PLATFORM = cmd of same name in sysinfo(2)
+ * SI_MACHINE = cmd of same name in sysinfo(2)
+ */
+#define MACRO_BEGTOK "${"
+#define MACRO_ENDTOK "}"
+#define SI_MACRO "SI_"
+
+static char *plugin_paths[] = {
+ "/usr/platform/${SI_PLATFORM}/lib/pci/" PCIDR_PLUGIN_NAME,
+ "/usr/platform/${SI_MACHINE}/lib/pci/" PCIDR_PLUGIN_NAME,
+ "/usr/lib/pci/" PCIDR_PLUGIN_NAME,
+};
+static int plugin_paths_len = sizeof (plugin_paths) / sizeof (plugin_paths[0]);
+
+
+static nvlist_t *nvlistp = NULL; /* attribute list */
+
+typedef struct {
+ char *name;
+ char *beg;
+ char *end;
+} macro_list_t;
+static macro_list_t *parse_macros(char *const, int *);
+static void free_macros(macro_list_t *, int);
+static char *parse_path(char *const);
+static void help();
+static void exiter();
+static char *find_plugin(nvlist_t *);
+static int do_plugin(char *, nvlist_t *, pcidr_opt_t *);
+static int nvadd(nvlist_t *, char *, char *, data_type_t);
+static nvlist_t *parse_argv_attr(int, char **, int *);
+static int si_name2cmd(char *);
+
+
+static void
+help()
+{
+/* since the handler is not public, we don't expose its usage normally */
+#ifdef DEBUG
+ (void) printf(
+"%s [-h] [-s] [-v <level>] [-l <log_file>] <attributes>\n"
+" -h help\n"
+"\n"
+" -s turn OFF messages to the syslog (use syslog by default)\n"
+"\n"
+" -v verbose mode; <level> range is %d..%d; default is %d\n"
+"\n"
+" -l also log messages to <log_file> (in addition to using\n"
+" the syslog if that option is not disabled);\n"
+" if <log_file> is '-', stdout is used\n"
+"\n"
+" <attributes>\n"
+" whitespace seperated strings of <name>=<value> pairs\n"
+"\n"
+"Example 1 (command line):\n"
+" %s -s -v%d -l- \\\n"
+" class=EC_dr subclass=ESC_dr_req publisher=pcie_pci \\\n"
+" dr_request_type=dr_request_outgoing_resource \\\n"
+" dr_ap_id=/devices/foo/bar\n"
+"\n"
+"Example 2 (/etc/sysevent/config/SUNW,sysevent.conf entry):\n"
+" EC_dr ESC_dr_req SUNW pcie_pci - - - %s -v%d -l/tmp/log \\\n"
+" class=$class subclass=$subclass publisher=$publisher \\\n"
+" dr_request_type=$dr_request_type\\\n"
+" dr_ap_id=$dr_ap_id\n"
+"\n",
+ prg, MIN_DLVL, MAX_DLVL, dlvl,
+ prg, MAX_DLVL, /* Example 1 */
+ prg, DWARN); /* Example 2 */
+#endif
+}
+
+
+/*
+ * will convert <value> from a string to the type indicated by <type>
+ * and will add it with <name> to nvlist_t <listp>; function returns the same
+ * value as nvlist_add_*()
+ */
+static int
+nvadd(nvlist_t *listp, char *name, char *value, data_type_t type)
+{
+ char *fn = "nvadd";
+ int rv = 0;
+
+ switch (type) {
+ case DATA_TYPE_STRING:
+ rv = nvlist_add_string(listp, name, value);
+ if (rv != 0) {
+ dprint(DDEBUG, "%s: nvlist_add_string() failed: "
+ "name = %s, value = %s, rv = %d\n",
+ fn, name, value, rv);
+ }
+ break;
+ /*
+ * Conversion must support whatever string format syseventd uses for
+ * its .conf macros; in addition, minimum types supported must match
+ * those for pcidr_name2type()
+ */
+ default:
+ dprint(DDEBUG, "%s: unsupported type: name = %s, value = %s, "
+ "type = 0x%x\n", fn, name, value, (int)type);
+ rv = EINVAL;
+ }
+
+ return (rv);
+}
+
+
+/*
+ * argc: length of argv
+ * argv: each string starting from index <argip> has the format "name=value"
+ * argip: starting index in <argv>; also used to return ending index
+ *
+ * return: allocated nvlist on success, exits otherwise
+ *
+ * recognized names will have predetermined types, while all others will have
+ * values of type string
+ */
+static nvlist_t *
+parse_argv_attr(int argc, char **argv, int *argip)
+{
+ char *fn = "parse_argv_attr";
+ int rv, i;
+ nvlist_t *attrlistp = NULL;
+ char *eqp, *name, *value;
+ data_type_t type;
+
+ assert(*argip < argc);
+
+ rv = nvlist_alloc(&attrlistp, NV_UNIQUE_NAME_TYPE, 0);
+ if (rv != 0) {
+ dprint(DDEBUG, "%s: nvlist_alloc() failed: rv = %d\n", fn, rv);
+ goto ERR;
+ }
+
+ for (i = *argip; i < argc; i++) {
+ eqp = strchr(argv[i], '=');
+ if (eqp == NULL)
+ goto ERR_ARG;
+ *eqp = '\0';
+ name = argv[i];
+ value = eqp;
+ value++;
+ if (*name == '\0' || *value == '\0')
+ goto ERR_ARG;
+
+ if (pcidr_name2type(name, &type) != 0)
+ type = DATA_TYPE_STRING;
+
+ rv = nvadd(attrlistp, name, value, type);
+ if (rv != 0) {
+ dprint(DDEBUG, "%s: nvadd() failed: attribute \"%s\", "
+ "value = %s, type = %d, rv = %d\n",
+ fn, name, value, (int)type, rv);
+ goto ERR;
+ }
+ *eqp = '=';
+ }
+
+ *argip = i;
+ return (attrlistp);
+
+ /*NOTREACHED*/
+ERR_ARG:
+ if (eqp != NULL)
+ *eqp = '=';
+ dprint(DDEBUG, "%s: bad attribute argv[%d]: \"%s\"\n", fn, i, argv[i]);
+ERR:
+ if (attrlistp != NULL)
+ nvlist_free(attrlistp);
+ return (NULL);
+}
+
+
+static struct {
+ int cmd;
+ char *name;
+} si_cmd_nametab[] = {
+ SI_PLATFORM, "SI_PLATFORM",
+ SI_MACHINE, "SI_MACHINE",
+};
+static int si_cmd_nametab_len =
+ sizeof (si_cmd_nametab) / sizeof (si_cmd_nametab[0]);
+
+static int
+si_name2cmd(char *name)
+{
+ int i;
+
+ for (i = 0; i < si_cmd_nametab_len; i++) {
+ if (strcmp(name, si_cmd_nametab[i].name) == 0)
+ return (si_cmd_nametab[i].cmd);
+ }
+ return (-1);
+}
+
+
+/*
+ * finds occurences of substrings surrounded (delimited) by MACRO_BEGTOK and
+ * MACRO_ENDTOK in <str>;
+ * returns an allocated array of macro_list_t whose length is
+ * returned through <lenp>; array entries will be in order of the occurrence;
+ * else returns NULL if none are found
+ *
+ * macro_list_t members:
+ * char *name = allocated string containing name without macro delimiters
+ * char *beg = location in <str> at _first char_ of MACRO_BEGTOK
+ * char *end = location in <str> at _last char_ of MACRO_ENDTOK
+ */
+static macro_list_t *
+parse_macros(char *const str, int *lenp)
+{
+ char *beg, *end;
+ macro_list_t *lp;
+ size_t size;
+ int i, begtok_len, endtok_len;
+
+ begtok_len = strlen(MACRO_BEGTOK);
+ endtok_len = strlen(MACRO_ENDTOK);
+
+ /* count all occurrences */
+ for (beg = str, i = 0; beg != NULL; i++) {
+ beg = strstr(beg, MACRO_BEGTOK);
+ if (beg == NULL)
+ break;
+ end = strstr(beg + begtok_len, MACRO_ENDTOK);
+ if (end == NULL)
+ break;
+ beg = end + endtok_len;
+ }
+ if (i <= 0)
+ return (NULL);
+
+ *lenp = i;
+ lp = pcidr_malloc(sizeof (macro_list_t) * i);
+
+ for (beg = str, i = 0; i < *lenp; i++) {
+ beg = strstr(beg, MACRO_BEGTOK);
+ assert(beg != NULL);
+ end = strstr(beg + begtok_len, MACRO_ENDTOK);
+ assert(end != NULL);
+
+ size = (end - (beg + begtok_len)) + 1;
+ lp[i].name = pcidr_malloc(size * sizeof (char));
+ (void) strlcpy(lp[i].name, beg + begtok_len, size);
+
+ lp[i].beg = beg;
+ lp[i].end = (end + endtok_len) - 1;
+
+ beg = end + endtok_len;
+ }
+
+ return (lp);
+}
+
+static void
+free_macros(macro_list_t *lp, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ free(lp[i].name);
+ free(lp);
+}
+
+
+/*
+ * evaluates any macros in <opath> and returns allocated string on success;
+ * else NULL
+ */
+static char *
+parse_path(char *const opath)
+{
+ char *fn = "parse_path";
+ char buf[MAXPATHLEN + 1];
+ int bufsize = sizeof (buf) / sizeof (buf[0]);
+ char sibuf[257];
+ int sibufsize = sizeof (sibuf) / sizeof (sibuf[0]);
+ macro_list_t *lp;
+ char *path, *pathp, *pathend;
+ int rv, i, lplen, si_cmd, pathlen, okmacro, si_macro_len;
+ size_t sz;
+
+ /*
+ * make a copy so we can modify it for easier parsing;
+ * lp members will refer to the copy
+ */
+ path = strdup(opath);
+ lp = parse_macros(path, &lplen);
+ if (lp == NULL)
+ return (path);
+
+ rv = 0;
+ si_macro_len = strlen(SI_MACRO);
+ pathlen = strlen(path);
+ pathend = &path[pathlen - 1];
+ pathp = path;
+ buf[0] = '\0';
+ for (i = 0; i < lplen; i++) {
+ lp[i].beg[0] = '\0';
+ sz = strlcat(buf, pathp, bufsize);
+ assert(sz < bufsize);
+
+ okmacro = 0;
+ if (strncmp(lp[i].name, SI_MACRO, si_macro_len) == 0) {
+ si_cmd = si_name2cmd(lp[i].name);
+ assert(si_cmd >= 0);
+
+ rv = sysinfo(si_cmd, sibuf, sibufsize);
+ if (rv < 0) {
+ dprint(DDEBUG, "%s: sysinfo cmd %d failed: "
+ "errno = %d\n", fn, si_cmd, errno);
+ goto OUT;
+ }
+
+ sz = strlcat(buf, sibuf, bufsize);
+ assert(sz < bufsize);
+ okmacro = 1;
+ }
+ /* check for unrecognized macros */
+ assert(okmacro);
+ pathp = lp[i].end + 1;
+ }
+
+ rv = 0;
+ if (pathp < pathend) {
+ sz = strlcat(buf, pathp, bufsize);
+ assert(sz < bufsize);
+ }
+OUT:
+ free_macros(lp, lplen);
+ free(path);
+ if (rv == 0)
+ return (strdup(buf));
+ return (NULL);
+}
+
+
+/*
+ * returns allocated string containing plugin path which caller must free;
+ * else NULL; <attrlistp> is for future use if attributes can be used to
+ * determin plugin
+ */
+/*ARGSUSED*/
+static char *
+find_plugin(nvlist_t *attrlistp)
+{
+ char *fn = "find_plugin";
+ char *path = NULL;
+ int i, rv;
+ struct stat statbuf;
+
+ for (i = 0; i < plugin_paths_len; i++) {
+ path = parse_path(plugin_paths[i]);
+ if (path == NULL) {
+ dprint(DDEBUG, "%s: error parsing path %s\n", fn,
+ path);
+ return (NULL);
+ }
+
+ rv = stat(path, &statbuf);
+ if (rv < 0)
+ dprint(DDEBUG, "%s: stat on %s failed: "
+ "errno = %d\n", fn, path, errno);
+ else if ((statbuf.st_mode & S_IFMT) != S_IFREG)
+ dprint(DDEBUG, "%s: %s is not a regular "
+ "file\n", fn, path);
+ else
+ return (path);
+
+ free(path);
+ }
+ return (NULL);
+}
+
+
+/*
+ * load plugin specified by <path> and pass the proceeding arguments
+ * to the plugin interface; returns 0 on success (likewise for
+ * the plugin function)
+ */
+static int
+do_plugin(char *path, nvlist_t *attrlistp, pcidr_opt_t *optp)
+{
+ char *fn = "do_plugin";
+ int rv;
+ void *dlh;
+ sigset_t set, oset;
+ pcidr_plugin_t fp;
+
+ dlh = dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
+ if (dlh == NULL) {
+ dprint(DDEBUG, "%s: dlopen() failed: %s\n", fn, dlerror());
+ rv = EINVAL;
+ goto OUT;
+ }
+
+ if (sigfillset(&set) != 0) {
+ dprint(DDEBUG, "%s: sigfillset() failed: errno = %d\n", fn,
+ errno);
+ rv = errno;
+ goto OUT;
+ }
+ if (sigprocmask(SIG_BLOCK, &set, &oset) != 0) {
+ dprint(DDEBUG, "%s: blocking signals with sigprocmask() "
+ "failed: errno = %d\n", fn, errno);
+ rv = errno;
+ goto OUT;
+ }
+
+ fp = (pcidr_plugin_t)dlsym(dlh, PCIDR_PLUGIN_SYMSTR);
+ if (fp == NULL) {
+ dprint(DDEBUG, "%s: dlsym() failed: %s\n", fn, dlerror());
+ rv = EINVAL;
+ goto OUT;
+ }
+ rv = fp(attrlistp, optp);
+ if (rv != 0)
+ dprint(DDEBUG, "%s: %s() failed: rv = %d\n", fn,
+ PCIDR_PLUGIN_SYMSTR, rv);
+
+ if (sigprocmask(SIG_SETMASK, &oset, NULL) != 0) {
+ dprint(DDEBUG, "%s: unblocking signals with sigprocmask() "
+ "failed: errno = %d\n", fn, errno);
+ rv = errno;
+ goto OUT;
+ }
+OUT:
+ if (dlh != NULL)
+ (void) dlclose(dlh);
+ return (rv);
+}
+
+
+static void
+exiter()
+{
+ extern FILE *dfp;
+
+ if (nvlistp != NULL)
+ nvlist_free(nvlistp);
+ if (dfp != NULL)
+ (void) fclose(dfp);
+#ifdef DEBUG
+ closelog();
+#endif
+}
+
+
+int
+main(int argc, char **argv)
+{
+ int rv, argi;
+ char *dfile = NULL, *plugin_path = NULL;
+ struct stat statbuf;
+ pcidr_opt_t plugin_opt;
+ char *optstr = NULL;
+
+ extern char *optarg;
+ extern int optind, optopt;
+ int c;
+
+ /*CONSTCOND*/
+ assert(MIN_DLVL == 0);
+ /*CONSTCOND*/
+ assert(MIN_DLVL == DNONE);
+ assert(MAX_DLVL == dpritab_len - 1);
+
+ (void) atexit(exiter);
+ prg = argv[0];
+ dfp = NULL;
+
+#ifdef DEBUG
+ openlog(prg, LOG_PID | LOG_CONS, LOG_DAEMON);
+ dlvl = DWARN;
+ dsys = 1;
+ optstr = "hsv:l:";
+#else
+ dlvl = DNONE;
+ dsys = 0;
+ optstr = "sv:l:";
+#endif
+
+ while ((c = getopt(argc, argv, optstr)) != -1) {
+ switch (c) {
+ case 'h':
+ help();
+ exit(0);
+ break;
+ case 's':
+ dsys = 0;
+ break;
+ case 'v':
+ dlvl = atoi(optarg);
+ break;
+ case 'l':
+ dfile = optarg;
+ break;
+ default:
+ dprint(DWARN, "bad option: %c\n", optopt);
+ return (EINVAL);
+ }
+ }
+
+ /*
+ * [ -l ] do file option first so we can still get msgs if -s is used
+ */
+ if (dfile != NULL) {
+ if (strcmp(dfile, "-") == 0) {
+ /* ignore if stdout is not open/valid */
+ dfp = NULL;
+ if (stdout != NULL &&
+ fstat(fileno(stdout), &statbuf) == 0)
+ dfp = stdout;
+ } else {
+ dfp = fopen(dfile, "a");
+ if (dfp == NULL) {
+ dprint(DWARN, "cannot open %s: %s\n",
+ dfile, strerror(errno));
+ return (EINVAL);
+ }
+ }
+ }
+
+ /* [ -v ] */
+ if (dlvl < MIN_DLVL || dlvl > MAX_DLVL) {
+ dprint(DWARN, "bad arg for -v: %d\n", dlvl);
+ return (EINVAL);
+ }
+
+ argi = optind;
+ if (argi >= argc) {
+ dprint(DWARN, "missing attribute arguments\n");
+ return (EINVAL);
+ }
+
+ nvlistp = parse_argv_attr(argc, argv, &argi);
+ if (nvlistp == NULL) {
+ dprint(DWARN, "attribute parsing error\n");
+ return (EINVAL);
+ }
+
+ (void) memset(&plugin_opt, 0, sizeof (plugin_opt));
+ plugin_opt.logopt.dlvl = dlvl;
+ plugin_opt.logopt.prg = prg;
+ plugin_opt.logopt.dfp = dfp;
+ plugin_opt.logopt.dsys = dsys;
+
+ dprint(DINFO, "=== sysevent attributes ========================\n");
+ pcidr_print_attrlist(DINFO, nvlistp, NULL);
+ dprint(DINFO, "================================================\n");
+
+ plugin_path = find_plugin(nvlistp);
+ if (plugin_path == NULL) {
+ dprint(DWARN, "cannot find plugin\n");
+ return (EINVAL);
+ }
+ dprint(DINFO, "using plugin: %s\n\n", plugin_path);
+
+ rv = do_plugin(plugin_path, nvlistp, &plugin_opt);
+ if (rv != 0) {
+ dprint(DWARN, "plugin %s failed\n", plugin_path);
+ }
+ if (plugin_path != NULL)
+ free(plugin_path);
+ return (rv);
+}
diff --git a/usr/src/cmd/pcidr/pcidr.h b/usr/src/cmd/pcidr/pcidr.h
new file mode 100644
index 0000000000..f23a7971b3
--- /dev/null
+++ b/usr/src/cmd/pcidr/pcidr.h
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _PCIDR_H
+#define _PCIDR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <libnvpair.h>
+#include <config_admin.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PCIDR_MALLOC_CNT 5
+#define PCIDR_MALLOC_TIME 1000000
+
+/* .._SYM and .._SYMSTR must match */
+#define PCIDR_PLUGIN_SYM pcidr_event_handler
+#define PCIDR_PLUGIN_SYMSTR "pcidr_event_handler"
+#define PCIDR_PLUGIN_NAME "pcidr_plugin.so"
+
+
+/*
+ * these ATTRNM_* correspond to the built-in sysevent.conf macros
+ * Note that the "publisher" macro used by syseventd is only a subset (third
+ * colon-delimited field) of the full publisher-id string specified in an
+ * event buffer/message.
+ */
+#define ATTRNM_CLASS "class"
+#define ATTRNM_SUBCLASS "subclass"
+#define ATTRNM_PUB_NAME "publisher"
+
+/* be sure to match with dpritab! */
+typedef enum {DNONE = 0, DWARN, DINFO, DDEBUG} dlvl_t;
+#define MIN_DLVL DNONE
+#define MAX_DLVL DDEBUG
+
+/* default set of DR attributes */
+typedef struct {
+ char *class;
+ char *subclass;
+ char *pub_name;
+ char *dr_req_type;
+ char *dr_ap_id;
+} pcidr_attrs_t;
+
+
+typedef struct {
+ dlvl_t dlvl;
+ char *prg;
+ FILE *dfp;
+ int dsys;
+} pcidr_logopt_t;
+
+typedef struct {
+ pcidr_logopt_t logopt;
+} pcidr_opt_t;
+
+typedef int(*pcidr_plugin_t)(nvlist_t *, pcidr_opt_t *);
+#define PCIDR_PLUGIN_PROTO(a, b) \
+ int PCIDR_PLUGIN_SYM(nvlist_t *a, pcidr_opt_t *b)
+
+
+void *pcidr_malloc(size_t);
+void dprint(dlvl_t, char *, ...);
+int pcidr_name2type(char *, data_type_t *);
+void pcidr_print_attrlist(dlvl_t, nvlist_t *, char *);
+int pcidr_check_string(char *, ...);
+int pcidr_get_attrs(nvlist_t *, pcidr_attrs_t *);
+int pcidr_check_attrs(pcidr_attrs_t *);
+void pcidr_set_logopt(pcidr_logopt_t *);
+
+extern dlvl_t dlvl;
+extern char *prg;
+extern FILE *dfp;
+extern int dsys;
+extern char *prg;
+extern int dpritab_len;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PCIDR_H */
diff --git a/usr/src/cmd/pcidr/pcidr_common.c b/usr/src/cmd/pcidr/pcidr_common.c
new file mode 100644
index 0000000000..31f198520c
--- /dev/null
+++ b/usr/src/cmd/pcidr/pcidr_common.c
@@ -0,0 +1,351 @@
+/*
+ * 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.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/param.h>
+#include <sys/sysevent/eventdefs.h>
+#include <sys/sysevent/dr.h>
+#include <syslog.h>
+#include <libnvpair.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <sys/stat.h>
+#include <dlfcn.h>
+#include <signal.h>
+#include <pcidr.h>
+
+
+/*
+ * How dpritab is used:
+ * dpritab[dlvl_t value] = corresponding syslog priority
+ *
+ * Be careful of some priorities (facility + severity) that get "lost" by
+ * default since they have no syslog.conf entries such as daemon.info and
+ * daemon.debug; see syslog(3C) and syslog.conf(4) for more info
+ */
+int dpritab[] = {LOG_INFO, LOG_WARNING, LOG_NOTICE, LOG_NOTICE};
+int dpritab_len = sizeof (dpritab) / sizeof (dpritab[0]);
+
+/*
+ * the following affects pcidr_set_logopt() which plugins should use to set
+ * these logging options received from the handler
+ */
+dlvl_t dlvl = MIN_DLVL; /* verbosity */
+char *prg = ""; /* program name */
+FILE *dfp = NULL; /* file to output messages to */
+int dsys = 1; /* flag controlling output to syslog */
+
+
+void *
+pcidr_malloc(size_t size)
+{
+ int i = 0;
+ void *buf;
+
+ errno = 0;
+ buf = malloc(size);
+ if (buf != NULL)
+ return (buf);
+
+ for (i = 0; i < PCIDR_MALLOC_CNT; i++) {
+ assert(errno == EAGAIN);
+ if (errno != EAGAIN)
+ exit(errno);
+ (void) usleep(PCIDR_MALLOC_TIME);
+
+ errno = 0;
+ buf = malloc(size);
+ if (buf != NULL)
+ return (buf);
+ }
+
+ assert(buf != NULL);
+ /* exit() in case assertions are disabled (NDEBUG defined) */
+ exit(errno);
+ return (NULL);
+}
+
+
+void
+dprint(dlvl_t lvl, char *fmt, ...)
+{
+ int buflen, rv;
+ char *buf;
+ va_list ap;
+
+ if (dlvl < lvl || (dsys == 0 && dfp == NULL))
+ return;
+
+ va_start(ap, fmt);
+ /*LINTED*/
+ buflen = vsnprintf(NULL, 0, fmt, ap);
+ va_end(ap);
+ if (buflen <= 0)
+ return;
+ buflen++;
+ buf = (char *)pcidr_malloc(sizeof (char) * buflen);
+
+ va_start(ap, fmt);
+ /*LINTED*/
+ rv = vsnprintf(buf, buflen, fmt, ap);
+ va_end(ap);
+ if (rv <= 0) {
+ free(buf);
+ return;
+ }
+
+#ifdef DEBUG
+ if (dsys != 0)
+ syslog(dpritab[lvl], "%s", buf);
+#endif
+ if (dfp != NULL)
+ (void) fprintf(dfp, "%s", buf);
+
+ free(buf);
+}
+
+
+void
+pcidr_set_logopt(pcidr_logopt_t *logopt)
+{
+ dlvl = logopt->dlvl;
+ prg = logopt->prg;
+ dfp = logopt->dfp;
+ dsys = logopt->dsys;
+}
+
+
+/*
+ * if <name> is recognized, function will return its type through <typep> and
+ * return 0; else function will return non-zero
+ */
+int
+pcidr_name2type(char *name, data_type_t *typep)
+{
+ /* string type */
+ if (strcmp(name, ATTRNM_CLASS) == 0 ||
+ strcmp(name, ATTRNM_SUBCLASS) == 0 ||
+ strcmp(name, ATTRNM_PUB_NAME) == 0 ||
+ strcmp(name, DR_REQ_TYPE) == 0 ||
+ strcmp(name, DR_AP_ID) == 0) {
+ *typep = DATA_TYPE_STRING;
+ return (0);
+ }
+
+ return (1);
+}
+
+
+void
+pcidr_print_attrlist(dlvl_t lvl, nvlist_t *attrlistp, char *prestr)
+{
+ char *fn = "pcidr_print_attrlist";
+ nvpair_t *nvpairp;
+ char *valstr, *name;
+ data_type_t type;
+ int rv;
+
+ if (prestr == NULL)
+ prestr = "";
+
+ nvpairp = NULL;
+ while ((nvpairp = nvlist_next_nvpair(attrlistp, nvpairp)) != NULL) {
+ type = nvpair_type(nvpairp);
+ name = nvpair_name(nvpairp);
+
+ switch (type) {
+ case DATA_TYPE_STRING:
+ rv = nvpair_value_string(nvpairp, &valstr);
+ if (rv != 0) {
+ dprint(lvl, "%s: nvpair_value_string() "
+ "failed: name = %s, rv = %d\n",
+ fn, name, rv);
+ continue;
+ }
+ break;
+ default:
+ dprint(lvl, "%s: unsupported type: name = %s, "
+ "type = 0x%x\n", fn, name, (int)type);
+ continue;
+ }
+ dprint(lvl, "%s%s = %s\n", prestr, name, valstr);
+ }
+}
+
+
+/*
+ * if one of the args matches <valstr>, return 0; else return non-zero
+ * args list must be NULL terminated;
+ * if args list is empty, this will return 0 if <valstr> is NOT empty
+ */
+int
+pcidr_check_string(char *valstr, ...)
+{
+ va_list ap;
+ int rv;
+ char *argstr;
+
+ assert(valstr != NULL);
+ rv = 1;
+ va_start(ap, valstr);
+ if (va_arg(ap, char *) == NULL) {
+ if (valstr[0] != '\0')
+ rv = 0;
+ goto OUT;
+ }
+
+ va_start(ap, valstr);
+ while ((argstr = va_arg(ap, char *)) != NULL) {
+ if (strcmp(argstr, valstr) == 0) {
+ rv = 0;
+ break;
+ }
+ }
+OUT:
+ va_end(ap);
+ return (rv);
+}
+
+
+/*
+ * dr attribute values that the default plugin checks for;
+ * other plugins may also use this if they support a superset of these
+ * values.
+ * returns 0 if valid, else non-zero
+ */
+int
+pcidr_check_attrs(pcidr_attrs_t *drp)
+{
+ char *fn = "pcidr_check_attrs";
+ int rv = 0;
+ char *val, *name;
+
+ name = ATTRNM_CLASS;
+ val = drp->class;
+ if (pcidr_check_string(val, EC_DR, NULL) != 0) {
+ dprint(DDEBUG, "%s: attribute \"%s\" has invalid value = %s\n",
+ fn, name, val);
+ rv = 1;
+ }
+
+ name = ATTRNM_SUBCLASS;
+ val = drp->subclass;
+ if (pcidr_check_string(val, ESC_DR_REQ, NULL) != 0) {
+ dprint(DDEBUG, "%s: attribute \"%s\" has invalid value = %s\n",
+ fn, name, val);
+ rv = 1;
+ }
+
+ name = ATTRNM_PUB_NAME;
+ val = drp->pub_name;
+ if (pcidr_check_string(val, NULL) != 0) {
+ dprint(DDEBUG, "%s: attribute \"%s\" is empty\n",
+ fn, name, val);
+ rv = 1;
+ }
+
+ name = DR_REQ_TYPE;
+ val = drp->dr_req_type;
+ if (pcidr_check_string(val, DR_REQ_INCOMING_RES, DR_REQ_OUTGOING_RES,
+ NULL) != 0) {
+ dprint(DDEBUG, "%s: attribute \"%s\" has invalid value = %s\n",
+ fn, name, val);
+ rv = 1;
+ }
+
+ name = DR_AP_ID;
+ val = drp->dr_ap_id;
+ if (pcidr_check_string(drp->dr_ap_id, NULL) != 0) {
+ dprint(DDEBUG, "%s: attribute \"%s\" is empty\n",
+ fn, name, val);
+ rv = 1;
+ }
+
+ return (rv);
+}
+
+
+/*
+ * get dr attributes from <listp> for the default plugin and returns
+ * them through <drp>;
+ * returns 0 on success
+ */
+int
+pcidr_get_attrs(nvlist_t *attrlistp, pcidr_attrs_t *drp)
+{
+ char *fn = "pcidr_get_attrs";
+ char *name;
+ int r, rv = 0;
+
+ name = ATTRNM_CLASS;
+ r = nvlist_lookup_string(attrlistp, name, &drp->class);
+ if (r != 0) {
+ dprint(DDEBUG, "%s: nvlist_lookup_string() failed for "
+ "attribute \"%s\": rv = %d\n", fn, name, r);
+ rv = r;
+ }
+
+ name = ATTRNM_SUBCLASS;
+ r = nvlist_lookup_string(attrlistp, name, &drp->subclass);
+ if (r != 0) {
+ dprint(DDEBUG, "%s: nvlist_lookup_string() failed for "
+ "attribute \"%s\": rv = %d\n", fn, name, r);
+ rv = r;
+ }
+
+ name = ATTRNM_PUB_NAME;
+ r = nvlist_lookup_string(attrlistp, name, &drp->pub_name);
+ if (r != 0) {
+ dprint(DDEBUG, "%s: nvlist_lookup_string() failed for "
+ "attribute \"%s\": rv = %d\n", fn, name, r);
+ rv = r;
+ }
+
+ name = DR_REQ_TYPE;
+ r = nvlist_lookup_string(attrlistp, name, &drp->dr_req_type);
+ if (r != 0) {
+ dprint(DDEBUG, "%s: nvlist_lookup_string() failed for "
+ "attribute \"%s\": rv = %d\n", fn, name, r);
+ rv = r;
+ }
+
+ name = DR_AP_ID;
+ r = nvlist_lookup_string(attrlistp, name, &drp->dr_ap_id);
+ if (r != 0) {
+ dprint(DDEBUG, "%s: nvlist_lookup_string() failed for "
+ "attribute \"%s\": rv = %d\n", fn, name, r);
+ rv = r;
+ }
+
+ return (rv);
+}
diff --git a/usr/src/cmd/pcidr/plugins/Makefile b/usr/src/cmd/pcidr/plugins/Makefile
new file mode 100755
index 0000000000..98a61d7d3a
--- /dev/null
+++ b/usr/src/cmd/pcidr/plugins/Makefile
@@ -0,0 +1,52 @@
+#
+# 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.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# cmd/pcidr/plugins/Makefile
+#
+
+.PARALLEL:
+
+SUBDIRS = default
+
+include $(SRC)/cmd/Makefile.cmd
+
+all := TARGET = all
+install := TARGET = install
+clean := TARGET = clean
+clobber := TARGET = clobber
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber lint install: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include $(SRC)/cmd/Makefile.targ
diff --git a/usr/src/cmd/pcidr/plugins/Makefile.targ b/usr/src/cmd/pcidr/plugins/Makefile.targ
new file mode 100755
index 0000000000..5530fee78f
--- /dev/null
+++ b/usr/src/cmd/pcidr/plugins/Makefile.targ
@@ -0,0 +1,37 @@
+#
+# 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.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# cmd/pcidr/plugins/Makefile.targ
+#
+
+# unlike cmd/Makefile.targ, lib/Makefile.targ install targets do not depend
+# on or create parent directories
+#
+$(ROOTLIBS): $(ROOTLIBDIR)
+
+$(ROOTLIBDIR):
+ $(INS.dir)
diff --git a/usr/src/cmd/pcidr/plugins/default/Makefile b/usr/src/cmd/pcidr/plugins/default/Makefile
new file mode 100755
index 0000000000..2a8ced542c
--- /dev/null
+++ b/usr/src/cmd/pcidr/plugins/default/Makefile
@@ -0,0 +1,93 @@
+#
+# 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.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# cmd/pcidr/plugins/default/Makefile
+#
+
+.PARALLEL:
+
+#############################################################################
+
+NAME = pcidr_plugin
+LIBRARY = $(NAME).a
+VERS =
+
+TOPOBJECTS = pcidr_common.o
+LOCOBJECTS = $(NAME).o pcidr_cfga.o
+OBJECTS = $(LOCOBJECTS) $(TOPOBJECTS)
+
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/cmd/pcidr/Makefile.com
+#############################################################################
+
+THISDIR = $(TOP)/plugins/default
+
+# SRCS is used by the lintcheck rule and is defined as
+# $(OBJECTS:%.o=$(SRCDIR)/%.c) where SRCDIR is this directory; set SRCS to a
+# list of source paths if it differ from the default
+#
+SRCS = $(TOPOBJECTS:%.o=$(TOP)/%.c) $(LOCOBJECTS:%.o=$(SRCDIR)/%.c)
+
+LIBS = $(DYNLIB)
+
+LDLIBS += -lcfgadm -lnvpair
+
+HDRSRCS_SH = ls -1 $(THISDIR)/*.h
+HDRSRCS = $(HDRSRCS_SH:sh)
+CPPFLAGS += -I$(THISDIR)
+
+# override LIBLINKS so that ROOTLIBS or anything else won't match the install
+# target "$(ROOTLIBDIR)/$(LIBLINKS)"
+#
+LIBLINKS = __no_liblinks__
+
+.KEEP_STATE:
+#############################################################################
+
+all: $(LIBS)
+install: $(ROOTLIBS)
+clean:
+clobber:
+lint: lintcheck
+
+$(ROOTLIBS): all
+
+# Note that we can't do:
+# $(TOPOBJECTS:%=objs/%) := SRCDIR = $(TOP)
+# and let the make do the rest because the man page states:
+# "Notice that if a conditional macro is referred to in a dependency list,
+# the $ must be delayed (use $$ instead)."
+#
+# So we must add new targets for our TOPOBJECTS items but follow
+# the existing pic/*.o and objs/*.o rules in lib/Makefile.targ
+#
+objs/%.o pics/%.o: $(TOP)/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+include $(SRC)/lib/Makefile.targ
+include ../Makefile.targ
diff --git a/usr/src/cmd/pcidr/plugins/default/pcidr_cfga.c b/usr/src/cmd/pcidr/plugins/default/pcidr_cfga.c
new file mode 100644
index 0000000000..631c602a8f
--- /dev/null
+++ b/usr/src/cmd/pcidr/plugins/default/pcidr_cfga.c
@@ -0,0 +1,330 @@
+/*
+ * 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.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <string.h>
+#include <sys/param.h>
+#include <assert.h>
+#include <pcidr.h>
+#include <pcidr_cfga.h>
+
+
+/*
+ * misc config_admin(3cfgadm) related routines
+ */
+
+static struct {
+ cfga_stat_t stat;
+ char *name;
+} pcidr_cfga_stat_nametab[] = {
+ {CFGA_STAT_NONE, "CFGA_STAT_NONE"},
+ {CFGA_STAT_EMPTY, "CFGA_STAT_EMPTY"},
+ {CFGA_STAT_DISCONNECTED, "CFGA_STAT_DISCONNECTED"},
+ {CFGA_STAT_CONNECTED, "CFGA_STAT_CONNECTED"},
+ {CFGA_STAT_UNCONFIGURED, "CFGA_STAT_UNCONFIGURED"},
+ {CFGA_STAT_CONFIGURED, "CFGA_STAT_CONFIGURED"},
+};
+static int pcidr_cfga_stat_nametab_len =
+ sizeof (pcidr_cfga_stat_nametab) / sizeof (pcidr_cfga_stat_nametab[0]);
+
+char *
+pcidr_cfga_stat_name(cfga_stat_t val)
+{
+ int i;
+
+ for (i = 0; i < pcidr_cfga_stat_nametab_len; i++) {
+ if (pcidr_cfga_stat_nametab[i].stat == val)
+ return (pcidr_cfga_stat_nametab[i].name);
+ }
+ return (NULL);
+}
+
+
+static struct {
+ cfga_stat_t cmd;
+ char *name;
+} pcidr_cfga_cmd_nametab[] = {
+ {CFGA_CMD_NONE, "CFGA_CMD_NONE"},
+ {CFGA_CMD_LOAD, "CFGA_CMD_LOAD"},
+ {CFGA_CMD_UNLOAD, "CFGA_CMD_UNLOAD"},
+ {CFGA_CMD_CONNECT, "CFGA_CMD_CONNECT"},
+ {CFGA_CMD_DISCONNECT, "CFGA_CMD_DISCONNECT"},
+ {CFGA_CMD_CONFIGURE, "CFGA_CMD_CONFIGURE"},
+ {CFGA_CMD_UNCONFIGURE, "CFGA_CMD_UNCONFIGURE"},
+};
+static int pcidr_cfga_cmd_nametab_len =
+ sizeof (pcidr_cfga_cmd_nametab) / sizeof (pcidr_cfga_cmd_nametab[0]);
+
+char *
+pcidr_cfga_cmd_name(cfga_cmd_t val)
+{
+ int i;
+
+ for (i = 0; i < pcidr_cfga_cmd_nametab_len; i++) {
+ if (pcidr_cfga_cmd_nametab[i].cmd == val)
+ return (pcidr_cfga_cmd_nametab[i].name);
+ }
+ return (NULL);
+}
+
+
+static struct {
+ cfga_cond_t cond;
+ char *name;
+} pcidr_cfga_cond_nametab[] = {
+ {CFGA_COND_UNKNOWN, "CFGA_COND_UNKNOWN"},
+ {CFGA_COND_OK, "CFGA_COND_OK"},
+ {CFGA_COND_FAILING, "CFGA_COND_FAILING"},
+ {CFGA_COND_FAILED, "CFGA_COND_FAILED"},
+ {CFGA_COND_UNUSABLE, "CFGA_COND_UNUSABLE"},
+};
+static int pcidr_cfga_cond_nametab_len =
+ sizeof (pcidr_cfga_cond_nametab) / sizeof (pcidr_cfga_cond_nametab[0]);
+
+char *
+pcidr_cfga_cond_name(cfga_cond_t val)
+{
+ int i;
+
+ for (i = 0; i < pcidr_cfga_cond_nametab_len; i++) {
+ if (pcidr_cfga_cond_nametab[i].cond == val)
+ return (pcidr_cfga_cond_nametab[i].name);
+ }
+ return (NULL);
+}
+
+
+static struct {
+ cfga_err_t err;
+ char *name;
+} pcidr_cfga_err_nametab[] = {
+ {CFGA_OK, "CFGA_OK"},
+ {CFGA_NACK, "CFGA_NACK"},
+ {CFGA_NOTSUPP, "CFGA_NOTSUPP"},
+ {CFGA_OPNOTSUPP, "CFGA_OPNOTSUPP"},
+ {CFGA_PRIV, "CFGA_PRIV"},
+ {CFGA_BUSY, "CFGA_BUSY"},
+ {CFGA_SYSTEM_BUSY, "CFGA_SYSTEM_BUSY"},
+ {CFGA_DATA_ERROR, "CFGA_DATA_ERROR"},
+ {CFGA_LIB_ERROR, "CFGA_LIB_ERROR"},
+ {CFGA_NO_LIB, "CFGA_NO_LIB"},
+ {CFGA_INSUFFICENT_CONDITION, "CFGA_INSUFFICENT_CONDITION"},
+ {CFGA_INVAL, "CFGA_INVAL"},
+ {CFGA_ERROR, "CFGA_ERROR"},
+ {CFGA_APID_NOEXIST, "CFGA_APID_NOEXIST"},
+ {CFGA_ATTR_INVAL, "CFGA_ATTR_INVAL"},
+};
+static int pcidr_cfga_err_nametab_len =
+ sizeof (pcidr_cfga_err_nametab) / sizeof (pcidr_cfga_err_nametab[0]);
+
+char *
+pcidr_cfga_err_name(cfga_err_t val)
+{
+ int i;
+
+ for (i = 0; i < pcidr_cfga_err_nametab_len; i++) {
+ if (pcidr_cfga_err_nametab[i].err == val)
+ return (pcidr_cfga_err_nametab[i].name);
+ }
+ return (NULL);
+}
+
+
+void
+pcidr_print_cfga(dlvl_t lvl, cfga_list_data_t *datap, char *prestr)
+{
+ char *str;
+
+ if (prestr == NULL)
+ prestr = "";
+
+ dprint(lvl, "%slogical APID = %s\n", prestr, datap->ap_log_id);
+ dprint(lvl, "%sphyiscal APID = %s\n", prestr, datap->ap_phys_id);
+ dprint(lvl, "%sAP class = %s\n", prestr, datap->ap_class);
+
+ str = pcidr_cfga_stat_name(datap->ap_r_state);
+ if (str == NULL)
+ str = "(unrecognized cfga_stat_t value!)";
+ dprint(lvl, "%sAP receptacle state = %s\n", prestr, str);
+
+ str = pcidr_cfga_stat_name(datap->ap_o_state);
+ if (str == NULL)
+ str = "(unrecognized cfga_stat_t value!)";
+ dprint(lvl, "%sAP occupant state = %s\n", prestr, str);
+
+ str = pcidr_cfga_cond_name(datap->ap_cond);
+ if (str == NULL)
+ str = "(unrecognized cfga_cond_t value!)";
+ dprint(lvl, "%sAP condition = %s\n", prestr, str);
+
+ dprint(lvl, "%sAP busy indicator = %d\n", prestr, datap->ap_busy);
+
+ str = ctime(&datap->ap_status_time);
+ str[strlen(str) - 1] = '\0'; /* get rid of newline */
+ dprint(lvl, "%sAP last change time = %ld (%s)\n", prestr,
+ datap->ap_status_time, str);
+
+ dprint(lvl, "%sAP info = %s\n", prestr, datap->ap_info);
+ dprint(lvl, "%sAP type = %s\n", prestr, datap->ap_type);
+}
+
+
+/*
+ * for use with config_admin(3cfgadm) functions in their
+ * <struct cfga_msg *msgp> parameter
+ */
+int
+pcidr_cfga_msg_func(void *datap, const char *msg)
+{
+ pcidr_cfga_msg_data_t *dp = (pcidr_cfga_msg_data_t *)datap;
+ char *prestr = dp->prestr;
+
+ if (prestr == NULL)
+ prestr = "";
+
+ dprint(dp->dlvl, "%s%s", prestr, msg);
+ return (0);
+}
+
+
+/*
+ * for use with config_admin(3cfgadm) functions in their
+ * <struct cfga_confirm *confp> parameter
+ */
+/*ARGSUSED*/
+int
+pcidr_cfga_confirm_func(void *datap, const char *msg)
+{
+ return (1);
+}
+
+
+/*
+ * returns 0 if successful, -1 if unusuccesful, 1 if the AP already had
+ * <cmd> performed on it
+ */
+int
+pcidr_cfga_do_cmd(cfga_cmd_t cmd, cfga_list_data_t *cfga_listp)
+{
+ char *fn = "pcidr_cfga_do_cmd";
+ int rv, i, j;
+ char *cmdnm, *cfga_errstr, *apid, *str;
+ int cmdarr[2];
+ int cmdarr_len = sizeof (cmdarr) / sizeof (cmdarr[0]);
+
+ struct cfga_msg cfga_msg;
+ pcidr_cfga_msg_data_t cfga_msg_data;
+ struct cfga_confirm cfga_confirm;
+ cfga_flags_t cfga_flags;
+
+ cmdnm = pcidr_cfga_cmd_name(cmd);
+ assert(cmdnm != NULL);
+
+ apid = cfga_listp->ap_phys_id;
+ cfga_msg_data.dlvl = DDEBUG;
+ cfga_msg_data.prestr = "pcidr_cfga_do_cmd(msg): ";
+ cfga_msg.message_routine = pcidr_cfga_msg_func;
+ cfga_msg.appdata_ptr = (void *)&cfga_msg_data;
+ cfga_confirm.confirm = pcidr_cfga_confirm_func;
+ cfga_confirm.appdata_ptr = NULL;
+ cfga_flags = CFGA_FLAG_VERBOSE;
+
+ if (cfga_listp->ap_busy != 0) {
+ dprint(DDEBUG, "%s: apid = %s is busy\n",
+ fn, cfga_listp->ap_phys_id);
+ return (-1);
+ }
+
+ /*
+ * explicitly perform each step that would otherwise be done
+ * implicitly by cfgadm to isolate errors
+ */
+ j = 0;
+ switch (cmd) {
+ case CFGA_CMD_CONFIGURE:
+ if (cfga_listp->ap_o_state < CFGA_STAT_CONNECTED) {
+ cmdarr[j] = CFGA_CMD_CONNECT;
+ j++;
+ }
+ if (cfga_listp->ap_o_state < CFGA_STAT_CONFIGURED) {
+ cmdarr[j] = CFGA_CMD_CONFIGURE;
+ j++;
+ }
+ if (cfga_listp->ap_o_state >= CFGA_STAT_CONFIGURED)
+ goto ALREADY;
+ break;
+ case CFGA_CMD_DISCONNECT:
+ if (cfga_listp->ap_o_state >= CFGA_STAT_CONFIGURED) {
+ cmdarr[j] = CFGA_CMD_UNCONFIGURE;
+ j++;
+ }
+ if (cfga_listp->ap_o_state >= CFGA_STAT_CONNECTED) {
+ cmdarr[j] = CFGA_CMD_DISCONNECT;
+ j++;
+ }
+ if (cfga_listp->ap_r_state <= CFGA_STAT_DISCONNECTED)
+ goto ALREADY;
+ break;
+ default:
+ dprint(DDEBUG, "%s: unsupported cmd %d\n", cmd);
+ return (-1);
+ }
+ assert(j <= cmdarr_len);
+
+ for (i = 0; i < j; i++) {
+ cmd = cmdarr[i];
+ cmdnm = pcidr_cfga_cmd_name(cmd);
+ assert(cmdnm != NULL);
+
+ rv = config_change_state(cmd, 1, &apid, NULL, &cfga_confirm,
+ &cfga_msg, &cfga_errstr, cfga_flags);
+ if (rv != CFGA_OK) {
+ dprint(DDEBUG, "%s: command %s failed on apid %s",
+ fn, cmdnm, apid);
+
+ str = pcidr_cfga_err_name(rv);
+ if (str == NULL)
+ str = "unrecognized rv!";
+ dprint(DDEBUG, ": rv = %d (%s)", rv, str);
+
+ if (cfga_errstr != NULL) {
+ dprint(DDEBUG, ", error string = "
+ "\"%s\"", cfga_errstr);
+ free(cfga_errstr);
+ }
+ dprint(DDEBUG, "\n");
+ return (-1);
+ }
+ }
+
+ return (0);
+ /*NOTREACHED*/
+ALREADY:
+ dprint(DDEBUG, "%s: command %s already done on apid %s\n",
+ fn, cmdnm, apid);
+ return (1);
+}
diff --git a/usr/src/cmd/pcidr/plugins/default/pcidr_cfga.h b/usr/src/cmd/pcidr/plugins/default/pcidr_cfga.h
new file mode 100644
index 0000000000..4465a5c3bc
--- /dev/null
+++ b/usr/src/cmd/pcidr/plugins/default/pcidr_cfga.h
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _PCIDR_CFGA_H
+#define _PCIDR_CFGA_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <config_admin.h>
+#include <pcidr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void pcidr_print_cfga(dlvl_t, cfga_list_data_t *, char *);
+char *pcidr_cfga_stat_name(cfga_stat_t);
+char *pcidr_cfga_cmd_name(cfga_cmd_t);
+char *pcidr_cfga_cond_name(cfga_cond_t);
+char *pcidr_cfga_err_name(cfga_err_t);
+int pcidr_cfga_do_cmd(cfga_cmd_t, cfga_list_data_t *);
+
+typedef struct {
+ dlvl_t dlvl;
+ char *prestr;
+} pcidr_cfga_msg_data_t;
+int pcidr_cfga_msg_func(void *, const char *);
+int pcidr_cfga_confirm_func(void *, const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PCIDR_CFGA_H */
diff --git a/usr/src/cmd/pcidr/plugins/default/pcidr_plugin.c b/usr/src/cmd/pcidr/plugins/default/pcidr_plugin.c
new file mode 100644
index 0000000000..c321cfe01c
--- /dev/null
+++ b/usr/src/cmd/pcidr/plugins/default/pcidr_plugin.c
@@ -0,0 +1,144 @@
+/*
+ * 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.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+#include <errno.h>
+#include <sys/param.h>
+#include <sys/systeminfo.h>
+#include <sys/sysevent/eventdefs.h>
+#include <sys/sysevent/dr.h>
+#include <syslog.h>
+#include <libnvpair.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <sys/stat.h>
+#include <dlfcn.h>
+#include <pcidr.h>
+#include <pcidr_cfga.h>
+
+
+PCIDR_PLUGIN_PROTO(attrlistp, optp)
+{
+ char *fn = PCIDR_PLUGIN_SYMSTR;
+ int rv = 0;
+ char *cfga_errstr = NULL;
+ char *str, *apid;
+ cfga_list_data_t *cfga_listp = NULL;
+ cfga_cmd_t cmd;
+ int cfga_list_len;
+ pcidr_attrs_t dr;
+
+ pcidr_set_logopt(&optp->logopt);
+
+ if (pcidr_get_attrs(attrlistp, &dr) != 0 ||
+ pcidr_check_attrs(&dr) != 0) {
+ dprint(DWARN, "%s: invalid or missing attributes\n", fn);
+ return (EINVAL);
+ }
+
+ /*
+ * get state of APID; enforce the cfgadm pci plugin implementation of
+ * returning one matching AP per supplied apid string
+ */
+ rv = config_list_ext(1, &dr.dr_ap_id, &cfga_listp, &cfga_list_len,
+ NULL, NULL, &cfga_errstr, CFGA_FLAG_LIST_ALL);
+ if (rv != CFGA_OK) {
+ str = pcidr_cfga_err_name(rv);
+ if (str == NULL)
+ str = "unrecognized rv!";
+ dprint(DDEBUG, "%s: config_list_ext() on apid = \"%s\" "
+ "failed: rv = %d (%s)", fn, dr.dr_ap_id, rv, str);
+
+ if (cfga_errstr != NULL) {
+ dprint(DDEBUG, ", error string = \"%s\"",
+ cfga_errstr);
+ free(cfga_errstr);
+ }
+ dprint(DDEBUG, "\n");
+ rv = EINVAL;
+ goto OUT;
+ }
+ if (cfga_list_len != 1) {
+ dprint(DWARN, "%s: invalid condition - more than one AP was "
+ "found for the APID \"%s\"\n", fn, dr.dr_ap_id);
+ rv = EINVAL;
+ goto OUT;
+ }
+
+ /*
+ * perform DR
+ */
+ dprint(DINFO, "%s: showing info and performing DR on APID(s) "
+ "matching \"%s\"\n", fn, dr.dr_ap_id);
+
+ cmd = CFGA_CMD_NONE;
+ dprint(DINFO, "===========================================\n", fn);
+ pcidr_print_cfga(DINFO, &cfga_listp[0], " .. ");
+ apid = cfga_listp[0].ap_phys_id;
+
+ if (strcmp(dr.dr_req_type, DR_REQ_OUTGOING_RES) == 0) {
+ cmd = CFGA_CMD_DISCONNECT;
+ dprint(DINFO, "%s: disconnecting ...\n", fn, apid);
+
+ rv = pcidr_cfga_do_cmd(cmd, &cfga_listp[0]);
+ if (rv < 0) {
+ dprint(DINFO, "%s: disconnect FAILED\n", fn);
+ rv = EIO;
+ }
+ else
+ dprint(DINFO, "%s: disconnect OK\n", fn);
+
+ goto OUT;
+ }
+ if (strcmp(dr.dr_req_type, DR_REQ_INCOMING_RES) == 0) {
+ cmd = CFGA_CMD_CONFIGURE;
+ dprint(DINFO, "%s: configuring ...\n", fn, apid);
+
+ rv = pcidr_cfga_do_cmd(cmd, &cfga_listp[0]);
+ if (rv < 0) {
+ dprint(DINFO, "%s: configure FAILED\n", fn);
+ rv = EIO;
+ } else
+ dprint(DINFO, "%s: configure OK\n", fn);
+
+ goto OUT;
+ }
+
+ /* we should not get here if pcidr_check_attrs() is correct */
+ dprint(DWARN, "%s: invalid dr_req_type = %s\n", fn, dr.dr_req_type);
+ assert(cmd != CFGA_CMD_NONE);
+ return (EINVAL);
+ /*NOTREACHED*/
+OUT:
+ if (cfga_listp != NULL)
+ free(cfga_listp);
+ return (rv);
+}