diff options
author | johnny <none@none> | 2005-11-10 12:33:07 -0800 |
---|---|---|
committer | johnny <none@none> | 2005-11-10 12:33:07 -0800 |
commit | 70025d765b044c6d8594bb965a2247a61e991a99 (patch) | |
tree | ecf0115912221f8be4400ca9bf4d04802b8e0355 /usr/src/cmd/pcidr | |
parent | 4610e4a00999c6d2291b3fc263926b890ec500a5 (diff) | |
download | illumos-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-x | usr/src/cmd/pcidr/Makefile | 79 | ||||
-rwxr-xr-x | usr/src/cmd/pcidr/Makefile.com | 52 | ||||
-rw-r--r-- | usr/src/cmd/pcidr/etc/Makefile | 50 | ||||
-rw-r--r-- | usr/src/cmd/pcidr/etc/SUNW,EC_dr,ESC_dr_req,sysevent.conf | 29 | ||||
-rwxr-xr-x | usr/src/cmd/pcidr/pcidr.c | 656 | ||||
-rw-r--r-- | usr/src/cmd/pcidr/pcidr.h | 109 | ||||
-rw-r--r-- | usr/src/cmd/pcidr/pcidr_common.c | 351 | ||||
-rwxr-xr-x | usr/src/cmd/pcidr/plugins/Makefile | 52 | ||||
-rwxr-xr-x | usr/src/cmd/pcidr/plugins/Makefile.targ | 37 | ||||
-rwxr-xr-x | usr/src/cmd/pcidr/plugins/default/Makefile | 93 | ||||
-rw-r--r-- | usr/src/cmd/pcidr/plugins/default/pcidr_cfga.c | 330 | ||||
-rw-r--r-- | usr/src/cmd/pcidr/plugins/default/pcidr_cfga.h | 57 | ||||
-rw-r--r-- | usr/src/cmd/pcidr/plugins/default/pcidr_plugin.c | 144 |
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); +} |