summaryrefslogtreecommitdiff
path: root/usr/src/lib
diff options
context:
space:
mode:
authorvikram <none@none>2007-08-09 21:43:47 -0700
committervikram <none@none>2007-08-09 21:43:47 -0700
commit25e8c5aa2b496d9026e958ac731a610167574f59 (patch)
tree48d445f55e23f769f3981231d5b06b0b35505b33 /usr/src/lib
parentffcd51f34e6cd303b9745909c4632da63426be17 (diff)
downloadillumos-joyent-25e8c5aa2b496d9026e958ac731a610167574f59.tar.gz
PSARC 2007/290 Retire Agent for I/O Devices
6464720 Deliver a FMA I/O retire agent --HG-- rename : usr/src/cmd/fm/modules/common/io-retire/ior_main.c => deleted_files/usr/src/cmd/fm/modules/common/io-retire/ior_main.c
Diffstat (limited to 'usr/src/lib')
-rw-r--r--usr/src/lib/cfgadm_plugins/scsi/common/cfga_list.c28
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/dev.c5
-rw-r--r--usr/src/lib/libcontract/Makefile8
-rw-r--r--usr/src/lib/libcontract/Makefile.com6
-rw-r--r--usr/src/lib/libcontract/common/device.c177
-rw-r--r--usr/src/lib/libcontract/common/device_dump.c103
-rw-r--r--usr/src/lib/libcontract/common/device_dump.h43
-rw-r--r--usr/src/lib/libcontract/common/libcontract.c31
-rw-r--r--usr/src/lib/libcontract/common/libcontract.h25
-rw-r--r--usr/src/lib/libcontract/common/libcontract_impl.h10
-rw-r--r--usr/src/lib/libcontract/common/libcontract_priv.c32
-rw-r--r--usr/src/lib/libcontract/common/libcontract_priv.h8
-rw-r--r--usr/src/lib/libcontract/common/mapfile-vers14
-rw-r--r--usr/src/lib/libdevinfo/Makefile.com4
-rw-r--r--usr/src/lib/libdevinfo/devinfo.c6
-rw-r--r--usr/src/lib/libdevinfo/devinfo_retire.c785
-rw-r--r--usr/src/lib/libdevinfo/libdevinfo.h18
-rw-r--r--usr/src/lib/libdevinfo/mapfile-vers3
-rw-r--r--usr/src/lib/librcm/librcm.h5
-rw-r--r--usr/src/lib/librcm/librcm_impl.h11
20 files changed, 1271 insertions, 51 deletions
diff --git a/usr/src/lib/cfgadm_plugins/scsi/common/cfga_list.c b/usr/src/lib/cfgadm_plugins/scsi/common/cfga_list.c
index 6a5f716282..78910e04b1 100644
--- a/usr/src/lib/cfgadm_plugins/scsi/common/cfga_list.c
+++ b/usr/src/lib/cfgadm_plugins/scsi/common/cfga_list.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -383,13 +382,18 @@ out:
}
+struct bus_state {
+ int b_state;
+ int b_retired;
+};
+
static scfga_ret_t
do_stat_bus(scfga_list_t *lap, int limited_bus_stat)
{
cfga_list_data_t *clp = NULL;
ldata_list_t *listp = NULL;
int l_errno = 0;
- uint_t devinfo_state = 0;
+ struct bus_state bstate = {0};
walkarg_t u;
scfga_ret_t ret;
@@ -399,10 +403,10 @@ do_stat_bus(scfga_list_t *lap, int limited_bus_stat)
u.node_args.flags = 0;
u.node_args.fcn = get_bus_state;
- ret = walk_tree(lap->apidp->hba_phys, &devinfo_state, DINFOPROP, &u,
+ ret = walk_tree(lap->apidp->hba_phys, &bstate, DINFOPROP, &u,
SCFGA_WALK_NODE, &l_errno);
if (ret == SCFGA_OK) {
- lap->hba_rstate = bus_devinfo_to_recep_state(devinfo_state);
+ lap->hba_rstate = bus_devinfo_to_recep_state(bstate.b_state);
} else {
lap->hba_rstate = CFGA_STAT_NONE;
}
@@ -428,7 +432,8 @@ do_stat_bus(scfga_list_t *lap, int limited_bus_stat)
clp->ap_class[0] = '\0'; /* Filled by libcfgadm */
clp->ap_r_state = lap->hba_rstate;
clp->ap_o_state = CFGA_STAT_NONE; /* filled in later by the plug-in */
- clp->ap_cond = CFGA_COND_UNKNOWN;
+ clp->ap_cond =
+ (bstate.b_retired) ? CFGA_COND_FAILED : CFGA_COND_UNKNOWN;
clp->ap_busy = 0;
clp->ap_status_time = (time_t)-1;
clp->ap_info[0] = '\0';
@@ -446,9 +451,10 @@ do_stat_bus(scfga_list_t *lap, int limited_bus_stat)
static int
get_bus_state(di_node_t node, void *arg)
{
- uint_t *di_statep = (uint_t *)arg;
+ struct bus_state *bsp = (struct bus_state *)arg;
- *di_statep = di_state(node);
+ bsp->b_state = di_state(node);
+ bsp->b_retired = di_retired(node);
return (DI_WALK_TERMINATE);
}
@@ -512,7 +518,7 @@ do_stat_dev(
clp->ap_class[0] = '\0'; /* Filled in by libcfgadm */
clp->ap_r_state = lap->hba_rstate;
clp->ap_o_state = ostate;
- clp->ap_cond = CFGA_COND_UNKNOWN;
+ clp->ap_cond = di_retired(node) ? CFGA_COND_FAILED : CFGA_COND_UNKNOWN;
clp->ap_busy = 0; /* no way to determine state change */
clp->ap_status_time = (time_t)-1;
diff --git a/usr/src/lib/fm/topo/libtopo/common/dev.c b/usr/src/lib/fm/topo/libtopo/common/dev.c
index dddede8706..7a4cb4f959 100644
--- a/usr/src/lib/fm/topo/libtopo/common/dev.c
+++ b/usr/src/lib/fm/topo/libtopo/common/dev.c
@@ -445,9 +445,10 @@ dev_fmri_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t version,
return (topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM));
unusable = 1;
} else {
+ uint_t retired = di_retired(dnode);
state = di_state(dnode);
- if (state & (DI_DEVICE_OFFLINE | DI_DEVICE_DOWN |
- DI_BUS_QUIESCED | DI_BUS_DOWN))
+ if (retired || (state & (DI_DEVICE_OFFLINE | DI_DEVICE_DOWN |
+ DI_BUS_QUIESCED | DI_BUS_DOWN)))
unusable = 1;
else
unusable = 0;
diff --git a/usr/src/lib/libcontract/Makefile b/usr/src/lib/libcontract/Makefile
index a042993bfc..8d05db4980 100644
--- a/usr/src/lib/libcontract/Makefile
+++ b/usr/src/lib/libcontract/Makefile
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -32,7 +32,8 @@ HDRDIR = common
SUBDIRS = $(MACH)
$(BUILD64)SUBDIRS += $(MACH64)
-MSGFILES = common/process_dump.c
+MSGFILES = common/process_dump.c common/device_dump.c \
+ common/libcontract_priv.c
POFILE = libcontract.po
all := TARGET = all
@@ -45,7 +46,8 @@ lint := TARGET = lint
all clean clobber install lint: $(SUBDIRS)
-$(POFILE): pofile_MSGFILES
+$(POFILE): $(MSGFILES)
+ $(BUILDPO.msgfiles)
install_h: $(ROOTHDRS)
diff --git a/usr/src/lib/libcontract/Makefile.com b/usr/src/lib/libcontract/Makefile.com
index 7d5ab8b471..050d42944e 100644
--- a/usr/src/lib/libcontract/Makefile.com
+++ b/usr/src/lib/libcontract/Makefile.com
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -32,7 +32,9 @@ OBJECTS = \
libcontract.o \
libcontract_priv.o \
process.o \
- process_dump.o
+ process_dump.o \
+ device.o \
+ device_dump.o
# include library definition
include ../../Makefile.lib
diff --git a/usr/src/lib/libcontract/common/device.c b/usr/src/lib/libcontract/common/device.c
new file mode 100644
index 0000000000..99e9bd1203
--- /dev/null
+++ b/usr/src/lib/libcontract/common/device.c
@@ -0,0 +1,177 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/ctfs.h>
+#include <sys/contract.h>
+#include <sys/contract/device.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <libnvpair.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <libcontract.h>
+#include "libcontract_impl.h"
+
+/*
+ * Device contract template routines
+ */
+
+int
+ct_dev_tmpl_set_minor(int fd, char *minor)
+{
+ return (ct_tmpl_set_internal(fd, CTDP_MINOR, (uintptr_t)minor));
+}
+
+int
+ct_dev_tmpl_set_aset(int fd, uint_t aset)
+{
+ return (ct_tmpl_set_internal(fd, CTDP_ACCEPT, aset));
+}
+
+int
+ct_dev_tmpl_set_noneg(int fd)
+{
+ return (ct_tmpl_set_internal(fd, CTDP_NONEG, CTDP_NONEG_SET));
+}
+
+int
+ct_dev_tmpl_clear_noneg(int fd)
+{
+ return (ct_tmpl_set_internal(fd, CTDP_NONEG, CTDP_NONEG_CLEAR));
+}
+
+int
+ct_dev_tmpl_get_minor(int fd, char *buf, size_t *buflenp)
+{
+ char path[PATH_MAX];
+ int error;
+ size_t len;
+
+ error = ct_tmpl_get_internal_string(fd, CTDP_MINOR, path);
+ if (error) {
+ return (error);
+ }
+
+ len = strlcpy(buf, path, *buflenp);
+ if (len >= *buflenp) {
+ *buflenp = len + 1;
+ return (EOVERFLOW);
+ }
+
+ return (0);
+}
+
+int
+ct_dev_tmpl_get_aset(int fd, uint_t *aset)
+{
+ return (ct_tmpl_get_internal(fd, CTDP_ACCEPT, aset));
+}
+
+int
+ct_dev_tmpl_get_noneg(int fd, uint_t *negp)
+{
+ return (ct_tmpl_get_internal(fd, CTDP_NONEG, negp));
+}
+
+/*
+ * Device contract event routines
+ */
+
+/*
+ * No device contract specific event routines
+ */
+
+
+/*
+ * Device contract status routines
+ */
+
+int
+ct_dev_status_get_aset(ct_stathdl_t stathdl, uint_t *aset)
+{
+ struct ctlib_status_info *info = stathdl;
+
+ if (info->status.ctst_type != CTT_DEVICE)
+ return (EINVAL);
+
+ if (info->nvl == NULL)
+ return (ENOENT);
+
+ return (nvlist_lookup_uint32(info->nvl, CTDS_ASET, aset));
+}
+
+int
+ct_dev_status_get_noneg(ct_stathdl_t stathdl, uint_t *negp)
+{
+ struct ctlib_status_info *info = stathdl;
+
+ if (info->status.ctst_type != CTT_DEVICE)
+ return (EINVAL);
+
+ if (info->nvl == NULL)
+ return (ENOENT);
+
+ return (nvlist_lookup_uint32(info->nvl, CTDS_NONEG, negp));
+}
+
+int
+ct_dev_status_get_dev_state(ct_stathdl_t stathdl, uint_t *statep)
+{
+ struct ctlib_status_info *info = stathdl;
+
+ if (info->status.ctst_type != CTT_DEVICE)
+ return (EINVAL);
+
+ if (info->nvl == NULL)
+ return (ENOENT);
+
+ return (nvlist_lookup_uint32(info->nvl, CTDS_STATE, statep));
+}
+
+int
+ct_dev_status_get_minor(ct_stathdl_t stathdl, char **bufp)
+{
+ int error;
+ struct ctlib_status_info *info = stathdl;
+
+ if (bufp == NULL)
+ return (EINVAL);
+
+ if (info->status.ctst_type != CTT_DEVICE)
+ return (EINVAL);
+
+ if (info->nvl == NULL)
+ return (ENOENT);
+
+ error = nvlist_lookup_string(info->nvl, CTDS_MINOR, bufp);
+ if (error != 0) {
+ return (error);
+ }
+
+ return (0);
+}
diff --git a/usr/src/lib/libcontract/common/device_dump.c b/usr/src/lib/libcontract/common/device_dump.c
new file mode 100644
index 0000000000..fb6d45cf10
--- /dev/null
+++ b/usr/src/lib/libcontract/common/device_dump.c
@@ -0,0 +1,103 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/contract/device.h>
+#include <sys/wait.h>
+#include <sys/ctfs.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+#include <assert.h>
+#include <signal.h>
+#include <libuutil.h>
+#include <libintl.h>
+#include <libcontract.h>
+#include <libcontract_priv.h>
+#include "libcontract_impl.h"
+#include "libcontract_priv.h"
+
+/*ARGSUSED*/
+void
+event_device(FILE *file, ct_evthdl_t ev, int verbose)
+{
+ uint_t type;
+ char *device;
+ char *s;
+ ctid_t ctid;
+ ct_stathdl_t stathdl;
+ int statfd;
+
+ type = ct_event_get_type(ev);
+ ctid = ct_event_get_ctid(ev);
+
+ statfd = contract_open(ctid, "device", "status", O_RDONLY);
+ if (statfd == -1) {
+ (void) fprintf(file, dgettext(TEXT_DOMAIN, "[bad contract]\n"));
+ return;
+ }
+
+ if (ct_status_read(statfd, CTD_ALL, &stathdl) != 0) {
+ (void) fprintf(file, dgettext(TEXT_DOMAIN, "[status error]\n"));
+ return;
+ }
+
+ if (ct_dev_status_get_minor(stathdl, &device) != 0) {
+ (void) fprintf(file, dgettext(TEXT_DOMAIN, "[bad status]\n"));
+ return;
+ }
+
+
+ switch (type) {
+ case CT_DEV_EV_OFFLINE:
+ s = dgettext(TEXT_DOMAIN, "device %s offlining\n");
+ break;
+ case CT_DEV_EV_DEGRADED:
+ s = dgettext(TEXT_DOMAIN, "device %s degrading\n");
+ break;
+ case CT_DEV_EV_ONLINE:
+ s = dgettext(TEXT_DOMAIN, "device %s online\n");
+ break;
+ case CT_EV_NEGEND:
+ contract_negend_dump(file, ev);
+ s = NULL;
+ break;
+ default:
+ s = dgettext(TEXT_DOMAIN, "device %s sent an unknown event\n");
+ break;
+ }
+
+ if (s) {
+ /*LINTED*/
+ (void) fprintf(file, s, device);
+ }
+
+ ct_status_free(stathdl);
+ (void) close(statfd);
+}
diff --git a/usr/src/lib/libcontract/common/device_dump.h b/usr/src/lib/libcontract/common/device_dump.h
new file mode 100644
index 0000000000..8c90400a52
--- /dev/null
+++ b/usr/src/lib/libcontract/common/device_dump.h
@@ -0,0 +1,43 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _DEVICE_DUMP_H
+#define _DEVICE_DUMP_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "libcontract_impl.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void event_device(FILE *, ct_evthdl_t, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DEVICE_DUMP_H */
diff --git a/usr/src/lib/libcontract/common/libcontract.c b/usr/src/lib/libcontract/common/libcontract.c
index 7cb35c4cfe..d2739cd1cd 100644
--- a/usr/src/lib/libcontract/common/libcontract.c
+++ b/usr/src/lib/libcontract/common/libcontract.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -66,11 +65,11 @@ ct_tmpl_create(int fd, ctid_t *ctidp)
}
int
-ct_tmpl_set_internal(int fd, uint_t id, uint_t value)
+ct_tmpl_set_internal(int fd, uint_t id, uintptr_t value)
{
ct_param_t param;
param.ctpm_id = id;
- param.ctpm_value = value;
+ param.ctpm_value = (uint64_t)value;
if (ioctl(fd, CT_TSET, &param) == -1)
return (errno);
return (0);
@@ -112,6 +111,18 @@ ct_tmpl_get_internal(int fd, uint_t id, uint_t *value)
}
int
+ct_tmpl_get_internal_string(int fd, uint_t id, char *value)
+{
+ ct_param_t param;
+
+ param.ctpm_id = id;
+ param.ctpm_value = (uint64_t)(uintptr_t)value;
+ if (ioctl(fd, CT_TGET, &param) == -1)
+ return (errno);
+ return (0);
+}
+
+int
ct_tmpl_get_critical(int fd, uint_t *events)
{
return (ct_tmpl_get_internal(fd, CTP_EV_CRITICAL, events));
@@ -173,6 +184,14 @@ ct_ctl_ack(int fd, ctevid_t event)
}
int
+ct_ctl_nack(int fd, ctevid_t event)
+{
+ if (ioctl(fd, CT_CNACK, &event) == -1)
+ return (errno);
+ return (0);
+}
+
+int
ct_ctl_qack(int fd, ctevid_t event)
{
if (ioctl(fd, CT_CQREQ, &event) == -1)
diff --git a/usr/src/lib/libcontract/common/libcontract.h b/usr/src/lib/libcontract/common/libcontract.h
index 98092b7db0..27453e5c83 100644
--- a/usr/src/lib/libcontract/common/libcontract.h
+++ b/usr/src/lib/libcontract/common/libcontract.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -55,6 +54,7 @@ extern int ct_tmpl_get_informative(int, uint_t *);
extern int ct_ctl_adopt(int);
extern int ct_ctl_abandon(int);
extern int ct_ctl_ack(int, ctevid_t);
+extern int ct_ctl_nack(int, ctevid_t);
extern int ct_ctl_qack(int, ctevid_t);
extern int ct_ctl_newct(int, ctevid_t, int);
@@ -113,6 +113,23 @@ extern int ct_pr_status_get_fatal(ct_stathdl_t, uint_t *);
extern int ct_pr_status_get_members(ct_stathdl_t, pid_t **, uint_t *);
extern int ct_pr_status_get_contracts(ct_stathdl_t, ctid_t **, uint_t *);
+/*
+ * Device contract routines
+ */
+int ct_dev_tmpl_set_minor(int, char *);
+int ct_dev_tmpl_set_aset(int, uint_t);
+int ct_dev_tmpl_set_noneg(int);
+int ct_dev_tmpl_clear_noneg(int);
+int ct_dev_tmpl_get_minor(int, char *, size_t *);
+int ct_dev_tmpl_get_aset(int, uint_t *);
+int ct_dev_tmpl_get_noneg(int, uint_t *);
+int ct_dev_status_get_aset(ct_stathdl_t, uint_t *);
+int ct_dev_status_get_noneg(ct_stathdl_t, uint_t *);
+int ct_dev_status_get_dev_state(ct_stathdl_t, uint_t *);
+int ct_dev_status_get_minor(ct_stathdl_t, char **);
+
+
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/libcontract/common/libcontract_impl.h b/usr/src/lib/libcontract/common/libcontract_impl.h
index d8504cb5cf..ad50cd3dcc 100644
--- a/usr/src/lib/libcontract/common/libcontract_impl.h
+++ b/usr/src/lib/libcontract/common/libcontract_impl.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -48,8 +47,9 @@ struct ctlib_event_info {
nvlist_t *nvl;
};
-extern int ct_tmpl_set_internal(int, uint_t, uint_t);
+extern int ct_tmpl_set_internal(int, uint_t, uintptr_t);
extern int ct_tmpl_get_internal(int, uint_t, uint_t *);
+extern int ct_tmpl_get_internal_string(int, uint_t, char *);
typedef struct contract_type {
const char *type_name;
diff --git a/usr/src/lib/libcontract/common/libcontract_priv.c b/usr/src/lib/libcontract/common/libcontract_priv.c
index 1db8ea2d95..d74e8409c6 100644
--- a/usr/src/lib/libcontract/common/libcontract_priv.c
+++ b/usr/src/lib/libcontract/common/libcontract_priv.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -34,16 +33,19 @@
#include <stdio.h>
#include <assert.h>
#include <libuutil.h>
+#include <libintl.h>
#include <string.h>
#include <procfs.h>
#include <libcontract.h>
#include <libcontract_priv.h>
#include "libcontract_impl.h"
#include "process_dump.h"
+#include "device_dump.h"
contract_type_t types[CTT_MAXTYPE] = {
- { "process", event_process }
+ { "process", event_process },
+ { "device", event_device }
};
static int
@@ -147,3 +149,23 @@ contract_event_dump(FILE *file, ct_evthdl_t hdl, int verbose)
type = info->event.ctev_cttype;
types[type].type_event(file, hdl, verbose);
}
+
+void
+contract_negend_dump(FILE *file, ct_evthdl_t ev)
+{
+ ctevid_t nevid = 0;
+ ctid_t my_ctid = ct_event_get_ctid(ev);
+ ctid_t new_ctid = 0;
+ char *s;
+
+ (void) ct_event_get_nevid(ev, &nevid);
+ (void) ct_event_get_newct(ev, &new_ctid);
+
+ if (new_ctid != my_ctid) {
+ s = dgettext(TEXT_DOMAIN, "negotiation %llu succeeded\n");
+ } else {
+ s = dgettext(TEXT_DOMAIN, "negotiation %llu failed\n");
+ }
+ /*LINTED*/
+ (void) fprintf(file, s, (unsigned long long)nevid);
+}
diff --git a/usr/src/lib/libcontract/common/libcontract_priv.h b/usr/src/lib/libcontract/common/libcontract_priv.h
index a1069efb35..639f190aff 100644
--- a/usr/src/lib/libcontract/common/libcontract_priv.h
+++ b/usr/src/lib/libcontract/common/libcontract_priv.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -42,6 +41,7 @@ extern int contract_open(ctid_t, const char *, const char *, int);
extern int contract_abandon_id(ctid_t);
extern ctid_t getctid(void);
extern void contract_event_dump(FILE *, ct_evthdl_t, int);
+extern void contract_negend_dump(FILE *, ct_evthdl_t);
#ifdef __cplusplus
}
diff --git a/usr/src/lib/libcontract/common/mapfile-vers b/usr/src/lib/libcontract/common/mapfile-vers
index 2f220b60ad..a64cbfd047 100644
--- a/usr/src/lib/libcontract/common/mapfile-vers
+++ b/usr/src/lib/libcontract/common/mapfile-vers
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -29,6 +29,7 @@ SUNW_1.1 {
global:
ct_ctl_abandon;
ct_ctl_ack;
+ ct_ctl_nack;
ct_ctl_adopt;
ct_ctl_newct;
ct_ctl_qack;
@@ -85,6 +86,17 @@ SUNW_1.1 {
ct_tmpl_set_cookie;
ct_tmpl_set_critical;
ct_tmpl_set_informative;
+ ct_dev_tmpl_set_minor;
+ ct_dev_tmpl_set_aset;
+ ct_dev_tmpl_set_noneg;
+ ct_dev_tmpl_clear_noneg;
+ ct_dev_tmpl_get_minor;
+ ct_dev_tmpl_get_aset;
+ ct_dev_tmpl_get_noneg;
+ ct_dev_status_get_aset;
+ ct_dev_status_get_noneg;
+ ct_dev_status_get_dev_state;
+ ct_dev_status_get_minor;
};
SUNWprivate_1.1 {
diff --git a/usr/src/lib/libdevinfo/Makefile.com b/usr/src/lib/libdevinfo/Makefile.com
index c1db80004a..7c10f0ba47 100644
--- a/usr/src/lib/libdevinfo/Makefile.com
+++ b/usr/src/lib/libdevinfo/Makefile.com
@@ -30,7 +30,9 @@ VERS= .1
OBJECTS= devfsinfo.o devinfo.o devinfo_prop_decode.o devinfo_devlink.o \
devinfo_devperm.o devfsmap.o devinfo_devname.o \
- devinfo_finddev.o devinfo_dli.o devinfo_dim.o devinfo_realpath.o
+ devinfo_finddev.o devinfo_dli.o devinfo_dim.o \
+ devinfo_realpath.o devinfo_retire.o
+
include ../../Makefile.lib
include ../../Makefile.rootfs
diff --git a/usr/src/lib/libdevinfo/devinfo.c b/usr/src/lib/libdevinfo/devinfo.c
index c9179e0d1f..8c103d2f7a 100644
--- a/usr/src/lib/libdevinfo/devinfo.c
+++ b/usr/src/lib/libdevinfo/devinfo.c
@@ -998,6 +998,12 @@ di_flags(di_node_t node)
return (DI_NODE(node)->flags);
}
+uint_t
+di_retired(di_node_t node)
+{
+ return (di_flags(node) & DEVI_RETIRED);
+}
+
ddi_devid_t
di_devid(di_node_t node)
{
diff --git a/usr/src/lib/libdevinfo/devinfo_retire.c b/usr/src/lib/libdevinfo/devinfo_retire.c
new file mode 100644
index 0000000000..8bcb77a730
--- /dev/null
+++ b/usr/src/lib/libdevinfo/devinfo_retire.c
@@ -0,0 +1,785 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <libdevinfo.h>
+#include <sys/modctl.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <librcm.h>
+#include <dlfcn.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+typedef struct rio_path {
+ char rpt_path[PATH_MAX];
+ struct rio_path *rpt_next;
+} rio_path_t;
+
+typedef struct rcm_arg {
+ char *rcm_root;
+ di_node_t rcm_node;
+ int rcm_supp;
+ rcm_handle_t *rcm_handle;
+ int rcm_retcode;
+ di_retire_t *rcm_dp;
+ rio_path_t *rcm_cons_nodes;
+ rio_path_t *rcm_rsrc_minors;
+ int (*rcm_offline)();
+ int (*rcm_online)();
+ int (*rcm_remove)();
+} rcm_arg_t;
+
+typedef struct selector {
+ char *sel_name;
+ int (*sel_selector)(di_node_t node, rcm_arg_t *rp);
+} di_selector_t;
+
+static void rio_assert(di_retire_t *dp, const char *EXstr, int line,
+ const char *file);
+
+#define LIBRCM_PATH "/usr/lib/librcm.so"
+#define RIO_ASSERT(d, x) \
+ {if (!(x)) rio_assert(d, #x, __LINE__, __FILE__); }
+
+static int disk_select(di_node_t node, rcm_arg_t *rp);
+static int nexus_select(di_node_t node, rcm_arg_t *rp);
+
+di_selector_t supported_devices[] = {
+ {"disk", disk_select},
+ {"nexus", nexus_select},
+ {NULL, NULL}
+};
+
+void *
+s_calloc(size_t nelem, size_t elsize, int fail)
+{
+ if (fail) {
+ errno = ENOMEM;
+ return (NULL);
+ } else {
+ return (calloc(nelem, elsize));
+ }
+}
+
+static void
+rio_assert(di_retire_t *dp, const char *EXstr, int line, const char *file)
+{
+ char buf[PATH_MAX];
+
+ if (dp->rt_abort == NULL)
+ assert(0);
+
+ (void) snprintf(buf, sizeof (buf),
+ "Assertion failed: %s, file %s, line %d\n",
+ EXstr, file, line);
+ dp->rt_abort(dp->rt_hdl, buf);
+}
+
+/*ARGSUSED*/
+static int
+disk_minor(di_node_t node, di_minor_t minor, void *arg)
+{
+ rcm_arg_t *rp = (rcm_arg_t *)arg;
+ di_retire_t *dp = rp->rcm_dp;
+
+ if (di_minor_spectype(minor) == S_IFBLK) {
+ rp->rcm_supp = 1;
+ dp->rt_debug(dp->rt_hdl, "[INFO]: disk_minor: is disk minor. "
+ "IDed this node as disk\n");
+ return (DI_WALK_TERMINATE);
+ }
+
+ dp->rt_debug(dp->rt_hdl, "[INFO]: disk_minor: Not a disk minor. "
+ "Continuing minor walk\n");
+ return (DI_WALK_CONTINUE);
+}
+
+static int
+disk_select(di_node_t node, rcm_arg_t *rp)
+{
+ rcm_arg_t rarg;
+ di_retire_t *dp = rp->rcm_dp;
+
+ rarg.rcm_dp = dp;
+
+ /*
+ * Check if this is a disk minor. If any one minor is DDI_NT_BLOCK
+ * we assume it is a disk
+ */
+ rarg.rcm_supp = 0;
+ if (di_walk_minor(node, DDI_NT_BLOCK, 0, &rarg, disk_minor) != 0) {
+ dp->rt_debug(dp->rt_hdl, "[INFO]: disk_select: di_walk_minor "
+ "failed. Returning NOTSUP\n");
+ return (0);
+ }
+
+ return (rarg.rcm_supp);
+}
+
+static int
+nexus_select(di_node_t node, rcm_arg_t *rp)
+{
+ int select;
+ char *path;
+
+ di_retire_t *dp = rp->rcm_dp;
+
+ path = di_devfs_path(node);
+ if (path == NULL) {
+ dp->rt_debug(dp->rt_hdl, "[INFO]: nexus_select: "
+ "di_devfs_path() is NULL. Returning NOTSUP\n");
+ return (0);
+ }
+
+ /*
+ * Check if it is a nexus
+ */
+ if (di_driver_ops(node) & DI_BUS_OPS) {
+ dp->rt_debug(dp->rt_hdl, "[INFO]: nexus_select: is nexus %s\n",
+ path);
+ select = 1;
+ } else {
+ dp->rt_debug(dp->rt_hdl, "[INFO]: nexus_select: not nexus %s\n",
+ path);
+ select = 0;
+ }
+
+ di_devfs_path_free(path);
+
+ return (select);
+}
+
+static int
+node_select(di_node_t node, void *arg)
+{
+ rcm_arg_t *rp = (rcm_arg_t *)arg;
+ di_retire_t *dp;
+ int sel;
+ int i;
+ char *path;
+ uint_t state;
+
+ dp = rp->rcm_dp;
+
+ /* skip pseudo nodes - we only retire real hardware */
+ path = di_devfs_path(node);
+ if (strncmp(path, "/pseudo/", strlen("/pseudo/")) == 0 ||
+ strcmp(path, "/pseudo") == 0) {
+ dp->rt_debug(dp->rt_hdl, "[INFO]: node_select: "
+ "pseudo device in subtree - returning NOTSUP: %s\n",
+ path);
+ rp->rcm_supp = 0;
+ di_devfs_path_free(path);
+ return (DI_WALK_TERMINATE);
+ }
+ di_devfs_path_free(path);
+
+ /*
+ * If a device is offline/detached/down it is
+ * retireable irrespective of the type of device,
+ * presumably the system is able to function without
+ * it.
+ */
+ state = di_state(node);
+ if ((state & DI_DRIVER_DETACHED) || (state & DI_DEVICE_OFFLINE) ||
+ (state & DI_BUS_DOWN)) {
+ dp->rt_debug(dp->rt_hdl, "[INFO]: node_select: device "
+ "is offline/detached. Assuming retire supported\n");
+ return (DI_WALK_CONTINUE);
+ }
+
+ sel = 0;
+ for (i = 0; supported_devices[i].sel_name != NULL; i++) {
+ sel = supported_devices[i].sel_selector(node, rp);
+ if (sel == 1) {
+ dp->rt_debug(dp->rt_hdl, "[INFO]: node_select: "
+ "found supported device: %s\n",
+ supported_devices[i].sel_name);
+ break;
+ }
+ }
+
+ if (sel != 1) {
+ /*
+ * This node is not a supported device. Retire cannot proceed
+ */
+ dp->rt_debug(dp->rt_hdl, "[INFO]: node_select: found "
+ "unsupported device. Returning NOTSUP\n");
+ rp->rcm_supp = 0;
+ return (DI_WALK_TERMINATE);
+ }
+
+ /*
+ * This node is supported. Check other nodes in this subtree.
+ */
+ dp->rt_debug(dp->rt_hdl, "[INFO]: node_select: This node supported. "
+ "Checking other nodes in subtree: %s\n", rp->rcm_root);
+ return (DI_WALK_CONTINUE);
+}
+
+
+
+/*
+ * when in doubt assume that retire is not supported for this device.
+ */
+static int
+retire_supported(rcm_arg_t *rp)
+{
+ di_retire_t *dp;
+ di_node_t rnode = rp->rcm_node;
+
+ dp = rp->rcm_dp;
+
+ /*
+ * We should not be here if devinfo snapshot is NULL.
+ */
+ RIO_ASSERT(dp, rnode != DI_NODE_NIL);
+
+ /*
+ * Note: We initally set supported to 1, then walk the
+ * subtree rooted at devpath, allowing each node the
+ * opportunity to veto the support. We cannot do things
+ * the other way around i.e. assume "not supported" and
+ * let individual nodes indicate that they are supported.
+ * In the latter case, the supported flag would be set
+ * if any one node in the subtree was supported which is
+ * not what we want.
+ */
+ rp->rcm_supp = 1;
+ if (di_walk_node(rnode, DI_WALK_CLDFIRST, rp, node_select) != 0) {
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: retire_supported: "
+ "di_walk_node: failed. Returning NOTSUP\n");
+ rp->rcm_supp = 0;
+ }
+
+ if (rp->rcm_supp) {
+ dp->rt_debug(dp->rt_hdl, "[INFO]: retire IS supported\n");
+ }
+
+ return (rp->rcm_supp);
+}
+
+static void
+rcm_finalize(rcm_arg_t *rp, int retcode)
+{
+ rio_path_t *p;
+ rio_path_t *tmp;
+ int flags = RCM_RETIRE_NOTIFY;
+ int retval;
+ int error;
+ di_retire_t *dp;
+
+ dp = rp->rcm_dp;
+
+ RIO_ASSERT(dp, retcode == 0 || retcode == -1);
+
+ dp->rt_debug(dp->rt_hdl, "[INFO]: rcm_finalize: retcode=%d: dev=%s\n",
+ retcode, rp->rcm_root);
+
+ for (p = rp->rcm_cons_nodes; p; ) {
+ tmp = p;
+ p = tmp->rpt_next;
+ free(tmp);
+ }
+ rp->rcm_cons_nodes = NULL;
+
+ dp->rt_debug(dp->rt_hdl, "[INFO]: rcm_finalize: cons_nodes NULL\n");
+
+ for (p = rp->rcm_rsrc_minors; p; ) {
+ tmp = p;
+ p = tmp->rpt_next;
+ if (retcode == 0) {
+ retval = rp->rcm_remove(rp->rcm_handle,
+ tmp->rpt_path, flags, NULL);
+ error = errno;
+ } else {
+ RIO_ASSERT(dp, retcode == -1);
+ retval = rp->rcm_online(rp->rcm_handle,
+ tmp->rpt_path, flags, NULL);
+ error = errno;
+ }
+ if (retval != RCM_SUCCESS) {
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: rcm_finalize: "
+ "rcm_%s: retval=%d: error=%s: path=%s\n",
+ retcode == 0 ? "remove" : "online", retval,
+ strerror(error), tmp->rpt_path);
+ } else {
+ dp->rt_debug(dp->rt_hdl, "[INFO]: rcm_finalize: "
+ "rcm_%s: SUCCESS: path=%s\n",
+ retcode == 0 ? "remove" : "online", tmp->rpt_path);
+ }
+ free(tmp);
+ }
+ rp->rcm_rsrc_minors = NULL;
+}
+/*ARGSUSED*/
+static int
+call_offline(di_node_t node, di_minor_t minor, void *arg)
+{
+ rcm_arg_t *rp = (rcm_arg_t *)arg;
+ di_retire_t *dp = rp->rcm_dp;
+ char *mnp;
+ rio_path_t *rpt;
+ int retval;
+
+ mnp = di_devfs_minor_path(minor);
+ if (mnp == NULL) {
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: di_devfs_minor_path "
+ "failed. Returning RCM FAILURE: %s\n", rp->rcm_root);
+ rp->rcm_retcode = RCM_FAILURE;
+ return (DI_WALK_TERMINATE);
+ }
+
+ rpt = s_calloc(1, sizeof (rio_path_t), 0);
+ if (rpt == NULL) {
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: calloc failed. "
+ "Returning RCM FAILURE: %s\n", rp->rcm_root);
+ di_devfs_path_free(mnp);
+ rp->rcm_retcode = RCM_FAILURE;
+ return (DI_WALK_TERMINATE);
+ }
+
+ (void) snprintf(rpt->rpt_path, sizeof (rpt->rpt_path),
+ "/devices%s", mnp);
+
+ di_devfs_path_free(mnp);
+
+ retval = rp->rcm_offline(rp->rcm_handle, rpt->rpt_path,
+ RCM_RETIRE_REQUEST, NULL);
+
+ rpt->rpt_next = rp->rcm_rsrc_minors;
+ rp->rcm_rsrc_minors = rpt;
+
+ if (retval == RCM_FAILURE) {
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: RCM OFFLINE failed "
+ "for: %s\n", rpt->rpt_path);
+ rp->rcm_retcode = RCM_FAILURE;
+ return (DI_WALK_TERMINATE);
+ } else if (retval == RCM_SUCCESS) {
+ rp->rcm_retcode = RCM_SUCCESS;
+ dp->rt_debug(dp->rt_hdl, "[INFO]: RCM OFFLINE returned "
+ "RCM_SUCCESS: %s\n", rpt->rpt_path);
+ } else if (retval != RCM_NO_CONSTRAINT) {
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: RCM OFFLINE returned "
+ "invalid value for: %s\n", rpt->rpt_path);
+ rp->rcm_retcode = RCM_FAILURE;
+ return (DI_WALK_TERMINATE);
+ } else {
+ dp->rt_debug(dp->rt_hdl, "[INFO]: RCM OFFLINE returned "
+ "RCM_NO_CONSTRAINT: %s\n", rpt->rpt_path);
+ }
+
+ return (DI_WALK_CONTINUE);
+}
+
+static int
+offline_one(di_node_t node, void *arg)
+{
+ rcm_arg_t *rp = (rcm_arg_t *)arg;
+ rio_path_t *rpt;
+ di_retire_t *dp = rp->rcm_dp;
+ char *path;
+
+ /*
+ * We should already have terminated the walk
+ * in case of failure
+ */
+ RIO_ASSERT(dp, rp->rcm_retcode == RCM_SUCCESS ||
+ rp->rcm_retcode == RCM_NO_CONSTRAINT);
+
+ dp->rt_debug(dp->rt_hdl, "[INFO]: offline_one: entered\n");
+
+ rp->rcm_retcode = RCM_NO_CONSTRAINT;
+
+ rpt = s_calloc(1, sizeof (rio_path_t), 0);
+ if (rpt == NULL) {
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: rio_path_t calloc "
+ "failed: error: %s\n", strerror(errno));
+ goto fail;
+ }
+
+ path = di_devfs_path(node);
+ if (path == NULL) {
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: di_devfs_path "
+ "failed: error: %s\n", strerror(errno));
+ free(rpt);
+ goto fail;
+ }
+
+ (void) strlcpy(rpt->rpt_path, path, sizeof (rpt->rpt_path));
+
+ di_devfs_path_free(path);
+
+ if (di_walk_minor(node, NULL, 0, rp, call_offline) != 0) {
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: di_walk_minor "
+ "failed: error: %s: %s\n", strerror(errno), path);
+ free(rpt);
+ goto fail;
+ }
+
+ if (rp->rcm_retcode == RCM_FAILURE) {
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: di_walk_minor "
+ "returned: RCM_FAILURE: %s\n", rpt->rpt_path);
+ free(rpt);
+ goto fail;
+ } else if (rp->rcm_retcode == RCM_SUCCESS) {
+ dp->rt_debug(dp->rt_hdl, "[INFO]: di_walk_minor "
+ "returned: RCM_SUCCESS: %s\n", rpt->rpt_path);
+ rpt->rpt_next = rp->rcm_cons_nodes;
+ rp->rcm_cons_nodes = rpt;
+ } else if (rp->rcm_retcode != RCM_NO_CONSTRAINT) {
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: di_walk_minor "
+ "returned: unknown RCM error code: %d, %s\n",
+ rp->rcm_retcode, rpt->rpt_path);
+ free(rpt);
+ goto fail;
+ } else {
+ dp->rt_debug(dp->rt_hdl, "[INFO]: di_walk_minor "
+ "returned: RCM_NO_CONSTRAINT: %s\n", rpt->rpt_path);
+ free(rpt);
+ }
+
+ /*
+ * RCM_SUCCESS or RCM_NO_CONSTRAINT.
+ * RCM_SUCCESS implies we overcame a constraint, so keep walking.
+ * RCM_NO_CONSTRAINT implies no constraints applied via RCM.
+ * Continue walking in the hope that contracts or LDI will
+ * apply constraints
+ * set retcode to RCM_SUCCESS to show that at least 1 node
+ * completely walked
+ */
+ rp->rcm_retcode = RCM_SUCCESS;
+ return (DI_WALK_CONTINUE);
+
+fail:
+ rp->rcm_retcode = RCM_FAILURE;
+ return (DI_WALK_TERMINATE);
+}
+
+/*
+ * Returns:
+ * RCM_SUCCESS: RCM constraints (if any) were applied. The
+ * device paths for which constraints were applied is passed
+ * back via the pp argument
+ *
+ * RCM_FAILURE: Either RCM constraints prevent a retire or
+ * an error occurred
+ */
+static int
+rcm_notify(rcm_arg_t *rp, char **pp, size_t *clen)
+{
+ size_t len;
+ rio_path_t *p;
+ rio_path_t *tmp;
+ char *plistp;
+ char *s;
+ di_retire_t *dp;
+ di_node_t rnode;
+
+ dp = rp->rcm_dp;
+
+ dp->rt_debug(dp->rt_hdl, "[INFO]: rcm_notify() entered\n");
+
+ RIO_ASSERT(dp, rp->rcm_root);
+
+ *pp = NULL;
+
+ rnode = rp->rcm_node;
+ if (rnode == DI_NODE_NIL) {
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: devinfo snapshot "
+ "NULL. Returning no RCM constraint: %s\n", rp->rcm_root);
+ return (RCM_NO_CONSTRAINT);
+ }
+
+ rp->rcm_retcode = RCM_NO_CONSTRAINT;
+ rp->rcm_cons_nodes = NULL;
+ rp->rcm_rsrc_minors = NULL;
+ if (di_walk_node(rnode, DI_WALK_CLDFIRST, rp, offline_one) != 0) {
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: di_walk_node "
+ "failed: error: %s: %s\n", strerror(errno), rp->rcm_root);
+ /* online is idempotent - safe to online non-offlined nodes */
+ rcm_finalize(rp, -1);
+ rp->rcm_retcode = RCM_FAILURE;
+ goto out;
+ }
+
+ if (rp->rcm_retcode == RCM_FAILURE) {
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: walk_node "
+ "returned retcode of RCM_FAILURE: %s\n", rp->rcm_root);
+ rcm_finalize(rp, -1);
+ goto out;
+ }
+
+ if (rp->rcm_retcode == RCM_NO_CONSTRAINT) {
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: di_walk_node "
+ " - no nodes walked: RCM_NO_CONSTRAINT: %s\n",
+ rp->rcm_root);
+ } else {
+ dp->rt_debug(dp->rt_hdl, "[INFO]: walk_node: RCM_SUCCESS\n");
+ }
+
+ /*
+ * Convert to a sequence of NUL separated strings terminated by '\0'\0'
+ */
+ for (len = 0, p = rp->rcm_cons_nodes; p; p = p->rpt_next) {
+ RIO_ASSERT(dp, p->rpt_path);
+ RIO_ASSERT(dp, strlen(p->rpt_path) > 0);
+ len += (strlen(p->rpt_path) + 1);
+ }
+ len++; /* list terminating '\0' */
+
+ dp->rt_debug(dp->rt_hdl, "[INFO]: len of constraint str = %lu\n", len);
+
+ plistp = s_calloc(1, len, 0);
+ if (plistp == NULL) {
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: fail to alloc "
+ "constraint list: error: %s: %s\n", strerror(errno),
+ rp->rcm_root);
+ rcm_finalize(rp, -1);
+ rp->rcm_retcode = RCM_FAILURE;
+ goto out;
+ }
+
+ for (s = plistp, p = rp->rcm_cons_nodes; p; ) {
+ tmp = p;
+ p = tmp->rpt_next;
+ (void) strcpy(s, tmp->rpt_path);
+ s += strlen(s) + 1;
+ RIO_ASSERT(dp, s - plistp < len);
+ free(tmp);
+ }
+ rp->rcm_cons_nodes = NULL;
+ RIO_ASSERT(dp, s - plistp == len - 1);
+ *s = '\0';
+
+ dp->rt_debug(dp->rt_hdl, "[INFO]: constraint str = %p\n", plistp);
+
+ *pp = plistp;
+ *clen = len;
+
+ rp->rcm_retcode = RCM_SUCCESS;
+out:
+ return (rp->rcm_retcode);
+}
+
+
+/*ARGSUSED*/
+int
+di_retire_device(char *devpath, di_retire_t *dp, int flags)
+{
+ char path[PATH_MAX];
+ struct stat sb;
+ int retval = EINVAL;
+ char *constraint = NULL;
+ size_t clen;
+ void *librcm_hdl;
+ rcm_arg_t rarg = {0};
+ int (*librcm_alloc_handle)();
+ int (*librcm_free_handle)();
+
+ if (dp == NULL || dp->rt_debug == NULL || dp->rt_hdl == NULL)
+ return (EINVAL);
+
+ if (devpath == NULL || devpath[0] == '\0') {
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: NULL argument(s)\n");
+ return (EINVAL);
+ }
+
+ if (devpath[0] != '/' || strlen(devpath) >= PATH_MAX ||
+ strncmp(devpath, "/devices/", strlen("/devices/")) == 0 ||
+ strstr(devpath, "../devices/") || strrchr(devpath, ':')) {
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: invalid devpath: %s\n",
+ devpath);
+ return (EINVAL);
+ }
+
+ if (flags != 0) {
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: flags should be 0: %d\n",
+ flags);
+ return (EINVAL);
+ }
+
+ /*
+ * dlopen rather than link against librcm since libdevinfo
+ * resides in / and librcm resides in /usr. The dlopen is
+ * safe to do since fmd which invokes the retire code
+ * resides on /usr and will not come here until /usr is
+ * mounted.
+ */
+ librcm_hdl = dlopen(LIBRCM_PATH, RTLD_LAZY);
+ if (librcm_hdl == NULL) {
+ char *errstr = dlerror();
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: Cannot dlopen librcm: %s\n",
+ errstr ? errstr : "Unknown error");
+ return (ENOSYS);
+ }
+
+ librcm_alloc_handle = (int (*)())dlsym(librcm_hdl, "rcm_alloc_handle");
+ rarg.rcm_offline = (int (*)())dlsym(librcm_hdl, "rcm_request_offline");
+ rarg.rcm_online = (int (*)())dlsym(librcm_hdl, "rcm_notify_online");
+ rarg.rcm_remove = (int (*)())dlsym(librcm_hdl, "rcm_notify_remove");
+ librcm_free_handle = (int (*)())dlsym(librcm_hdl, "rcm_free_handle");
+
+ if (librcm_alloc_handle == NULL ||
+ rarg.rcm_offline == NULL ||
+ rarg.rcm_online == NULL ||
+ rarg.rcm_remove == NULL ||
+ librcm_free_handle == NULL) {
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: dlsym failed\n");
+ retval = ENOSYS;
+ goto out;
+ }
+
+ /*
+ * Take a libdevinfo snapshot here because we cannot do so
+ * after device is retired. If device doesn't attach, we retire
+ * anyway i.e. it is not fatal.
+ */
+ rarg.rcm_node = di_init(devpath, DINFOCPYALL);
+ if (rarg.rcm_node == DI_NODE_NIL) {
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: device doesn't attach, "
+ "retiring anyway: %s\n", devpath);
+ }
+
+ rarg.rcm_handle = NULL;
+ if (librcm_alloc_handle(NULL, 0, NULL, &rarg.rcm_handle)
+ != RCM_SUCCESS) {
+ retval = errno;
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: failed to alloc "
+ "RCM handle. Returning RCM failure: %s\n", devpath);
+ rarg.rcm_handle = NULL;
+ goto out;
+ }
+
+ rarg.rcm_root = devpath;
+ rarg.rcm_dp = dp;
+
+ /*
+ * If device is already detached/nonexistent and cannot be
+ * attached, allow retire without checking device type.
+ * XXX
+ * Else, check if retire is supported for this device type.
+ */
+ (void) snprintf(path, sizeof (path), "/devices%s", devpath);
+ if (stat(path, &sb) == -1 || !S_ISDIR(sb.st_mode)) {
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: detached or nonexistent "
+ "device. Bypassing retire_supported: %s\n", devpath);
+ } else if (!retire_supported(&rarg)) {
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: retire not supported for "
+ "device type: %s\n", devpath);
+ retval = ENOTSUP;
+ goto out;
+ }
+
+ clen = 0;
+ constraint = NULL;
+ retval = rcm_notify(&rarg, &constraint, &clen);
+ if (retval == RCM_FAILURE) {
+ /* retire not permitted */
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: RCM constraints block "
+ "retire: %s\n", devpath);
+ retval = EBUSY;
+ goto out;
+ } else if (retval == RCM_SUCCESS) {
+ dp->rt_debug(dp->rt_hdl, "[INFO]: RCM constraints applied"
+ ": %s\n", devpath);
+ } else if (retval == RCM_NO_CONSTRAINT) {
+ dp->rt_debug(dp->rt_hdl, "[INFO]: No RCM constraints applied"
+ ": %s\n", devpath);
+ } else {
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: notify returned unknown "
+ "return code: %d: %s\n", retval, devpath);
+ retval = ESRCH;
+ goto out;
+ }
+
+ if (modctl(MODRETIRE, devpath, constraint, clen) != 0) {
+ retval = errno;
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: retire modctl() failed: "
+ "%s: %s\n", devpath, strerror(retval));
+ rcm_finalize(&rarg, -1);
+ goto out;
+ }
+
+ dp->rt_debug(dp->rt_hdl, "[INFO]: retire modctl() succeeded: %s\n",
+ devpath);
+
+ rcm_finalize(&rarg, 0);
+
+ retval = 0;
+
+out:
+ if (rarg.rcm_handle)
+ (void) librcm_free_handle(rarg.rcm_handle);
+
+ RIO_ASSERT(dp, rarg.rcm_cons_nodes == NULL);
+ RIO_ASSERT(dp, rarg.rcm_rsrc_minors == NULL);
+
+ (void) dlclose(librcm_hdl);
+
+ free(constraint);
+
+ if (rarg.rcm_node != DI_NODE_NIL)
+ di_fini(rarg.rcm_node);
+
+ return (retval);
+}
+
+/*ARGSUSED*/
+int
+di_unretire_device(char *devpath, di_retire_t *dp)
+{
+ if (dp == NULL || dp->rt_debug == NULL || dp->rt_hdl == NULL)
+ return (EINVAL);
+
+ if (devpath == NULL || devpath[0] == '\0') {
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: NULL devpath\n");
+ return (EINVAL);
+ }
+
+ if (devpath[0] != '/' || strlen(devpath) >= PATH_MAX ||
+ strncmp(devpath, "/devices/", strlen("/devices/")) == 0 ||
+ strstr(devpath, "../devices/") || strrchr(devpath, ':')) {
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: invalid devpath: %s\n",
+ devpath);
+ return (EINVAL);
+ }
+
+ if (modctl(MODUNRETIRE, devpath) != 0) {
+ int err = errno;
+ dp->rt_debug(dp->rt_hdl, "[ERROR]: unretire modctl() failed: "
+ "%s: %s\n", devpath, strerror(err));
+ return (err);
+ }
+
+ dp->rt_debug(dp->rt_hdl, "[INFO]: unretire modctl() done: %s\n",
+ devpath);
+
+ return (0);
+}
diff --git a/usr/src/lib/libdevinfo/libdevinfo.h b/usr/src/lib/libdevinfo/libdevinfo.h
index ad08502628..bdb4fa2238 100644
--- a/usr/src/lib/libdevinfo/libdevinfo.h
+++ b/usr/src/lib/libdevinfo/libdevinfo.h
@@ -355,6 +355,11 @@ extern void *di_parent_private_data(di_node_t node);
extern void *di_driver_private_data(di_node_t node);
/*
+ * The value of the dip's devi_flags field
+ */
+uint_t di_flags(di_node_t node);
+
+/*
* Types of links for devlink lookup
*/
#define DI_PRIMARY_LINK 0x01
@@ -412,6 +417,19 @@ extern int di_devlink_cache_walk(di_devlink_handle_t hdp, const char *re,
int (*devlink_callback)(di_devlink_t, void *));
/*
+ * Private interfaces for I/O retire
+ */
+typedef struct di_retire {
+ void *rt_hdl;
+ void (*rt_abort)(void *hdl, const char *format, ...);
+ void (*rt_debug)(void *hdl, const char *format, ...);
+} di_retire_t;
+
+extern int di_retire_device(char *path, di_retire_t *dp, int flags);
+extern int di_unretire_device(char *path, di_retire_t *dp);
+extern uint_t di_retired(di_node_t node);
+
+/*
* Private interfaces for /etc/logindevperm
*/
extern int di_devperm_login(const char *, uid_t, gid_t, void (*)(char *));
diff --git a/usr/src/lib/libdevinfo/mapfile-vers b/usr/src/lib/libdevinfo/mapfile-vers
index c941cd3efe..c2d82dcb4b 100644
--- a/usr/src/lib/libdevinfo/mapfile-vers
+++ b/usr/src/lib/libdevinfo/mapfile-vers
@@ -211,6 +211,9 @@ SUNWprivate_1.1 {
finddev_close;
finddev_next;
di_flags;
+ di_retire_device;
+ di_unretire_device;
+ di_retired;
local:
*;
};
diff --git a/usr/src/lib/librcm/librcm.h b/usr/src/lib/librcm/librcm.h
index d830ea375e..be57013b0a 100644
--- a/usr/src/lib/librcm/librcm.h
+++ b/usr/src/lib/librcm/librcm.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -57,6 +57,8 @@ extern "C" {
#define RCM_REGISTER_EVENT 0x2000 /* private */
#define RCM_REGISTER_CAPACITY 0x4000 /* private */
#define RCM_SUSPENDED 0x8000 /* private */
+#define RCM_RETIRE_REQUEST 0x10000
+#define RCM_RETIRE_NOTIFY 0x20000
/*
* RCM return values
@@ -64,6 +66,7 @@ extern "C" {
#define RCM_SUCCESS 0
#define RCM_FAILURE -1
#define RCM_CONFLICT -2
+#define RCM_NO_CONSTRAINT -3
/*
* RCM resource states
diff --git a/usr/src/lib/librcm/librcm_impl.h b/usr/src/lib/librcm/librcm_impl.h
index a534d22e1e..b096ffba0d 100644
--- a/usr/src/lib/librcm/librcm_impl.h
+++ b/usr/src/lib/librcm/librcm_impl.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -69,8 +68,8 @@ extern "C" {
#define RCM_REGISTER_MASK (RCM_FILESYS|RCM_REGISTER_DR|\
RCM_REGISTER_EVENT|RCM_REGISTER_CAPACITY)
#define RCM_REQUEST_MASK (RCM_QUERY|RCM_SCOPE|RCM_FORCE|RCM_FILESYS|\
- RCM_QUERY_CANCEL)
-#define RCM_NOTIFY_MASK (RCM_FILESYS)
+ RCM_QUERY_CANCEL|RCM_RETIRE_REQUEST)
+#define RCM_NOTIFY_MASK (RCM_FILESYS|RCM_RETIRE_NOTIFY)
/* event data names */
#define RCM_CMD "rcm.cmd"