/*
* 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
* 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
*/
/*
*/
#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_impl.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
* v12n_chassis_serialno(), the ldoms agent daemon (ldmad) on the control
* domain supplies the required information via the "agent-system" domain
* service.
*/
/* libds statics */
/*
* Defines to support the 'agent-system' domain service.
*/
#define LDMA_SYSTEM_NVERS \
(sizeof (v12n_ldma_system_vers) / sizeof (ds_ver_t))
LDMA_NAME_SYSTEM, /* svc_id */
v12n_ldma_system_vers, /* vers */
LDMA_SYSTEM_NVERS /* nvers */
};
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 */
/* 'agent-system' data used in async registration/data message handlers */
static int v12n_ldma_msgtype;
static char *v12n_ldma_msgstr;
/* 'agent-system' timeout values in seconds */
/*
*/
/*
* Wrapper for MD free: need unused size argument.
*/
/* ARGSUSED */
static void
{
}
/*
* Wrapper for MD init: read MD and invoke md_init_intern.
*/
static md_t *
{
int md_size;
int fd;
/*
* Open the Machine Description (MD)
*/
if (fd == -1) {
return (NULL);
}
goto errdone;
goto errdone;
goto errdone;
}
return (mdp);
return (NULL);
}
/*
* Wrapper for md_fini. Allow NULL md ptr and free MD buffer.
*/
static void
{
if (mdp) {
}
}
/*
* 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
{
int nnodes;
return (0);
}
return (0);
}
if (nnodes >= 1) {
&prop_val);
}
return (prop_val == 1);
}
int
{
int cap;
/*
* Check if this is an LDoms system. When using LDoms each
* the Machine Description (MD) of the domain. If this device
* does not exist then this is not an LDoms system.
*/
/*
* Not sun4v -> LDoms not supported
*/
cap = 0;
/*
* via the 'domaining-enabled' property.
*/
(v12n_domaining_enabled() ? V12N_CAP_ENABLED : 0));
/*
* but not enabled.
*/
}
return (cap);
}
/*
* Routines to support v12n_domain_roles.
*/
static int
char **props)
{
int nnodes, i, j;
char *prop_str;
return (0);
}
if (node_str_prop == NULL)
return (nnodes > 0);
for (i = 0; i < nnodes; i++) {
continue;
return (1);
}
}
}
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
{
static char *hvctl_str[] = {
"hvctl",
};
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
{
static char *vdevs[] = {
"vcc",
"vsw",
"vds",
};
vdevs));
}
/*
* Check if MD has an physical I/O device node, returns 1 if true.
*/
static int
{
}
/*
* 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'. If there are any of these without a 'virtual-root-complex'
* property or that property is not 1, then it is a root complex. If
* there are 'pciex' nodes, but with 'virtual-root-complex' property of 1,
* then these are ignored.
*/
static int
{
char *prop_str;
return (0);
}
for (i = 0; i < nnodes; i++) {
continue;
continue;
/*
* Check if this pciex iodevice node has the
* 'virtual-root-complex' property with value 1. If it does,
* it is a SDIO virtual root complex and not a root complex.
* If it doesn't, it is a root complex.
*/
rv = 1;
break;
}
}
return (rv);
}
/*
* Get the domain roles for the domain.
*/
int
{
int roles = 0;
if (v12n_capabilities() != V12N_LDOMS_SUPPORTED) {
return (-1);
}
return (-1);
}
if (v12n_check_hv_access(mdp))
if (v12n_check_io_service(mdp))
roles |= V12N_ROLE_IO;
if (v12n_check_root(mdp))
roles |= V12N_ROLE_ROOT;
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
{
char *vldc_name;
if (vdev_nodes == NULL) {
return (0);
}
rv = 0;
for (i = 0; i < nvdevs; i++) {
continue;
"vlds-domain-name", vds_dnamep) == 0);
break;
}
}
return (rv);
}
/*
* String copyout utility.
*/
static size_t
{
}
return (ret);
}
/*
* Get the domain name of this domain.
*/
{
char *ldmname;
if (v12n_capabilities() != V12N_LDOMS_SUPPORTED) {
} else {
}
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
{
if (plat_nodes == NULL) {
return (0);
}
if (npnodes >= 1)
else
rv = 0;
return (rv);
}
/*
* Get the domain UUID.
*/
int
{
char *uuid_str;
if (v12n_capabilities() != V12N_LDOMS_SUPPORTED) {
} else {
}
return (rv);
}
/*
* Send 'agent-sytem' request message.
*/
static int
{
return (ENOENT);
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
{
/* got registration from control domain */
if (dhdl == 0) {
(void) mutex_lock(&v12n_ldma_cv_lock);
if (v12n_ldma_cv_state == V12N_LDMA_REGWAITING) {
(void) cond_signal(&v12n_ldma_cv);
}
(void) mutex_unlock(&v12n_ldma_cv_lock);
}
}
/*
* 'agent-system' data handler.
*/
/* ARGSUSED */
static void
{
char *data;
int n;
/*
* 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.
*/
return;
case LDMA_MSG_RESULT:
break;
}
/* ensure that data ends with a '\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.
*/
break;
}
data += n + 1;
else
break;
else
break;
default:
/* v12n_ldma_msgtype must be valid */
ASSERT(0);
}
break;
case LDMA_MSG_ERROR:
break;
default:
/* unexpected message, ignored */
return;
}
(void) mutex_lock(&v12n_ldma_cv_lock);
(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) {
return (ENOENT);
return (0);
}
return (ENOENT);
return (ENOENT);
return (ENOENT);
if ((v12n_ds_unreg_svc = (int (*)(char *, boolean_t))
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
{
int tout;
int err = 0;
/*
* 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) {
(void) mutex_unlock(&v12n_ldma_lock);
return (err);
}
/* initialize v12n_ldma_cv_state variable before registering service */
(void) mutex_lock(&v12n_ldma_cv_lock);
(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.
*/
&v12n_ldma_ops)) == 0)
break;
goto done;
}
(void) sleep(v12n_ldma_sleeptime);
}
if (tout >= v12n_ldma_timeout) {
goto done;
}
/*
* Wait for control domain registration.
*/
(void) mutex_lock(&v12n_ldma_cv_lock);
while (v12n_ldma_cv_state == V12N_LDMA_REGWAITING) {
break;
}
/*
* Check for timeout or an error.
*/
if (v12n_ldma_cv_state != V12N_LDMA_REGRECEIVED) {
if (err == 0)
(void) mutex_unlock(&v12n_ldma_cv_lock);
goto done;
}
/*
* Received a registration request, send the request message.
*/
if ((err = v12n_ldma_send_request()) != 0) {
(void) mutex_unlock(&v12n_ldma_cv_lock);
goto done;
}
while (v12n_ldma_cv_state == V12N_LDMA_MSGWAITING) {
break;
}
if (v12n_ldma_cv_state != V12N_LDMA_MSGRECEIVED) {
if (err == 0)
(void) mutex_unlock(&v12n_ldma_cv_lock);
goto done;
}
(void) mutex_unlock(&v12n_ldma_cv_lock);
/*
* If v12n_ldma_msgstr is set, a valid data response was seen.
*/
if (v12n_ldma_msgstr == NULL)
else {
if (*v12n_ldma_msgstr == '\0' ||
}
done:
v12n_ldma_msgtype = -1;
(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.
*/
{
char *str;
int err;
if (v12n_capabilities() != V12N_LDOMS_SUPPORTED) {
&str)) != 0) {
} else {
}
return (rv);
}
/*
* Get the Chassis serial number from the Control Domain.
* This is obtained via the 'agent-system' domain service provided
* by ldmad.
*/
{
char *str;
int err;
if (v12n_capabilities() != V12N_LDOMS_SUPPORTED) {
&str)) != 0) {
} else {
}
return (rv);
}