diff options
author | Mike Christensen <Michael.Christensen@Sun.COM> | 2010-03-01 18:02:46 -0800 |
---|---|---|
committer | Mike Christensen <Michael.Christensen@Sun.COM> | 2010-03-01 18:02:46 -0800 |
commit | 82629e3015252bf18319ba3815c773df23e21436 (patch) | |
tree | babd90f2440f44cae78e40aef052d2760e973ca9 /usr/src/lib | |
parent | d78a6b7e13de1e122f6c7e0d539522698d83ec22 (diff) | |
download | illumos-gate-82629e3015252bf18319ba3815c773df23e21436.tar.gz |
PSARC 2010/004 Logical Domains Information API and ldminfo
FWARC 2009/680 Domain UUID property
FWARC 2010/058 Logical Domains Agent Chassis Serial Number Message
6680702 RFE: Want a mechanism for Solaris to know if it is an LDOM and if so what type
6873151 RFE: unique ID for LDOMs to facillitate asset tracking
6712763 RFE: Need information about control domain from within a guest domain
Diffstat (limited to 'usr/src/lib')
-rw-r--r-- | usr/src/lib/Makefile | 6 | ||||
-rw-r--r-- | usr/src/lib/libv12n/Makefile | 58 | ||||
-rw-r--r-- | usr/src/lib/libv12n/Makefile.com | 54 | ||||
-rw-r--r-- | usr/src/lib/libv12n/common/libv12n.h | 61 | ||||
-rw-r--r-- | usr/src/lib/libv12n/common/llib-lv12n | 29 | ||||
-rw-r--r-- | usr/src/lib/libv12n/common/mapfile-vers | 50 | ||||
-rw-r--r-- | usr/src/lib/libv12n/sparc/Makefile | 53 | ||||
-rw-r--r-- | usr/src/lib/libv12n/sparc/libv12n.c | 870 | ||||
-rw-r--r-- | usr/src/lib/libv12n/sparcv9/Makefile | 54 |
9 files changed, 1234 insertions, 1 deletions
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile index fd5a1b90c7..b4c910a1ed 100644 --- a/usr/src/lib/Makefile +++ b/usr/src/lib/Makefile @@ -285,7 +285,8 @@ sparc_SUBDIRS= .WAIT \ librsc \ storage \ libpcp \ - libtsalarm + libtsalarm \ + libv12n FM_sparc_DEPLIBS= libpri @@ -518,6 +519,7 @@ sparc_HDRSUBDIRS= \ libds \ libdscp \ libpri \ + libv12n \ storage all := TARGET= all @@ -584,6 +586,7 @@ libdladm: libdevinfo libinetutil libsocket libscf librcm libnvpair \ libexacct libnsl libkstat libcurses libdll: libast libdlpi: libinetutil libdladm +libds: libsysevent libdscfg: libnsctl libunistat libsocket libnsl libdtrace: libproc libgen libctf libdtrace_jni: libuutil libdtrace @@ -648,6 +651,7 @@ libexacct/demo: libexacct libproject libsocket libnsl libtsalarm: libpcp smbsrv: libsocket libnsl libmd libxnet libpthread librt \ libshare libidmap pkcs11 libsqlite libcryptoutil +libv12n: libds libuuid libvrrpadm: libsocket libdladm libscf libvscan: libscf scsi: libnvpair diff --git a/usr/src/lib/libv12n/Makefile b/usr/src/lib/libv12n/Makefile new file mode 100644 index 0000000000..eceddb2405 --- /dev/null +++ b/usr/src/lib/libv12n/Makefile @@ -0,0 +1,58 @@ +# +# 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 2010 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# + +include ../Makefile.lib + +HDRS = libv12n.h +HDRDIR = common + +ROOTHDRDIR = $(ROOT)/usr/include + +SUBDIRS = $(MACH) +$(BUILD64)SUBDIRS += $(MACH64) + +all := TARGET = all +clean := TARGET = clean +clobber := TARGET = clobber +install := TARGET = install +lint := TARGET = lint + +.KEEP_STATE: + +all clean clobber lint: $(SUBDIRS) + +check: $(CHECKHDRS) + +install: all .WAIT $(SUBDIRS) + +install_h: $(ROOTHDRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + +include ../Makefile.targ diff --git a/usr/src/lib/libv12n/Makefile.com b/usr/src/lib/libv12n/Makefile.com new file mode 100644 index 0000000000..869beaf2d5 --- /dev/null +++ b/usr/src/lib/libv12n/Makefile.com @@ -0,0 +1,54 @@ +# +# 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 2010 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# + +LIBRARY = libv12n.a +VERS = .1 + +OBJECTS = $(MACHCOBJS) $(CMNOBJS) + +include ../../Makefile.lib + +LIBS = $(DYNLIB) $(LINTLIB) + +SRCDIR = ../common +SRCS = $(MACHCOBJS:%.o=../$(MACH)/%.c) + +CFLAGS += $(CCVERBOSE) $(C_BIGPICFLAGS) +CFLAGS64 += $(CCVERBOSE) $(C_BIGPICFLAGS) + +$(LINTLIB) := SRCS = ../common/llib-lv12n + +.KEEP_STATE: + +all: $(LIBS) + +lint: $(LINTLIB) lintcheck + +pics/%.o: ../$(MACH)/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +include ../../Makefile.targ diff --git a/usr/src/lib/libv12n/common/libv12n.h b/usr/src/lib/libv12n/common/libv12n.h new file mode 100644 index 0000000000..b854d011c9 --- /dev/null +++ b/usr/src/lib/libv12n/common/libv12n.h @@ -0,0 +1,61 @@ +/* + * 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 2010 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_LIBV12N_H +#define _SYS_LIBV12N_H + +#include <sys/types.h> +#include <uuid/uuid.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* Max length of an v12n name/uuid/serialno */ +#define V12N_NAME_MAX 1024 + +/* Virtualization capabilities - bit mask */ +#define V12N_CAP_SUPPORTED 0x1 /* Virtualization supported */ +#define V12N_CAP_ENABLED 0x2 /* Virtualization enabled */ +#define V12N_CAP_IMPL_LDOMS 0x4 /* LDoms Implementation */ + +/* LDoms Domain role types - bit mask */ +#define V12N_ROLE_CONTROL 0x1 /* LDoms Ctrl domain (zero = Guest) */ +#define V12N_ROLE_IO 0x2 /* I/O domain */ +#define V12N_ROLE_SERVICE 0x4 /* Service domain */ +#define V12N_ROLE_ROOT 0x8 /* Root domain */ + +int v12n_capabilities(void); +int v12n_domain_roles(void); +int v12n_domain_uuid(uuid_t); +size_t v12n_domain_name(char *, size_t); +size_t v12n_ctrl_domain(char *, size_t); +size_t v12n_chassis_serialno(char *, size_t); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_LIBV12N_H */ diff --git a/usr/src/lib/libv12n/common/llib-lv12n b/usr/src/lib/libv12n/common/llib-lv12n new file mode 100644 index 0000000000..904f11528d --- /dev/null +++ b/usr/src/lib/libv12n/common/llib-lv12n @@ -0,0 +1,29 @@ +/* + * 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 2010 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/*LINTLIBRARY*/ +/*PROTOLIB1*/ + +#include "libv12n.h" diff --git a/usr/src/lib/libv12n/common/mapfile-vers b/usr/src/lib/libv12n/common/mapfile-vers new file mode 100644 index 0000000000..582b964fe7 --- /dev/null +++ b/usr/src/lib/libv12n/common/mapfile-vers @@ -0,0 +1,50 @@ +# +# 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 2010 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# MAPFILE HEADER START +# +# WARNING: STOP NOW. DO NOT MODIFY THIS FILE. +# Object versioning must comply with the rules detailed in +# +# usr/src/lib/README.mapfiles +# +# You should not be making modifications here until you've read the most current +# copy of that file. If you need help, contact a gatekeeper for guidance. +# +# MAPFILE HEADER END +# + +SUNW_1.1 { + global: + v12n_capabilities; + v12n_domain_roles; + v12n_domain_name; + v12n_ctrl_domain; + v12n_domain_uuid; + v12n_chassis_serialno; + local: + *; +}; diff --git a/usr/src/lib/libv12n/sparc/Makefile b/usr/src/lib/libv12n/sparc/Makefile new file mode 100644 index 0000000000..2d76647e9f --- /dev/null +++ b/usr/src/lib/libv12n/sparc/Makefile @@ -0,0 +1,53 @@ +# +# 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 2010 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# + +MACHCOBJS = libv12n.o + +CMNOBJS= mdesc_findname.o \ + mdesc_findnodeprop.o \ + mdesc_fini.o \ + mdesc_getpropval.o \ + mdesc_getpropstr.o \ + mdesc_init_intern.o \ + mdesc_nodecount.o \ + mdesc_rootnode.o \ + mdesc_scandag.o + +OBJS += $(CMNOBJS) + +include ../Makefile.com + +C99MODE = $(C99_ENABLE) + +LDLIBS += -luuid -lc + +CPPFLAGS += -I. -I$(SRC)/lib/libds/common -I$(SRC)/cmd/ldmad + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) + +pics/%.o: $(SRC)/common/mdesc/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) diff --git a/usr/src/lib/libv12n/sparc/libv12n.c b/usr/src/lib/libv12n/sparc/libv12n.c new file mode 100644 index 0000000000..8a2dd7892a --- /dev/null +++ b/usr/src/lib/libv12n/sparc/libv12n.c @@ -0,0 +1,870 @@ +/* + * 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 2010 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <dlfcn.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <strings.h> +#include <synch.h> +#include <thread.h> +#include <unistd.h> +#include <utility.h> +#include <sys/mdesc.h> +#include <sys/mdesc_impl.h> +#include <sys/debug.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/utsname.h> + +#include "ldma.h" +#include "libds.h" +#include "libv12n.h" + +/* + * sun4 support for libv12n. + * + * Non-sun4v support is minimal. The v12n_capabilities() function will + * only return 0 (not supported, not enabled, no implementation). + * + * For sun4v the support for v12n_capabilities(), v12n_domain_roles(), + * v12n_domain_name() and v12n_domain_uuid() are supported by scanning the + * MD from /dev/mdesc for specific properties. For v12n_ctrl_domain() and + * v12n_chassis_serialno(), the ldoms agent daemon (ldmad) on the control + * domain supplies the required information via the "agent-system" domain + * service. + */ + +/* libds statics */ +static void *v12n_ds_dlhdl = NULL; +static int (*v12n_ds_send_msg)(ds_hdl_t, void *, size_t) = NULL; +static int (*v12n_ds_clnt_reg)(ds_capability_t *, ds_ops_t *); +static int (*v12n_ds_unreg_svc)(char *, boolean_t); + +/* + * Defines to support the 'agent-system' domain service. + */ + +#define LDMA_SYSTEM_NVERS \ + (sizeof (v12n_ldma_system_vers) / sizeof (ds_ver_t)) +static ds_ver_t v12n_ldma_system_vers[] = { { 1, 0} }; + +static ds_capability_t v12n_ldma_cap = { + LDMA_NAME_SYSTEM, /* svc_id */ + v12n_ldma_system_vers, /* vers */ + LDMA_SYSTEM_NVERS /* nvers */ +}; + +static void v12n_ldma_register_handler(ds_hdl_t hdl, ds_cb_arg_t arg, + ds_ver_t *ver, ds_domain_hdl_t dhdl); +static void v12n_ldma_data_handler(ds_hdl_t hdl, ds_cb_arg_t arg, void *buf, + size_t buflen); + +static ds_ops_t v12n_ldma_ops = { + v12n_ldma_register_handler, /* ds_reg_cb */ + NULL, /* ds_unreg_cb */ + v12n_ldma_data_handler, /* ds_data_cb */ + NULL /* ds_cb_arg */ +}; + +/* v12n_ldma_cv_state values */ +#define V12N_LDMA_CVINVALID -1 /* invalid value for cv_state */ +#define V12N_LDMA_REGWAITING 0 /* waiting for ctrl domain reg */ +#define V12N_LDMA_REGRECEIVED 1 /* received ctrl domain reg */ +#define V12N_LDMA_MSGWAITING 2 /* waiting for message response */ +#define V12N_LDMA_MSGRECEIVED 3 /* received message response */ +#define V12N_LDMA_MSGERROR 4 /* received a bad message */ + +/* 'agent-system' data used in async registration/data message handlers */ +static ds_hdl_t v12n_ldma_ctrl_hdl = DS_INVALID_HDL; +static int v12n_ldma_msgtype; +static char *v12n_ldma_msgstr; +static mutex_t v12n_ldma_lock = DEFAULTMUTEX; +static cond_t v12n_ldma_cv = DEFAULTCV; +static int v12n_ldma_cv_state = V12N_LDMA_CVINVALID; +static mutex_t v12n_ldma_cv_lock = DEFAULTMUTEX; + +/* 'agent-system' timeout values in seconds */ +static int v12n_ldma_timeout = 15; +static int v12n_ldma_sleeptime = 1; + + +#define V12N_LDOMS_SUPPORTED (V12N_CAP_SUPPORTED | V12N_CAP_ENABLED | \ + V12N_CAP_IMPL_LDOMS) + +#define MD_DEVICE "/dev/mdesc" + +/* + * libv12n routines to support /dev/mdesc. + */ + +/* + * Wrapper for MD free: need unused size argument. + */ +/* ARGSUSED */ +static void +v12n_md_free(void *buf, size_t n) +{ + free(buf); +} + +/* + * Wrapper for MD init: read MD and invoke md_init_intern. + */ +static md_t * +v12n_md_init() +{ + md_t *mdp; + char *buf = NULL; + md_header_t mdh; + int md_size; + int fd; + + /* + * Open the Machine Description (MD) + */ + fd = open(MD_DEVICE, O_RDONLY); + if (fd == -1) { + return (NULL); + } + + if (read(fd, &mdh, sizeof (md_header_t)) != sizeof (md_header_t)) + goto errdone; + + md_size = sizeof (md_header_t) + mdh.node_blk_sz + mdh.name_blk_sz + + mdh.data_blk_sz; + + if ((buf = malloc(md_size)) == NULL) + goto errdone; + + (void) memcpy(buf, &mdh, sizeof (md_header_t)); + if (read(fd, buf + sizeof (md_header_t), + md_size - sizeof (md_header_t)) != md_size - sizeof (md_header_t)) { + goto errdone; + } + + mdp = md_init_intern((uint64_t *)((void *)buf), malloc, v12n_md_free); + + (void) close(fd); + + return (mdp); + +errdone: + (void) close(fd); + free(buf); + + return (NULL); +} + +/* + * Wrapper for md_fini. Allow NULL md ptr and free MD buffer. + */ +static void +v12n_md_fini(void *md) +{ + md_impl_t *mdp = (md_impl_t *)md; + + if (mdp) { + free(mdp->caddr); + (void) md_fini(md); + } +} + +/* + * See if LDoms domaining is enabled, returns 1 if enabled. + * Get the value of the 'domaining-enabled' property under the + * 'platform' node. Value of 1 => domaining is enabled. + */ +static int +v12n_domaining_enabled() +{ + mde_cookie_t *nodes, rootnode; + int nnodes; + uint64_t prop_val = 0; + md_t *mdp; + + if ((mdp = v12n_md_init()) == NULL) { + return (0); + } + + nnodes = md_node_count(mdp); + nodes = malloc(nnodes * sizeof (mde_cookie_t)); + if (nodes == NULL) { + v12n_md_fini(mdp); + return (0); + } + + rootnode = md_root_node(mdp); + + nnodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "platform"), + md_find_name(mdp, "fwd"), nodes); + + if (nnodes >= 1) { + (void) md_get_prop_val(mdp, nodes[0], "domaining-enabled", + &prop_val); + } + + v12n_md_fini(mdp); + free(nodes); + return (prop_val == 1); +} + +int +v12n_capabilities() +{ + struct utsname uinfo; + struct stat st; + int cap; + + /* + * Check if this is an LDoms system. When using LDoms each + * domain should have a /dev/mdesc device providing access to + * the Machine Description (MD) of the domain. If this device + * does not exist then this is not an LDoms system. + */ + if (uname(&uinfo) == -1 || strcmp(uinfo.machine, "sun4v")) { + /* + * Not sun4v -> LDoms not supported + */ + cap = 0; + } else if (stat(MD_DEVICE, &st) == 0) { + /* + * sun4v + /dev/mdesc exists -> Check if LDoms enabled + * via the 'domaining-enabled' property. + */ + cap = (V12N_CAP_SUPPORTED | V12N_CAP_IMPL_LDOMS | + (v12n_domaining_enabled() ? V12N_CAP_ENABLED : 0)); + } else if (errno == ENOENT) { + /* + * sun4v + /dev/mdesc does not exist -> LDoms supported + * but not enabled. + */ + cap = (V12N_CAP_SUPPORTED | V12N_CAP_IMPL_LDOMS); + } + + return (cap); +} + +/* + * Routines to support v12n_domain_roles. + */ +static int +v12n_scan_md_nodes(md_t *mdp, char *node_name, char *node_str_prop, + char **props) +{ + mde_cookie_t *nodes, rootnode; + int nnodes, i, j; + char *prop_str; + + nnodes = md_node_count(mdp); + nodes = malloc(nnodes * sizeof (mde_cookie_t)); + if (nodes == NULL) { + return (0); + } + + rootnode = md_root_node(mdp); + + nnodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, node_name), + md_find_name(mdp, "fwd"), nodes); + + if (node_str_prop == NULL) + return (nnodes > 0); + + for (i = 0; i < nnodes; i++) { + if (md_get_prop_str(mdp, nodes[i], node_str_prop, &prop_str)) + continue; + for (j = 0; props[j] != NULL; j++) { + if (strcmp(prop_str, props[j]) == 0) { + free(nodes); + return (1); + } + } + } + free(nodes); + return (0); +} + +/* + * Check if MD has a hypervisor access point, returns 1 if true. + * Check the MD for a 'virtual-device-port' node whose 'vldc-svc-name' is + * 'hvctl'. + */ +static int +v12n_check_hv_access(md_t *mdp) +{ + static char *hvctl_str[] = { + "hvctl", + NULL + }; + + return (v12n_scan_md_nodes(mdp, "virtual-device-port", "vldc-svc-name", + hvctl_str)); +} + +/* + * Check if MD has a virtual device service (vcc, vsw, vds), returns 1 if true. + * Need to check all the MD 'virtual-device' nodes for a 'device-type' property + * of 'vcc', 'vsw' or 'vds'. + */ +static int +v12n_check_virtual_service(md_t *mdp) +{ + static char *vdevs[] = { + "vcc", + "vsw", + "vds", + NULL + }; + + return (v12n_scan_md_nodes(mdp, "virtual-device", "device-type", + vdevs)); +} + +/* + * Check if MD has an physical I/O device node, returns 1 if true. + */ +static int +v12n_check_io_service(md_t *mdp) +{ + return (v12n_scan_md_nodes(mdp, "iodevice", NULL, NULL)); +} + +/* + * Check if a MD node is root PCI device, returns 1 if true. + * Need to check all the MD 'iodevice' nodes for a 'device-type' property + * of 'pciex'. + */ +static int +v12n_check_root(md_t *mdp) +{ + static char *pciex[] = { + "pciex", + NULL + }; + + return (v12n_scan_md_nodes(mdp, "iodevice", "device-type", pciex)); +} + +/* + * Get the domain roles for the domain. + */ +int +v12n_domain_roles() +{ + md_t *mdp; + int roles = 0; + + if (v12n_capabilities() != V12N_LDOMS_SUPPORTED) { + errno = ENOTSUP; + return (-1); + } + + if ((mdp = v12n_md_init()) == NULL) { + errno = EACCES; + return (-1); + } + + if (v12n_check_hv_access(mdp)) + roles |= V12N_ROLE_CONTROL; + + if (v12n_check_virtual_service(mdp)) + roles |= V12N_ROLE_SERVICE; + + if (v12n_check_io_service(mdp)) + roles |= V12N_ROLE_IO; + + if (v12n_check_root(mdp)) + roles |= V12N_ROLE_ROOT; + + v12n_md_fini(mdp); + + return (roles); +} + +/* + * Get domain name from MD's virtual domain service node, returns 1 on success. + * The domain name is a string property 'vlds-domain-name' under the + * 'virtual-device' device node whose name is 'virtual-domain-service'. + */ +static int +v12n_get_md_domain_name(md_t *mdp, char **vds_dnamep) +{ + mde_cookie_t *vdev_nodes, rootnode; + int list_size, nvdevs, num_nodes, i, rv; + char *vldc_name; + + num_nodes = md_node_count(mdp); + list_size = num_nodes * sizeof (mde_cookie_t); + vdev_nodes = malloc(list_size); + if (vdev_nodes == NULL) { + return (0); + } + + rootnode = md_root_node(mdp); + + nvdevs = md_scan_dag(mdp, rootnode, md_find_name(mdp, "virtual-device"), + md_find_name(mdp, "fwd"), vdev_nodes); + + rv = 0; + for (i = 0; i < nvdevs; i++) { + if (md_get_prop_str(mdp, vdev_nodes[i], "name", &vldc_name)) + continue; + if (strcmp(vldc_name, "virtual-domain-service") == 0) { + rv = (md_get_prop_str(mdp, vdev_nodes[i], + "vlds-domain-name", vds_dnamep) == 0); + break; + } + } + free(vdev_nodes); + return (rv); +} + +/* + * String copyout utility. + */ +static size_t +v12n_string_copyout(char *sout, char *sfrom, size_t count) +{ + size_t ret = strlen(sfrom) + 1; + + if (sout != NULL && count > 0) { + count = MIN(ret, count); + (void) memcpy(sout, sfrom, count); + } + return (ret); +} + +/* + * Get the domain name of this domain. + */ +size_t +v12n_domain_name(char *buf, size_t count) +{ + md_t *mdp = NULL; + char *ldmname; + int rv = -1; + + if (v12n_capabilities() != V12N_LDOMS_SUPPORTED) { + errno = ENOTSUP; + } else if ((mdp = v12n_md_init()) == NULL) { + errno = EACCES; + } else if (!v12n_get_md_domain_name(mdp, &ldmname)) { + errno = ESRCH; + } else { + rv = v12n_string_copyout(buf, ldmname, count); + } + + v12n_md_fini(mdp); + return (rv); +} + +/* + * Get UUID string from MD, returns 1 on success. + * The UUID is a string property 'uuid' under the 'platform' node of the MD. + */ +static int +v12n_get_md_uuid_str(md_t *mdp, char **uuid_strp) +{ + mde_cookie_t *plat_nodes, rootnode; + int list_size, npnodes, num_nodes, rv; + + num_nodes = md_node_count(mdp); + list_size = num_nodes * sizeof (mde_cookie_t); + plat_nodes = malloc(list_size); + if (plat_nodes == NULL) { + return (0); + } + + rootnode = md_root_node(mdp); + + npnodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "platform"), + md_find_name(mdp, "fwd"), plat_nodes); + + if (npnodes >= 1) + rv = !md_get_prop_str(mdp, plat_nodes[0], "uuid", uuid_strp); + else + rv = 0; + + free(plat_nodes); + return (rv); +} + +/* + * Get the domain UUID. + */ +int +v12n_domain_uuid(uuid_t uuid) +{ + md_t *mdp = NULL; + char *uuid_str; + int rv = -1; + + if (v12n_capabilities() != V12N_LDOMS_SUPPORTED) { + errno = ENOTSUP; + } else if ((mdp = v12n_md_init()) == NULL) { + errno = EACCES; + } else if (!v12n_get_md_uuid_str(mdp, &uuid_str)) { + errno = ESRCH; + } else { + rv = uuid_parse(uuid_str, uuid); + } + + v12n_md_fini(mdp); + + return (rv); +} + +/* + * Send 'agent-sytem' request message. + */ +static int +v12n_ldma_send_request() +{ + ldma_message_header_t ldmamsg; + + if (v12n_ds_send_msg == NULL || v12n_ldma_ctrl_hdl == DS_INVALID_HDL) + return (ENOENT); + + ldmamsg.msg_num = 0; + ldmamsg.msg_type = v12n_ldma_msgtype; + ldmamsg.msg_info = 0; + return (v12n_ds_send_msg(v12n_ldma_ctrl_hdl, (char *)&ldmamsg, + sizeof (ldmamsg))); +} + +/* + * 'agent-system' registration handler. + * If we get a registration from the control domain (domain 0), then send + * the requested message. Otherwise, ignore the registration. + */ +/* ARGSUSED */ +static void +v12n_ldma_register_handler(ds_hdl_t hdl, ds_cb_arg_t arg, ds_ver_t *ver, + ds_domain_hdl_t dhdl) +{ + + /* got registration from control domain */ + if (dhdl == 0) { + (void) mutex_lock(&v12n_ldma_cv_lock); + if (v12n_ldma_cv_state == V12N_LDMA_REGWAITING) { + v12n_ldma_ctrl_hdl = hdl; + v12n_ldma_cv_state = V12N_LDMA_REGRECEIVED; + (void) cond_signal(&v12n_ldma_cv); + } + (void) mutex_unlock(&v12n_ldma_cv_lock); + } +} + +/* + * 'agent-system' data handler. + */ +/* ARGSUSED */ +static void +v12n_ldma_data_handler(ds_hdl_t hdl, ds_cb_arg_t arg, void *buf, + size_t buflen) +{ + char *data; + ldma_message_header_t *ldmp; + int n; + int cv_state = V12N_LDMA_MSGERROR; + + /* + * Ignore any message not from the control domain. + */ + if (v12n_ldma_ctrl_hdl != hdl) + return; + + /* + * Ignore any unexpected message. + */ + if (buflen < LDMA_MESSAGE_HEADER_SIZE) + return; + + /* + * Ignore message with unexpected msgnum. + */ + ldmp = (ldma_message_header_t *)buf; + if (ldmp->msg_num != 0) + return; + + switch (ldmp->msg_type) { + + case LDMA_MSG_RESULT: + if (ldmp->msg_info == 0 || + ldmp->msg_info > LDMA_MESSAGE_DLEN(buflen)) { + cv_state = V12N_LDMA_MSGERROR; + break; + } + data = LDMA_HDR2DATA(buf); + + /* ensure that data ends with a '\0' */ + data[ldmp->msg_info - 1] = '\0'; + switch (v12n_ldma_msgtype) { + + case LDMA_MSGSYS_GET_SYSINFO: + /* + * Control domain nodename is second string in the + * message. Make sure there is enough data in the msg + * to have a second string. + */ + n = strlen(data); + if (LDMA_MESSAGE_DLEN(buflen) <= n + 3) { + cv_state = V12N_LDMA_MSGERROR; + break; + } + data += n + 1; + if ((v12n_ldma_msgstr = strdup(data)) == NULL) + cv_state = V12N_LDMA_MSGERROR; + else + cv_state = V12N_LDMA_MSGRECEIVED; + break; + + case LDMA_MSGSYS_GET_CHASSISNO: + if ((v12n_ldma_msgstr = strdup(data)) == NULL) + cv_state = V12N_LDMA_MSGERROR; + else + cv_state = V12N_LDMA_MSGRECEIVED; + break; + + default: + /* v12n_ldma_msgtype must be valid */ + ASSERT(0); + } + break; + + case LDMA_MSG_ERROR: + cv_state = V12N_LDMA_MSGERROR; + break; + + default: + /* unexpected message, ignored */ + return; + } + + (void) mutex_lock(&v12n_ldma_cv_lock); + v12n_ldma_cv_state = cv_state; + (void) cond_signal(&v12n_ldma_cv); + (void) mutex_unlock(&v12n_ldma_cv_lock); +} + + +/* + * libds doesn't exist on non-sun4v, dynamically load it and get the + * function pointers to the needed lib functions. + */ +static int +v12n_libds_init(void) +{ + if (v12n_ds_dlhdl != NULL) { + if (v12n_ds_clnt_reg == NULL || v12n_ds_send_msg == NULL || + v12n_ds_unreg_svc == NULL) + return (ENOENT); + return (0); + } + + if ((v12n_ds_dlhdl = dlopen("libds.so.1", + RTLD_NOW | RTLD_GLOBAL)) == NULL) + return (ENOENT); + + if ((v12n_ds_clnt_reg = (int (*)(ds_capability_t *, ds_ops_t *)) + dlsym(v12n_ds_dlhdl, "ds_clnt_reg")) == NULL) + return (ENOENT); + + if ((v12n_ds_send_msg = (int (*)(ds_hdl_t, void *, size_t)) + dlsym(v12n_ds_dlhdl, "ds_send_msg")) == NULL) + return (ENOENT); + + if ((v12n_ds_unreg_svc = (int (*)(char *, boolean_t)) + dlsym(v12n_ds_dlhdl, "ds_unreg_svc")) == NULL) + return (ENOENT); + + return (0); +} + +/* + * Initiate and wait for an ldmad 'agent-system' domain service. + * Dynamically load libds, register the client 'agent-system' service + * and wait for a specified amount of time for the 'agent-system' + * service on the control domain to respond to the request. + */ +static int +v12n_get_ldma_system_msg(int msgtype, char **strp) +{ + int tout; + int err = 0; + timestruc_t timeout; + + /* + * Ensure that there's only one thread trying to do a + * 'agent-system' client registration/message at a time. + */ + (void) mutex_lock(&v12n_ldma_lock); + if ((err = v12n_libds_init()) != 0) + goto done; + + v12n_ldma_msgtype = msgtype; + v12n_ldma_msgstr = NULL; + + /* initialize v12n_ldma_cv_state variable before registering service */ + (void) mutex_lock(&v12n_ldma_cv_lock); + v12n_ldma_cv_state = V12N_LDMA_REGWAITING; + (void) mutex_unlock(&v12n_ldma_cv_lock); + + /* + * Other instances may be trying to load the "agent-system" service. + * If a collision happens (EBUSY error), wait and try again. + */ + for (tout = 0; tout < v12n_ldma_timeout; tout += v12n_ldma_sleeptime) { + if ((err = v12n_ds_clnt_reg(&v12n_ldma_cap, + &v12n_ldma_ops)) == 0) + break; + if (err != EALREADY) { + goto done; + } + (void) sleep(v12n_ldma_sleeptime); + } + + if (tout >= v12n_ldma_timeout) { + err = EBUSY; + goto done; + } + + /* + * Wait for control domain registration. + */ + timeout.tv_sec = v12n_ldma_timeout; + timeout.tv_nsec = 0; + + (void) mutex_lock(&v12n_ldma_cv_lock); + while (v12n_ldma_cv_state == V12N_LDMA_REGWAITING) { + if ((err = cond_reltimedwait(&v12n_ldma_cv, + &v12n_ldma_cv_lock, &timeout)) != EINTR) + break; + } + + /* + * Check for timeout or an error. + */ + if (v12n_ldma_cv_state != V12N_LDMA_REGRECEIVED) { + if (err == 0) + err = EPROTO; + (void) mutex_unlock(&v12n_ldma_cv_lock); + goto done; + } + + /* + * Received a registration request, send the request message. + */ + v12n_ldma_cv_state = V12N_LDMA_MSGWAITING; + if ((err = v12n_ldma_send_request()) != 0) { + (void) mutex_unlock(&v12n_ldma_cv_lock); + goto done; + } + + while (v12n_ldma_cv_state == V12N_LDMA_MSGWAITING) { + if ((err = cond_reltimedwait(&v12n_ldma_cv, + &v12n_ldma_cv_lock, &timeout)) != EINTR) + break; + } + + if (v12n_ldma_cv_state != V12N_LDMA_MSGRECEIVED) { + if (err == 0) + err = EPROTO; + (void) mutex_unlock(&v12n_ldma_cv_lock); + goto done; + } + + v12n_ldma_cv_state = V12N_LDMA_CVINVALID; + (void) mutex_unlock(&v12n_ldma_cv_lock); + + /* + * If v12n_ldma_msgstr is set, a valid data response was seen. + */ + if (v12n_ldma_msgstr == NULL) + err = ENODATA; + else { + if (*v12n_ldma_msgstr == '\0' || + (*strp = strdup(v12n_ldma_msgstr)) == NULL) + err = ENODATA; + free(v12n_ldma_msgstr); + v12n_ldma_msgstr = NULL; + } + +done: + v12n_ds_unreg_svc(LDMA_NAME_SYSTEM, B_TRUE); + v12n_ldma_msgtype = -1; + v12n_ldma_ctrl_hdl = DS_INVALID_HDL; + (void) mutex_unlock(&v12n_ldma_lock); + + return (err); +} + +/* + * Get the nodename of the control domain. Returns the equivalent + * of 'uname -n' on the control domain. + * This is obtained via the 'agent-system' domain service provided + * by ldmad. + */ +size_t +v12n_ctrl_domain(char *buf, size_t count) +{ + char *str; + int err; + size_t rv = (size_t)(-1); + + if (v12n_capabilities() != V12N_LDOMS_SUPPORTED) { + errno = ENOTSUP; + } else if ((err = v12n_get_ldma_system_msg(LDMA_MSGSYS_GET_SYSINFO, + &str)) != 0) { + errno = err; + } else { + rv = v12n_string_copyout(buf, str, count); + } + return (rv); +} + +/* + * Get the Chassis serial number from the Control Domain. + * This is obtained via the 'agent-system' domain service provided + * by ldmad. + */ +size_t +v12n_chassis_serialno(char *buf, size_t count) +{ + char *str; + int err; + size_t rv = (size_t)(-1); + + if (v12n_capabilities() != V12N_LDOMS_SUPPORTED) { + errno = ENOTSUP; + } else if ((err = v12n_get_ldma_system_msg(LDMA_MSGSYS_GET_CHASSISNO, + &str)) != 0) { + errno = err; + } else { + rv = v12n_string_copyout(buf, str, count); + } + return (rv); +} diff --git a/usr/src/lib/libv12n/sparcv9/Makefile b/usr/src/lib/libv12n/sparcv9/Makefile new file mode 100644 index 0000000000..a03fd47ade --- /dev/null +++ b/usr/src/lib/libv12n/sparcv9/Makefile @@ -0,0 +1,54 @@ +# +# 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 2010 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# + +MACHCOBJS = libv12n.o + +CMNOBJS= mdesc_findname.o \ + mdesc_findnodeprop.o \ + mdesc_fini.o \ + mdesc_getpropval.o \ + mdesc_getpropstr.o \ + mdesc_init_intern.o \ + mdesc_nodecount.o \ + mdesc_rootnode.o \ + mdesc_scandag.o + +OBJS += $(CMNOBJS) + +include ../Makefile.com +include ../../Makefile.lib.64 + +C99MODE = $(C99_ENABLE) + +LDLIBS += -luuid -lc + +CPPFLAGS += -I. -I$(SRC)/lib/libds/common -I$(SRC)/cmd/ldmad + +install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64) + +pics/%.o: $(SRC)/common/mdesc/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) |