xref: /onnv-gate/usr/src/lib/libv12n/sparc/libv12n.c (revision 12913:fd395ba5d913)
111833SMichael.Christensen@Sun.COM /*
211833SMichael.Christensen@Sun.COM  * CDDL HEADER START
311833SMichael.Christensen@Sun.COM  *
411833SMichael.Christensen@Sun.COM  * The contents of this file are subject to the terms of the
511833SMichael.Christensen@Sun.COM  * Common Development and Distribution License (the "License").
611833SMichael.Christensen@Sun.COM  * You may not use this file except in compliance with the License.
711833SMichael.Christensen@Sun.COM  *
811833SMichael.Christensen@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911833SMichael.Christensen@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1011833SMichael.Christensen@Sun.COM  * See the License for the specific language governing permissions
1111833SMichael.Christensen@Sun.COM  * and limitations under the License.
1211833SMichael.Christensen@Sun.COM  *
1311833SMichael.Christensen@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1411833SMichael.Christensen@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511833SMichael.Christensen@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1611833SMichael.Christensen@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1711833SMichael.Christensen@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1811833SMichael.Christensen@Sun.COM  *
1911833SMichael.Christensen@Sun.COM  * CDDL HEADER END
2011833SMichael.Christensen@Sun.COM  */
2111833SMichael.Christensen@Sun.COM /*
22*12913SMichael.Christensen@Sun.COM  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2311833SMichael.Christensen@Sun.COM  */
2411833SMichael.Christensen@Sun.COM 
2511833SMichael.Christensen@Sun.COM #include <dlfcn.h>
2611833SMichael.Christensen@Sun.COM #include <errno.h>
2711833SMichael.Christensen@Sun.COM #include <fcntl.h>
2811833SMichael.Christensen@Sun.COM #include <stdio.h>
2911833SMichael.Christensen@Sun.COM #include <stdlib.h>
3011833SMichael.Christensen@Sun.COM #include <strings.h>
3111833SMichael.Christensen@Sun.COM #include <synch.h>
3211833SMichael.Christensen@Sun.COM #include <thread.h>
3311833SMichael.Christensen@Sun.COM #include <unistd.h>
3411833SMichael.Christensen@Sun.COM #include <utility.h>
3511833SMichael.Christensen@Sun.COM #include <sys/mdesc.h>
3611833SMichael.Christensen@Sun.COM #include <sys/mdesc_impl.h>
3711833SMichael.Christensen@Sun.COM #include <sys/debug.h>
3811833SMichael.Christensen@Sun.COM #include <sys/stat.h>
3911833SMichael.Christensen@Sun.COM #include <sys/types.h>
4011833SMichael.Christensen@Sun.COM #include <sys/utsname.h>
4111833SMichael.Christensen@Sun.COM 
4211833SMichael.Christensen@Sun.COM #include "ldma.h"
4311833SMichael.Christensen@Sun.COM #include "libds.h"
4411833SMichael.Christensen@Sun.COM #include "libv12n.h"
4511833SMichael.Christensen@Sun.COM 
4611833SMichael.Christensen@Sun.COM /*
4711833SMichael.Christensen@Sun.COM  * sun4 support for libv12n.
4811833SMichael.Christensen@Sun.COM  *
4911833SMichael.Christensen@Sun.COM  * Non-sun4v support is minimal.  The v12n_capabilities() function will
5011833SMichael.Christensen@Sun.COM  * only return 0 (not supported, not enabled, no implementation).
5111833SMichael.Christensen@Sun.COM  *
5211833SMichael.Christensen@Sun.COM  * For sun4v the support for v12n_capabilities(), v12n_domain_roles(),
5311833SMichael.Christensen@Sun.COM  * v12n_domain_name() and v12n_domain_uuid() are supported by scanning the
5411833SMichael.Christensen@Sun.COM  * MD from /dev/mdesc for specific properties.  For v12n_ctrl_domain() and
5511833SMichael.Christensen@Sun.COM  * v12n_chassis_serialno(), the ldoms agent daemon (ldmad) on the control
5611833SMichael.Christensen@Sun.COM  * domain supplies the required information via the "agent-system" domain
5711833SMichael.Christensen@Sun.COM  * service.
5811833SMichael.Christensen@Sun.COM  */
5911833SMichael.Christensen@Sun.COM 
6011833SMichael.Christensen@Sun.COM /* libds statics */
6111833SMichael.Christensen@Sun.COM static void *v12n_ds_dlhdl = NULL;
6211833SMichael.Christensen@Sun.COM static int (*v12n_ds_send_msg)(ds_hdl_t, void *, size_t) = NULL;
6311833SMichael.Christensen@Sun.COM static int (*v12n_ds_clnt_reg)(ds_capability_t *, ds_ops_t *);
6411833SMichael.Christensen@Sun.COM static int (*v12n_ds_unreg_svc)(char *, boolean_t);
6511833SMichael.Christensen@Sun.COM 
6611833SMichael.Christensen@Sun.COM /*
6711833SMichael.Christensen@Sun.COM  * Defines to support the 'agent-system' domain service.
6811833SMichael.Christensen@Sun.COM  */
6911833SMichael.Christensen@Sun.COM 
7011833SMichael.Christensen@Sun.COM #define	LDMA_SYSTEM_NVERS		\
7111833SMichael.Christensen@Sun.COM 			(sizeof (v12n_ldma_system_vers) / sizeof (ds_ver_t))
7211833SMichael.Christensen@Sun.COM static ds_ver_t v12n_ldma_system_vers[] = { { 1, 0} };
7311833SMichael.Christensen@Sun.COM 
7411833SMichael.Christensen@Sun.COM static ds_capability_t v12n_ldma_cap = {
7511833SMichael.Christensen@Sun.COM 	LDMA_NAME_SYSTEM,	/* svc_id */
7611833SMichael.Christensen@Sun.COM 	v12n_ldma_system_vers,	/* vers */
7711833SMichael.Christensen@Sun.COM 	LDMA_SYSTEM_NVERS	/* nvers */
7811833SMichael.Christensen@Sun.COM };
7911833SMichael.Christensen@Sun.COM 
8011833SMichael.Christensen@Sun.COM static void v12n_ldma_register_handler(ds_hdl_t hdl, ds_cb_arg_t arg,
8111833SMichael.Christensen@Sun.COM     ds_ver_t *ver, ds_domain_hdl_t dhdl);
8211833SMichael.Christensen@Sun.COM static void v12n_ldma_data_handler(ds_hdl_t hdl, ds_cb_arg_t arg, void *buf,
8311833SMichael.Christensen@Sun.COM     size_t buflen);
8411833SMichael.Christensen@Sun.COM 
8511833SMichael.Christensen@Sun.COM static ds_ops_t v12n_ldma_ops = {
8611833SMichael.Christensen@Sun.COM 	v12n_ldma_register_handler,	/* ds_reg_cb */
8711833SMichael.Christensen@Sun.COM 	NULL,				/* ds_unreg_cb */
8811833SMichael.Christensen@Sun.COM 	v12n_ldma_data_handler,		/* ds_data_cb */
8911833SMichael.Christensen@Sun.COM 	NULL				/* ds_cb_arg */
9011833SMichael.Christensen@Sun.COM };
9111833SMichael.Christensen@Sun.COM 
9211833SMichael.Christensen@Sun.COM /* v12n_ldma_cv_state values */
9311833SMichael.Christensen@Sun.COM #define	V12N_LDMA_CVINVALID	-1	/* invalid value for cv_state */
9411833SMichael.Christensen@Sun.COM #define	V12N_LDMA_REGWAITING	0	/* waiting for ctrl domain reg */
9511833SMichael.Christensen@Sun.COM #define	V12N_LDMA_REGRECEIVED	1	/* received ctrl domain reg */
9611833SMichael.Christensen@Sun.COM #define	V12N_LDMA_MSGWAITING	2	/* waiting for message response */
9711833SMichael.Christensen@Sun.COM #define	V12N_LDMA_MSGRECEIVED	3	/* received message response */
9811833SMichael.Christensen@Sun.COM #define	V12N_LDMA_MSGERROR	4	/* received a bad message */
9911833SMichael.Christensen@Sun.COM 
10011833SMichael.Christensen@Sun.COM /* 'agent-system' data used in async registration/data message handlers */
10111833SMichael.Christensen@Sun.COM static ds_hdl_t v12n_ldma_ctrl_hdl = DS_INVALID_HDL;
10211833SMichael.Christensen@Sun.COM static int v12n_ldma_msgtype;
10311833SMichael.Christensen@Sun.COM static char *v12n_ldma_msgstr;
10411833SMichael.Christensen@Sun.COM static mutex_t v12n_ldma_lock = DEFAULTMUTEX;
10511833SMichael.Christensen@Sun.COM static cond_t v12n_ldma_cv = DEFAULTCV;
10611833SMichael.Christensen@Sun.COM static int v12n_ldma_cv_state = V12N_LDMA_CVINVALID;
10711833SMichael.Christensen@Sun.COM static mutex_t v12n_ldma_cv_lock = DEFAULTMUTEX;
10811833SMichael.Christensen@Sun.COM 
10911833SMichael.Christensen@Sun.COM /* 'agent-system' timeout values in seconds */
11011833SMichael.Christensen@Sun.COM static int v12n_ldma_timeout = 15;
11111833SMichael.Christensen@Sun.COM static int v12n_ldma_sleeptime = 1;
11211833SMichael.Christensen@Sun.COM 
11311833SMichael.Christensen@Sun.COM 
11411833SMichael.Christensen@Sun.COM #define	V12N_LDOMS_SUPPORTED	(V12N_CAP_SUPPORTED | V12N_CAP_ENABLED | \
11511833SMichael.Christensen@Sun.COM 				    V12N_CAP_IMPL_LDOMS)
11611833SMichael.Christensen@Sun.COM 
11711833SMichael.Christensen@Sun.COM #define	MD_DEVICE		"/dev/mdesc"
11811833SMichael.Christensen@Sun.COM 
11911833SMichael.Christensen@Sun.COM /*
12011833SMichael.Christensen@Sun.COM  * libv12n routines to support /dev/mdesc.
12111833SMichael.Christensen@Sun.COM  */
12211833SMichael.Christensen@Sun.COM 
12311833SMichael.Christensen@Sun.COM /*
12411833SMichael.Christensen@Sun.COM  * Wrapper for MD free: need unused size argument.
12511833SMichael.Christensen@Sun.COM  */
12611833SMichael.Christensen@Sun.COM /* ARGSUSED */
12711833SMichael.Christensen@Sun.COM static void
v12n_md_free(void * buf,size_t n)12811833SMichael.Christensen@Sun.COM v12n_md_free(void *buf, size_t n)
12911833SMichael.Christensen@Sun.COM {
13011833SMichael.Christensen@Sun.COM 	free(buf);
13111833SMichael.Christensen@Sun.COM }
13211833SMichael.Christensen@Sun.COM 
13311833SMichael.Christensen@Sun.COM /*
13411833SMichael.Christensen@Sun.COM  * Wrapper for MD init: read MD and invoke md_init_intern.
13511833SMichael.Christensen@Sun.COM  */
13611833SMichael.Christensen@Sun.COM static md_t *
v12n_md_init()13711833SMichael.Christensen@Sun.COM v12n_md_init()
13811833SMichael.Christensen@Sun.COM {
13911833SMichael.Christensen@Sun.COM 	md_t *mdp;
14011833SMichael.Christensen@Sun.COM 	char *buf = NULL;
14111833SMichael.Christensen@Sun.COM 	md_header_t mdh;
14211833SMichael.Christensen@Sun.COM 	int md_size;
14311833SMichael.Christensen@Sun.COM 	int fd;
14411833SMichael.Christensen@Sun.COM 
14511833SMichael.Christensen@Sun.COM 	/*
14611833SMichael.Christensen@Sun.COM 	 * Open the Machine Description (MD)
14711833SMichael.Christensen@Sun.COM 	 */
14811833SMichael.Christensen@Sun.COM 	fd = open(MD_DEVICE, O_RDONLY);
14911833SMichael.Christensen@Sun.COM 	if (fd == -1) {
15011833SMichael.Christensen@Sun.COM 		return (NULL);
15111833SMichael.Christensen@Sun.COM 	}
15211833SMichael.Christensen@Sun.COM 
15311833SMichael.Christensen@Sun.COM 	if (read(fd, &mdh, sizeof (md_header_t)) != sizeof (md_header_t))
15411833SMichael.Christensen@Sun.COM 		goto errdone;
15511833SMichael.Christensen@Sun.COM 
15611833SMichael.Christensen@Sun.COM 	md_size = sizeof (md_header_t) + mdh.node_blk_sz + mdh.name_blk_sz +
15711833SMichael.Christensen@Sun.COM 	    mdh.data_blk_sz;
15811833SMichael.Christensen@Sun.COM 
15911833SMichael.Christensen@Sun.COM 	if ((buf = malloc(md_size)) == NULL)
16011833SMichael.Christensen@Sun.COM 		goto errdone;
16111833SMichael.Christensen@Sun.COM 
16211833SMichael.Christensen@Sun.COM 	(void) memcpy(buf, &mdh, sizeof (md_header_t));
16311833SMichael.Christensen@Sun.COM 	if (read(fd, buf + sizeof (md_header_t),
16411833SMichael.Christensen@Sun.COM 	    md_size - sizeof (md_header_t)) != md_size - sizeof (md_header_t)) {
16511833SMichael.Christensen@Sun.COM 		goto errdone;
16611833SMichael.Christensen@Sun.COM 	}
16711833SMichael.Christensen@Sun.COM 
16811833SMichael.Christensen@Sun.COM 	mdp = md_init_intern((uint64_t *)((void *)buf), malloc, v12n_md_free);
16911833SMichael.Christensen@Sun.COM 
17011833SMichael.Christensen@Sun.COM 	(void) close(fd);
17111833SMichael.Christensen@Sun.COM 
17211833SMichael.Christensen@Sun.COM 	return (mdp);
17311833SMichael.Christensen@Sun.COM 
17411833SMichael.Christensen@Sun.COM errdone:
17511833SMichael.Christensen@Sun.COM 	(void) close(fd);
17611833SMichael.Christensen@Sun.COM 	free(buf);
17711833SMichael.Christensen@Sun.COM 
17811833SMichael.Christensen@Sun.COM 	return (NULL);
17911833SMichael.Christensen@Sun.COM }
18011833SMichael.Christensen@Sun.COM 
18111833SMichael.Christensen@Sun.COM /*
18211833SMichael.Christensen@Sun.COM  * Wrapper for md_fini.  Allow NULL md ptr and free MD buffer.
18311833SMichael.Christensen@Sun.COM  */
18411833SMichael.Christensen@Sun.COM static void
v12n_md_fini(void * md)18511833SMichael.Christensen@Sun.COM v12n_md_fini(void *md)
18611833SMichael.Christensen@Sun.COM {
18711833SMichael.Christensen@Sun.COM 	md_impl_t *mdp = (md_impl_t *)md;
18811833SMichael.Christensen@Sun.COM 
18911833SMichael.Christensen@Sun.COM 	if (mdp) {
19011833SMichael.Christensen@Sun.COM 		free(mdp->caddr);
19111833SMichael.Christensen@Sun.COM 		(void) md_fini(md);
19211833SMichael.Christensen@Sun.COM 	}
19311833SMichael.Christensen@Sun.COM }
19411833SMichael.Christensen@Sun.COM 
19511833SMichael.Christensen@Sun.COM /*
19611833SMichael.Christensen@Sun.COM  * See if LDoms domaining is enabled, returns 1 if enabled.
19711833SMichael.Christensen@Sun.COM  * Get the value of the 'domaining-enabled' property under the
19811833SMichael.Christensen@Sun.COM  * 'platform' node.  Value of 1 => domaining is enabled.
19911833SMichael.Christensen@Sun.COM  */
20011833SMichael.Christensen@Sun.COM static int
v12n_domaining_enabled()20111833SMichael.Christensen@Sun.COM v12n_domaining_enabled()
20211833SMichael.Christensen@Sun.COM {
20311833SMichael.Christensen@Sun.COM 	mde_cookie_t *nodes, rootnode;
20411833SMichael.Christensen@Sun.COM 	int nnodes;
20511833SMichael.Christensen@Sun.COM 	uint64_t prop_val = 0;
20611833SMichael.Christensen@Sun.COM 	md_t *mdp;
20711833SMichael.Christensen@Sun.COM 
20811833SMichael.Christensen@Sun.COM 	if ((mdp = v12n_md_init()) == NULL) {
20911833SMichael.Christensen@Sun.COM 		return (0);
21011833SMichael.Christensen@Sun.COM 	}
21111833SMichael.Christensen@Sun.COM 
21211833SMichael.Christensen@Sun.COM 	nnodes = md_node_count(mdp);
21311833SMichael.Christensen@Sun.COM 	nodes = malloc(nnodes * sizeof (mde_cookie_t));
21411833SMichael.Christensen@Sun.COM 	if (nodes == NULL) {
21511833SMichael.Christensen@Sun.COM 		v12n_md_fini(mdp);
21611833SMichael.Christensen@Sun.COM 		return (0);
21711833SMichael.Christensen@Sun.COM 	}
21811833SMichael.Christensen@Sun.COM 
21911833SMichael.Christensen@Sun.COM 	rootnode = md_root_node(mdp);
22011833SMichael.Christensen@Sun.COM 
22111833SMichael.Christensen@Sun.COM 	nnodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "platform"),
22211833SMichael.Christensen@Sun.COM 	    md_find_name(mdp, "fwd"), nodes);
22311833SMichael.Christensen@Sun.COM 
22411833SMichael.Christensen@Sun.COM 	if (nnodes >= 1) {
22511833SMichael.Christensen@Sun.COM 		(void) md_get_prop_val(mdp, nodes[0], "domaining-enabled",
22611833SMichael.Christensen@Sun.COM 		    &prop_val);
22711833SMichael.Christensen@Sun.COM 	}
22811833SMichael.Christensen@Sun.COM 
22911833SMichael.Christensen@Sun.COM 	v12n_md_fini(mdp);
23011833SMichael.Christensen@Sun.COM 	free(nodes);
23111833SMichael.Christensen@Sun.COM 	return (prop_val == 1);
23211833SMichael.Christensen@Sun.COM }
23311833SMichael.Christensen@Sun.COM 
23411833SMichael.Christensen@Sun.COM int
v12n_capabilities()23511833SMichael.Christensen@Sun.COM v12n_capabilities()
23611833SMichael.Christensen@Sun.COM {
23711833SMichael.Christensen@Sun.COM 	struct utsname uinfo;
23811833SMichael.Christensen@Sun.COM 	struct stat st;
23911833SMichael.Christensen@Sun.COM 	int cap;
24011833SMichael.Christensen@Sun.COM 
24111833SMichael.Christensen@Sun.COM 	/*
24211833SMichael.Christensen@Sun.COM 	 * Check if this is an LDoms system. When using LDoms each
24311833SMichael.Christensen@Sun.COM 	 * domain should have a /dev/mdesc device providing access to
24411833SMichael.Christensen@Sun.COM 	 * the Machine Description (MD) of the domain. If this device
24511833SMichael.Christensen@Sun.COM 	 * does not exist then this is not an LDoms system.
24611833SMichael.Christensen@Sun.COM 	 */
24711833SMichael.Christensen@Sun.COM 	if (uname(&uinfo) == -1 || strcmp(uinfo.machine, "sun4v")) {
24811833SMichael.Christensen@Sun.COM 		/*
24911833SMichael.Christensen@Sun.COM 		 * Not sun4v -> LDoms not supported
25011833SMichael.Christensen@Sun.COM 		 */
25111833SMichael.Christensen@Sun.COM 		cap = 0;
25211833SMichael.Christensen@Sun.COM 	} else if (stat(MD_DEVICE, &st) == 0) {
25311833SMichael.Christensen@Sun.COM 		/*
25411833SMichael.Christensen@Sun.COM 		 * sun4v + /dev/mdesc exists -> Check if LDoms enabled
25511833SMichael.Christensen@Sun.COM 		 * via the 'domaining-enabled' property.
25611833SMichael.Christensen@Sun.COM 		 */
25711833SMichael.Christensen@Sun.COM 		cap = (V12N_CAP_SUPPORTED | V12N_CAP_IMPL_LDOMS |
25811833SMichael.Christensen@Sun.COM 		    (v12n_domaining_enabled() ? V12N_CAP_ENABLED : 0));
25911833SMichael.Christensen@Sun.COM 	} else if (errno == ENOENT) {
26011833SMichael.Christensen@Sun.COM 		/*
26111833SMichael.Christensen@Sun.COM 		 * sun4v + /dev/mdesc does not exist -> LDoms supported
26211833SMichael.Christensen@Sun.COM 		 * but not enabled.
26311833SMichael.Christensen@Sun.COM 		 */
26411833SMichael.Christensen@Sun.COM 		cap = (V12N_CAP_SUPPORTED | V12N_CAP_IMPL_LDOMS);
26511833SMichael.Christensen@Sun.COM 	}
26611833SMichael.Christensen@Sun.COM 
26711833SMichael.Christensen@Sun.COM 	return (cap);
26811833SMichael.Christensen@Sun.COM }
26911833SMichael.Christensen@Sun.COM 
27011833SMichael.Christensen@Sun.COM /*
27111833SMichael.Christensen@Sun.COM  * Routines to support v12n_domain_roles.
27211833SMichael.Christensen@Sun.COM  */
27311833SMichael.Christensen@Sun.COM static int
v12n_scan_md_nodes(md_t * mdp,char * node_name,char * node_str_prop,char ** props)27411833SMichael.Christensen@Sun.COM v12n_scan_md_nodes(md_t *mdp, char *node_name, char *node_str_prop,
27511833SMichael.Christensen@Sun.COM     char **props)
27611833SMichael.Christensen@Sun.COM {
27711833SMichael.Christensen@Sun.COM 	mde_cookie_t *nodes, rootnode;
27811833SMichael.Christensen@Sun.COM 	int nnodes, i, j;
27911833SMichael.Christensen@Sun.COM 	char *prop_str;
28011833SMichael.Christensen@Sun.COM 
28111833SMichael.Christensen@Sun.COM 	nnodes = md_node_count(mdp);
28211833SMichael.Christensen@Sun.COM 	nodes = malloc(nnodes * sizeof (mde_cookie_t));
28311833SMichael.Christensen@Sun.COM 	if (nodes == NULL) {
28411833SMichael.Christensen@Sun.COM 		return (0);
28511833SMichael.Christensen@Sun.COM 	}
28611833SMichael.Christensen@Sun.COM 
28711833SMichael.Christensen@Sun.COM 	rootnode = md_root_node(mdp);
28811833SMichael.Christensen@Sun.COM 
28911833SMichael.Christensen@Sun.COM 	nnodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, node_name),
29011833SMichael.Christensen@Sun.COM 	    md_find_name(mdp, "fwd"), nodes);
29111833SMichael.Christensen@Sun.COM 
29211833SMichael.Christensen@Sun.COM 	if (node_str_prop == NULL)
29311833SMichael.Christensen@Sun.COM 		return (nnodes > 0);
29411833SMichael.Christensen@Sun.COM 
29511833SMichael.Christensen@Sun.COM 	for (i = 0; i < nnodes; i++) {
29611833SMichael.Christensen@Sun.COM 		if (md_get_prop_str(mdp, nodes[i], node_str_prop, &prop_str))
29711833SMichael.Christensen@Sun.COM 			continue;
29811833SMichael.Christensen@Sun.COM 		for (j = 0; props[j] != NULL; j++) {
29911833SMichael.Christensen@Sun.COM 			if (strcmp(prop_str, props[j]) == 0) {
30011833SMichael.Christensen@Sun.COM 				free(nodes);
30111833SMichael.Christensen@Sun.COM 				return (1);
30211833SMichael.Christensen@Sun.COM 			}
30311833SMichael.Christensen@Sun.COM 		}
30411833SMichael.Christensen@Sun.COM 	}
30511833SMichael.Christensen@Sun.COM 	free(nodes);
30611833SMichael.Christensen@Sun.COM 	return (0);
30711833SMichael.Christensen@Sun.COM }
30811833SMichael.Christensen@Sun.COM 
30911833SMichael.Christensen@Sun.COM /*
31011833SMichael.Christensen@Sun.COM  * Check if MD has a hypervisor access point, returns 1 if true.
31111833SMichael.Christensen@Sun.COM  * Check the MD for a 'virtual-device-port' node whose 'vldc-svc-name' is
31211833SMichael.Christensen@Sun.COM  * 'hvctl'.
31311833SMichael.Christensen@Sun.COM  */
31411833SMichael.Christensen@Sun.COM static int
v12n_check_hv_access(md_t * mdp)31511833SMichael.Christensen@Sun.COM v12n_check_hv_access(md_t *mdp)
31611833SMichael.Christensen@Sun.COM {
31711833SMichael.Christensen@Sun.COM 	static char *hvctl_str[] = {
31811833SMichael.Christensen@Sun.COM 		"hvctl",
31911833SMichael.Christensen@Sun.COM 		NULL
32011833SMichael.Christensen@Sun.COM 	};
32111833SMichael.Christensen@Sun.COM 
32211833SMichael.Christensen@Sun.COM 	return (v12n_scan_md_nodes(mdp, "virtual-device-port", "vldc-svc-name",
32311833SMichael.Christensen@Sun.COM 	    hvctl_str));
32411833SMichael.Christensen@Sun.COM }
32511833SMichael.Christensen@Sun.COM 
32611833SMichael.Christensen@Sun.COM /*
32711833SMichael.Christensen@Sun.COM  * Check if MD has a virtual device service (vcc, vsw, vds), returns 1 if true.
32811833SMichael.Christensen@Sun.COM  * Need to check all the MD 'virtual-device' nodes for a 'device-type' property
32911833SMichael.Christensen@Sun.COM  * of 'vcc', 'vsw' or 'vds'.
33011833SMichael.Christensen@Sun.COM  */
33111833SMichael.Christensen@Sun.COM static int
v12n_check_virtual_service(md_t * mdp)33211833SMichael.Christensen@Sun.COM v12n_check_virtual_service(md_t *mdp)
33311833SMichael.Christensen@Sun.COM {
33411833SMichael.Christensen@Sun.COM 	static char *vdevs[] = {
33511833SMichael.Christensen@Sun.COM 		"vcc",
33611833SMichael.Christensen@Sun.COM 		"vsw",
33711833SMichael.Christensen@Sun.COM 		"vds",
33811833SMichael.Christensen@Sun.COM 		NULL
33911833SMichael.Christensen@Sun.COM 	};
34011833SMichael.Christensen@Sun.COM 
34111833SMichael.Christensen@Sun.COM 	return (v12n_scan_md_nodes(mdp, "virtual-device", "device-type",
34211833SMichael.Christensen@Sun.COM 	    vdevs));
34311833SMichael.Christensen@Sun.COM }
34411833SMichael.Christensen@Sun.COM 
34511833SMichael.Christensen@Sun.COM /*
34611833SMichael.Christensen@Sun.COM  * Check if MD has an physical I/O device node, returns 1 if true.
34711833SMichael.Christensen@Sun.COM  */
34811833SMichael.Christensen@Sun.COM static int
v12n_check_io_service(md_t * mdp)34911833SMichael.Christensen@Sun.COM v12n_check_io_service(md_t *mdp)
35011833SMichael.Christensen@Sun.COM {
35111833SMichael.Christensen@Sun.COM 	return (v12n_scan_md_nodes(mdp, "iodevice", NULL, NULL));
35211833SMichael.Christensen@Sun.COM }
35311833SMichael.Christensen@Sun.COM 
35411833SMichael.Christensen@Sun.COM /*
35511833SMichael.Christensen@Sun.COM  * Check if a MD node is root PCI device, returns 1 if true.
35611833SMichael.Christensen@Sun.COM  * Need to check all the MD 'iodevice' nodes for a 'device-type' property
35711833SMichael.Christensen@Sun.COM  * of 'pciex'.
35811833SMichael.Christensen@Sun.COM  */
35911833SMichael.Christensen@Sun.COM static int
v12n_check_root(md_t * mdp)36011833SMichael.Christensen@Sun.COM v12n_check_root(md_t *mdp)
36111833SMichael.Christensen@Sun.COM {
36211833SMichael.Christensen@Sun.COM 	static char *pciex[] = {
36311833SMichael.Christensen@Sun.COM 		"pciex",
36411833SMichael.Christensen@Sun.COM 		NULL
36511833SMichael.Christensen@Sun.COM 	};
36611833SMichael.Christensen@Sun.COM 
36711833SMichael.Christensen@Sun.COM 	return (v12n_scan_md_nodes(mdp, "iodevice", "device-type", pciex));
36811833SMichael.Christensen@Sun.COM }
36911833SMichael.Christensen@Sun.COM 
37011833SMichael.Christensen@Sun.COM /*
37111833SMichael.Christensen@Sun.COM  * Get the domain roles for the domain.
37211833SMichael.Christensen@Sun.COM  */
37311833SMichael.Christensen@Sun.COM int
v12n_domain_roles()37411833SMichael.Christensen@Sun.COM v12n_domain_roles()
37511833SMichael.Christensen@Sun.COM {
37611833SMichael.Christensen@Sun.COM 	md_t *mdp;
37711833SMichael.Christensen@Sun.COM 	int roles = 0;
37811833SMichael.Christensen@Sun.COM 
37911833SMichael.Christensen@Sun.COM 	if (v12n_capabilities() != V12N_LDOMS_SUPPORTED) {
38011833SMichael.Christensen@Sun.COM 		errno = ENOTSUP;
38111833SMichael.Christensen@Sun.COM 		return (-1);
38211833SMichael.Christensen@Sun.COM 	}
38311833SMichael.Christensen@Sun.COM 
38411833SMichael.Christensen@Sun.COM 	if ((mdp = v12n_md_init()) == NULL) {
38511833SMichael.Christensen@Sun.COM 		errno = EACCES;
38611833SMichael.Christensen@Sun.COM 		return (-1);
38711833SMichael.Christensen@Sun.COM 	}
38811833SMichael.Christensen@Sun.COM 
38911833SMichael.Christensen@Sun.COM 	if (v12n_check_hv_access(mdp))
39011833SMichael.Christensen@Sun.COM 		roles |= V12N_ROLE_CONTROL;
39111833SMichael.Christensen@Sun.COM 
39211833SMichael.Christensen@Sun.COM 	if (v12n_check_virtual_service(mdp))
39311833SMichael.Christensen@Sun.COM 		roles |= V12N_ROLE_SERVICE;
39411833SMichael.Christensen@Sun.COM 
39511833SMichael.Christensen@Sun.COM 	if (v12n_check_io_service(mdp))
39611833SMichael.Christensen@Sun.COM 		roles |= V12N_ROLE_IO;
39711833SMichael.Christensen@Sun.COM 
39811833SMichael.Christensen@Sun.COM 	if (v12n_check_root(mdp))
39911833SMichael.Christensen@Sun.COM 		roles |= V12N_ROLE_ROOT;
40011833SMichael.Christensen@Sun.COM 
40111833SMichael.Christensen@Sun.COM 	v12n_md_fini(mdp);
40211833SMichael.Christensen@Sun.COM 
40311833SMichael.Christensen@Sun.COM 	return (roles);
40411833SMichael.Christensen@Sun.COM }
40511833SMichael.Christensen@Sun.COM 
40611833SMichael.Christensen@Sun.COM /*
40711833SMichael.Christensen@Sun.COM  * Get domain name from MD's virtual domain service node, returns 1 on success.
40811833SMichael.Christensen@Sun.COM  * The domain name is a string property 'vlds-domain-name' under the
40911833SMichael.Christensen@Sun.COM  * 'virtual-device' device node whose name is 'virtual-domain-service'.
41011833SMichael.Christensen@Sun.COM  */
41111833SMichael.Christensen@Sun.COM static int
v12n_get_md_domain_name(md_t * mdp,char ** vds_dnamep)41211833SMichael.Christensen@Sun.COM v12n_get_md_domain_name(md_t *mdp, char **vds_dnamep)
41311833SMichael.Christensen@Sun.COM {
41411833SMichael.Christensen@Sun.COM 	mde_cookie_t *vdev_nodes, rootnode;
41511833SMichael.Christensen@Sun.COM 	int list_size, nvdevs, num_nodes, i, rv;
41611833SMichael.Christensen@Sun.COM 	char *vldc_name;
41711833SMichael.Christensen@Sun.COM 
41811833SMichael.Christensen@Sun.COM 	num_nodes = md_node_count(mdp);
41911833SMichael.Christensen@Sun.COM 	list_size = num_nodes * sizeof (mde_cookie_t);
42011833SMichael.Christensen@Sun.COM 	vdev_nodes = malloc(list_size);
42111833SMichael.Christensen@Sun.COM 	if (vdev_nodes == NULL) {
42211833SMichael.Christensen@Sun.COM 		return (0);
42311833SMichael.Christensen@Sun.COM 	}
42411833SMichael.Christensen@Sun.COM 
42511833SMichael.Christensen@Sun.COM 	rootnode = md_root_node(mdp);
42611833SMichael.Christensen@Sun.COM 
42711833SMichael.Christensen@Sun.COM 	nvdevs = md_scan_dag(mdp, rootnode, md_find_name(mdp, "virtual-device"),
42811833SMichael.Christensen@Sun.COM 	    md_find_name(mdp, "fwd"), vdev_nodes);
42911833SMichael.Christensen@Sun.COM 
43011833SMichael.Christensen@Sun.COM 	rv = 0;
43111833SMichael.Christensen@Sun.COM 	for (i = 0; i < nvdevs; i++) {
43211833SMichael.Christensen@Sun.COM 		if (md_get_prop_str(mdp, vdev_nodes[i], "name", &vldc_name))
43311833SMichael.Christensen@Sun.COM 			continue;
43411833SMichael.Christensen@Sun.COM 		if (strcmp(vldc_name, "virtual-domain-service") == 0) {
43511833SMichael.Christensen@Sun.COM 			rv = (md_get_prop_str(mdp, vdev_nodes[i],
43611833SMichael.Christensen@Sun.COM 			    "vlds-domain-name", vds_dnamep) == 0);
43711833SMichael.Christensen@Sun.COM 			break;
43811833SMichael.Christensen@Sun.COM 		}
43911833SMichael.Christensen@Sun.COM 	}
44011833SMichael.Christensen@Sun.COM 	free(vdev_nodes);
44111833SMichael.Christensen@Sun.COM 	return (rv);
44211833SMichael.Christensen@Sun.COM }
44311833SMichael.Christensen@Sun.COM 
44411833SMichael.Christensen@Sun.COM /*
44511833SMichael.Christensen@Sun.COM  * String copyout utility.
44611833SMichael.Christensen@Sun.COM  */
44711833SMichael.Christensen@Sun.COM static size_t
v12n_string_copyout(char * sout,char * sfrom,size_t count)44811833SMichael.Christensen@Sun.COM v12n_string_copyout(char *sout, char *sfrom, size_t count)
44911833SMichael.Christensen@Sun.COM {
45011833SMichael.Christensen@Sun.COM 	size_t ret = strlen(sfrom) + 1;
45111833SMichael.Christensen@Sun.COM 
45211833SMichael.Christensen@Sun.COM 	if (sout != NULL && count > 0) {
45311833SMichael.Christensen@Sun.COM 		count = MIN(ret, count);
45411833SMichael.Christensen@Sun.COM 		(void) memcpy(sout, sfrom, count);
45511833SMichael.Christensen@Sun.COM 	}
45611833SMichael.Christensen@Sun.COM 	return (ret);
45711833SMichael.Christensen@Sun.COM }
45811833SMichael.Christensen@Sun.COM 
45911833SMichael.Christensen@Sun.COM /*
46011833SMichael.Christensen@Sun.COM  * Get the domain name of this domain.
46111833SMichael.Christensen@Sun.COM  */
46211833SMichael.Christensen@Sun.COM size_t
v12n_domain_name(char * buf,size_t count)46311833SMichael.Christensen@Sun.COM v12n_domain_name(char *buf, size_t count)
46411833SMichael.Christensen@Sun.COM {
46511833SMichael.Christensen@Sun.COM 	md_t *mdp = NULL;
46611833SMichael.Christensen@Sun.COM 	char *ldmname;
46711833SMichael.Christensen@Sun.COM 	int rv = -1;
46811833SMichael.Christensen@Sun.COM 
46911833SMichael.Christensen@Sun.COM 	if (v12n_capabilities() != V12N_LDOMS_SUPPORTED) {
47011833SMichael.Christensen@Sun.COM 		errno = ENOTSUP;
47111833SMichael.Christensen@Sun.COM 	} else if ((mdp = v12n_md_init()) == NULL) {
47211833SMichael.Christensen@Sun.COM 		errno = EACCES;
47311833SMichael.Christensen@Sun.COM 	} else if (!v12n_get_md_domain_name(mdp, &ldmname)) {
47411833SMichael.Christensen@Sun.COM 		errno = ESRCH;
47511833SMichael.Christensen@Sun.COM 	} else {
47611833SMichael.Christensen@Sun.COM 		rv = v12n_string_copyout(buf, ldmname, count);
47711833SMichael.Christensen@Sun.COM 	}
47811833SMichael.Christensen@Sun.COM 
47911833SMichael.Christensen@Sun.COM 	v12n_md_fini(mdp);
48011833SMichael.Christensen@Sun.COM 	return (rv);
48111833SMichael.Christensen@Sun.COM }
48211833SMichael.Christensen@Sun.COM 
48311833SMichael.Christensen@Sun.COM /*
48411833SMichael.Christensen@Sun.COM  * Get UUID string from MD, returns 1 on success.
48511833SMichael.Christensen@Sun.COM  * The UUID is a string property 'uuid' under the 'platform' node of the MD.
48611833SMichael.Christensen@Sun.COM  */
48711833SMichael.Christensen@Sun.COM static int
v12n_get_md_uuid_str(md_t * mdp,char ** uuid_strp)48811833SMichael.Christensen@Sun.COM v12n_get_md_uuid_str(md_t *mdp, char **uuid_strp)
48911833SMichael.Christensen@Sun.COM {
49011833SMichael.Christensen@Sun.COM 	mde_cookie_t *plat_nodes, rootnode;
49111833SMichael.Christensen@Sun.COM 	int list_size, npnodes, num_nodes, rv;
49211833SMichael.Christensen@Sun.COM 
49311833SMichael.Christensen@Sun.COM 	num_nodes = md_node_count(mdp);
49411833SMichael.Christensen@Sun.COM 	list_size = num_nodes * sizeof (mde_cookie_t);
49511833SMichael.Christensen@Sun.COM 	plat_nodes = malloc(list_size);
49611833SMichael.Christensen@Sun.COM 	if (plat_nodes == NULL) {
49711833SMichael.Christensen@Sun.COM 		return (0);
49811833SMichael.Christensen@Sun.COM 	}
49911833SMichael.Christensen@Sun.COM 
50011833SMichael.Christensen@Sun.COM 	rootnode = md_root_node(mdp);
50111833SMichael.Christensen@Sun.COM 
50211833SMichael.Christensen@Sun.COM 	npnodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "platform"),
50311833SMichael.Christensen@Sun.COM 	    md_find_name(mdp, "fwd"), plat_nodes);
50411833SMichael.Christensen@Sun.COM 
50511833SMichael.Christensen@Sun.COM 	if (npnodes >= 1)
50611833SMichael.Christensen@Sun.COM 		rv = !md_get_prop_str(mdp, plat_nodes[0], "uuid", uuid_strp);
50711833SMichael.Christensen@Sun.COM 	else
50811833SMichael.Christensen@Sun.COM 		rv = 0;
50911833SMichael.Christensen@Sun.COM 
51011833SMichael.Christensen@Sun.COM 	free(plat_nodes);
51111833SMichael.Christensen@Sun.COM 	return (rv);
51211833SMichael.Christensen@Sun.COM }
51311833SMichael.Christensen@Sun.COM 
51411833SMichael.Christensen@Sun.COM /*
51511833SMichael.Christensen@Sun.COM  * Get the domain UUID.
51611833SMichael.Christensen@Sun.COM  */
51711833SMichael.Christensen@Sun.COM int
v12n_domain_uuid(uuid_t uuid)51811833SMichael.Christensen@Sun.COM v12n_domain_uuid(uuid_t uuid)
51911833SMichael.Christensen@Sun.COM {
52011833SMichael.Christensen@Sun.COM 	md_t *mdp = NULL;
52111833SMichael.Christensen@Sun.COM 	char *uuid_str;
52211833SMichael.Christensen@Sun.COM 	int rv = -1;
52311833SMichael.Christensen@Sun.COM 
52411833SMichael.Christensen@Sun.COM 	if (v12n_capabilities() != V12N_LDOMS_SUPPORTED) {
52511833SMichael.Christensen@Sun.COM 		errno = ENOTSUP;
52611833SMichael.Christensen@Sun.COM 	} else if ((mdp = v12n_md_init()) == NULL) {
52711833SMichael.Christensen@Sun.COM 		errno = EACCES;
52811833SMichael.Christensen@Sun.COM 	} else if (!v12n_get_md_uuid_str(mdp, &uuid_str)) {
52911833SMichael.Christensen@Sun.COM 		errno = ESRCH;
53011833SMichael.Christensen@Sun.COM 	} else {
53111833SMichael.Christensen@Sun.COM 		rv = uuid_parse(uuid_str, uuid);
53211833SMichael.Christensen@Sun.COM 	}
53311833SMichael.Christensen@Sun.COM 
53411833SMichael.Christensen@Sun.COM 	v12n_md_fini(mdp);
53511833SMichael.Christensen@Sun.COM 
53611833SMichael.Christensen@Sun.COM 	return (rv);
53711833SMichael.Christensen@Sun.COM }
53811833SMichael.Christensen@Sun.COM 
53911833SMichael.Christensen@Sun.COM /*
54011833SMichael.Christensen@Sun.COM  * Send 'agent-sytem' request message.
54111833SMichael.Christensen@Sun.COM  */
54211833SMichael.Christensen@Sun.COM static int
v12n_ldma_send_request()54311833SMichael.Christensen@Sun.COM v12n_ldma_send_request()
54411833SMichael.Christensen@Sun.COM {
54511833SMichael.Christensen@Sun.COM 	ldma_message_header_t ldmamsg;
54611833SMichael.Christensen@Sun.COM 
54711833SMichael.Christensen@Sun.COM 	if (v12n_ds_send_msg == NULL || v12n_ldma_ctrl_hdl == DS_INVALID_HDL)
54811833SMichael.Christensen@Sun.COM 		return (ENOENT);
54911833SMichael.Christensen@Sun.COM 
55011833SMichael.Christensen@Sun.COM 	ldmamsg.msg_num = 0;
55111833SMichael.Christensen@Sun.COM 	ldmamsg.msg_type = v12n_ldma_msgtype;
55211833SMichael.Christensen@Sun.COM 	ldmamsg.msg_info = 0;
55311833SMichael.Christensen@Sun.COM 	return (v12n_ds_send_msg(v12n_ldma_ctrl_hdl, (char *)&ldmamsg,
55411833SMichael.Christensen@Sun.COM 	    sizeof (ldmamsg)));
55511833SMichael.Christensen@Sun.COM }
55611833SMichael.Christensen@Sun.COM 
55711833SMichael.Christensen@Sun.COM /*
55811833SMichael.Christensen@Sun.COM  * 'agent-system' registration handler.
55911833SMichael.Christensen@Sun.COM  * If we get a registration from the control domain (domain 0), then send
56011833SMichael.Christensen@Sun.COM  * the requested message.  Otherwise, ignore the registration.
56111833SMichael.Christensen@Sun.COM  */
56211833SMichael.Christensen@Sun.COM /* ARGSUSED */
56311833SMichael.Christensen@Sun.COM static void
v12n_ldma_register_handler(ds_hdl_t hdl,ds_cb_arg_t arg,ds_ver_t * ver,ds_domain_hdl_t dhdl)56411833SMichael.Christensen@Sun.COM v12n_ldma_register_handler(ds_hdl_t hdl, ds_cb_arg_t arg, ds_ver_t *ver,
56511833SMichael.Christensen@Sun.COM     ds_domain_hdl_t dhdl)
56611833SMichael.Christensen@Sun.COM {
56711833SMichael.Christensen@Sun.COM 
56811833SMichael.Christensen@Sun.COM 	/* got registration from control domain */
56911833SMichael.Christensen@Sun.COM 	if (dhdl == 0) {
57011833SMichael.Christensen@Sun.COM 		(void) mutex_lock(&v12n_ldma_cv_lock);
57111833SMichael.Christensen@Sun.COM 		if (v12n_ldma_cv_state == V12N_LDMA_REGWAITING) {
57211833SMichael.Christensen@Sun.COM 			v12n_ldma_ctrl_hdl = hdl;
57311833SMichael.Christensen@Sun.COM 			v12n_ldma_cv_state = V12N_LDMA_REGRECEIVED;
57411833SMichael.Christensen@Sun.COM 			(void) cond_signal(&v12n_ldma_cv);
57511833SMichael.Christensen@Sun.COM 		}
57611833SMichael.Christensen@Sun.COM 		(void) mutex_unlock(&v12n_ldma_cv_lock);
57711833SMichael.Christensen@Sun.COM 	}
57811833SMichael.Christensen@Sun.COM }
57911833SMichael.Christensen@Sun.COM 
58011833SMichael.Christensen@Sun.COM /*
58111833SMichael.Christensen@Sun.COM  * 'agent-system' data handler.
58211833SMichael.Christensen@Sun.COM  */
58311833SMichael.Christensen@Sun.COM /* ARGSUSED */
58411833SMichael.Christensen@Sun.COM static void
v12n_ldma_data_handler(ds_hdl_t hdl,ds_cb_arg_t arg,void * buf,size_t buflen)58511833SMichael.Christensen@Sun.COM v12n_ldma_data_handler(ds_hdl_t hdl, ds_cb_arg_t arg, void *buf,
58611833SMichael.Christensen@Sun.COM     size_t buflen)
58711833SMichael.Christensen@Sun.COM {
58811833SMichael.Christensen@Sun.COM 	char *data;
58911833SMichael.Christensen@Sun.COM 	ldma_message_header_t *ldmp;
59011833SMichael.Christensen@Sun.COM 	int n;
59111833SMichael.Christensen@Sun.COM 	int cv_state = V12N_LDMA_MSGERROR;
59211833SMichael.Christensen@Sun.COM 
59311833SMichael.Christensen@Sun.COM 	/*
59411833SMichael.Christensen@Sun.COM 	 * Ignore any message not from the control domain.
59511833SMichael.Christensen@Sun.COM 	 */
59611833SMichael.Christensen@Sun.COM 	if (v12n_ldma_ctrl_hdl != hdl)
59711833SMichael.Christensen@Sun.COM 		return;
59811833SMichael.Christensen@Sun.COM 
59911833SMichael.Christensen@Sun.COM 	/*
60011833SMichael.Christensen@Sun.COM 	 * Ignore any unexpected message.
60111833SMichael.Christensen@Sun.COM 	 */
60211833SMichael.Christensen@Sun.COM 	if (buflen < LDMA_MESSAGE_HEADER_SIZE)
60311833SMichael.Christensen@Sun.COM 		return;
60411833SMichael.Christensen@Sun.COM 
60511833SMichael.Christensen@Sun.COM 	/*
60611833SMichael.Christensen@Sun.COM 	 * Ignore message with unexpected msgnum.
60711833SMichael.Christensen@Sun.COM 	 */
60811833SMichael.Christensen@Sun.COM 	ldmp = (ldma_message_header_t *)buf;
60911833SMichael.Christensen@Sun.COM 	if (ldmp->msg_num != 0)
61011833SMichael.Christensen@Sun.COM 		return;
61111833SMichael.Christensen@Sun.COM 
61211833SMichael.Christensen@Sun.COM 	switch (ldmp->msg_type) {
61311833SMichael.Christensen@Sun.COM 
61411833SMichael.Christensen@Sun.COM 	case LDMA_MSG_RESULT:
61511833SMichael.Christensen@Sun.COM 		if (ldmp->msg_info == 0 ||
61611833SMichael.Christensen@Sun.COM 		    ldmp->msg_info > LDMA_MESSAGE_DLEN(buflen)) {
61711833SMichael.Christensen@Sun.COM 			cv_state = V12N_LDMA_MSGERROR;
61811833SMichael.Christensen@Sun.COM 			break;
61911833SMichael.Christensen@Sun.COM 		}
62011833SMichael.Christensen@Sun.COM 		data = LDMA_HDR2DATA(buf);
62111833SMichael.Christensen@Sun.COM 
62211833SMichael.Christensen@Sun.COM 		/* ensure that data ends with a '\0' */
62311833SMichael.Christensen@Sun.COM 		data[ldmp->msg_info - 1] = '\0';
62411833SMichael.Christensen@Sun.COM 		switch (v12n_ldma_msgtype) {
62511833SMichael.Christensen@Sun.COM 
62611833SMichael.Christensen@Sun.COM 		case LDMA_MSGSYS_GET_SYSINFO:
62711833SMichael.Christensen@Sun.COM 			/*
62811833SMichael.Christensen@Sun.COM 			 * Control domain nodename is second string in the
62911833SMichael.Christensen@Sun.COM 			 * message.  Make sure there is enough data in the msg
63011833SMichael.Christensen@Sun.COM 			 * to have a second string.
63111833SMichael.Christensen@Sun.COM 			 */
63211833SMichael.Christensen@Sun.COM 			n = strlen(data);
63311833SMichael.Christensen@Sun.COM 			if (LDMA_MESSAGE_DLEN(buflen) <= n + 3) {
63411833SMichael.Christensen@Sun.COM 				cv_state = V12N_LDMA_MSGERROR;
63511833SMichael.Christensen@Sun.COM 				break;
63611833SMichael.Christensen@Sun.COM 			}
63711833SMichael.Christensen@Sun.COM 			data += n + 1;
63811833SMichael.Christensen@Sun.COM 			if ((v12n_ldma_msgstr = strdup(data)) == NULL)
63911833SMichael.Christensen@Sun.COM 				cv_state = V12N_LDMA_MSGERROR;
64011833SMichael.Christensen@Sun.COM 			else
64111833SMichael.Christensen@Sun.COM 				cv_state = V12N_LDMA_MSGRECEIVED;
64211833SMichael.Christensen@Sun.COM 			break;
64311833SMichael.Christensen@Sun.COM 
64411833SMichael.Christensen@Sun.COM 		case LDMA_MSGSYS_GET_CHASSISNO:
64511833SMichael.Christensen@Sun.COM 			if ((v12n_ldma_msgstr = strdup(data)) == NULL)
64611833SMichael.Christensen@Sun.COM 				cv_state = V12N_LDMA_MSGERROR;
64711833SMichael.Christensen@Sun.COM 			else
64811833SMichael.Christensen@Sun.COM 				cv_state = V12N_LDMA_MSGRECEIVED;
64911833SMichael.Christensen@Sun.COM 			break;
65011833SMichael.Christensen@Sun.COM 
65111833SMichael.Christensen@Sun.COM 		default:
65211833SMichael.Christensen@Sun.COM 			/* v12n_ldma_msgtype must be valid */
65311833SMichael.Christensen@Sun.COM 			ASSERT(0);
65411833SMichael.Christensen@Sun.COM 		}
65511833SMichael.Christensen@Sun.COM 		break;
65611833SMichael.Christensen@Sun.COM 
65711833SMichael.Christensen@Sun.COM 	case LDMA_MSG_ERROR:
65811833SMichael.Christensen@Sun.COM 		cv_state = V12N_LDMA_MSGERROR;
65911833SMichael.Christensen@Sun.COM 		break;
66011833SMichael.Christensen@Sun.COM 
66111833SMichael.Christensen@Sun.COM 	default:
66211833SMichael.Christensen@Sun.COM 		/* unexpected message, ignored */
66311833SMichael.Christensen@Sun.COM 		return;
66411833SMichael.Christensen@Sun.COM 	}
66511833SMichael.Christensen@Sun.COM 
66611833SMichael.Christensen@Sun.COM 	(void) mutex_lock(&v12n_ldma_cv_lock);
66711833SMichael.Christensen@Sun.COM 	v12n_ldma_cv_state = cv_state;
66811833SMichael.Christensen@Sun.COM 	(void) cond_signal(&v12n_ldma_cv);
66911833SMichael.Christensen@Sun.COM 	(void) mutex_unlock(&v12n_ldma_cv_lock);
67011833SMichael.Christensen@Sun.COM }
67111833SMichael.Christensen@Sun.COM 
67211833SMichael.Christensen@Sun.COM 
67311833SMichael.Christensen@Sun.COM /*
67411833SMichael.Christensen@Sun.COM  * libds doesn't exist on non-sun4v, dynamically load it and get the
67511833SMichael.Christensen@Sun.COM  * function pointers to the needed lib functions.
67611833SMichael.Christensen@Sun.COM  */
67711833SMichael.Christensen@Sun.COM static int
v12n_libds_init(void)67811833SMichael.Christensen@Sun.COM v12n_libds_init(void)
67911833SMichael.Christensen@Sun.COM {
68011833SMichael.Christensen@Sun.COM 	if (v12n_ds_dlhdl != NULL) {
68111833SMichael.Christensen@Sun.COM 		if (v12n_ds_clnt_reg == NULL || v12n_ds_send_msg == NULL ||
68211833SMichael.Christensen@Sun.COM 		    v12n_ds_unreg_svc == NULL)
68311833SMichael.Christensen@Sun.COM 			return (ENOENT);
68411833SMichael.Christensen@Sun.COM 		return (0);
68511833SMichael.Christensen@Sun.COM 	}
68611833SMichael.Christensen@Sun.COM 
68711833SMichael.Christensen@Sun.COM 	if ((v12n_ds_dlhdl = dlopen("libds.so.1",
68811833SMichael.Christensen@Sun.COM 	    RTLD_NOW | RTLD_GLOBAL)) == NULL)
68911833SMichael.Christensen@Sun.COM 		return (ENOENT);
69011833SMichael.Christensen@Sun.COM 
69111833SMichael.Christensen@Sun.COM 	if ((v12n_ds_clnt_reg = (int (*)(ds_capability_t *, ds_ops_t *))
69211833SMichael.Christensen@Sun.COM 	    dlsym(v12n_ds_dlhdl, "ds_clnt_reg")) == NULL)
69311833SMichael.Christensen@Sun.COM 		return (ENOENT);
69411833SMichael.Christensen@Sun.COM 
69511833SMichael.Christensen@Sun.COM 	if ((v12n_ds_send_msg = (int (*)(ds_hdl_t, void *, size_t))
69611833SMichael.Christensen@Sun.COM 	    dlsym(v12n_ds_dlhdl, "ds_send_msg")) == NULL)
69711833SMichael.Christensen@Sun.COM 		return (ENOENT);
69811833SMichael.Christensen@Sun.COM 
69911833SMichael.Christensen@Sun.COM 	if ((v12n_ds_unreg_svc = (int (*)(char *, boolean_t))
70011833SMichael.Christensen@Sun.COM 	    dlsym(v12n_ds_dlhdl, "ds_unreg_svc")) == NULL)
70111833SMichael.Christensen@Sun.COM 		return (ENOENT);
70211833SMichael.Christensen@Sun.COM 
70311833SMichael.Christensen@Sun.COM 	return (0);
70411833SMichael.Christensen@Sun.COM }
70511833SMichael.Christensen@Sun.COM 
70611833SMichael.Christensen@Sun.COM /*
70711833SMichael.Christensen@Sun.COM  * Initiate and wait for an ldmad 'agent-system' domain service.
70811833SMichael.Christensen@Sun.COM  * Dynamically load libds, register the client 'agent-system' service
70911833SMichael.Christensen@Sun.COM  * and wait for a specified amount of time for the 'agent-system'
71011833SMichael.Christensen@Sun.COM  * service on the control domain to respond to the request.
71111833SMichael.Christensen@Sun.COM  */
71211833SMichael.Christensen@Sun.COM static int
v12n_get_ldma_system_msg(int msgtype,char ** strp)71311833SMichael.Christensen@Sun.COM v12n_get_ldma_system_msg(int msgtype, char **strp)
71411833SMichael.Christensen@Sun.COM {
71511833SMichael.Christensen@Sun.COM 	int tout;
71611833SMichael.Christensen@Sun.COM 	int err = 0;
71711833SMichael.Christensen@Sun.COM 	timestruc_t timeout;
71811833SMichael.Christensen@Sun.COM 
71911833SMichael.Christensen@Sun.COM 	/*
72011833SMichael.Christensen@Sun.COM 	 * Ensure that there's only one thread trying to do a
72111833SMichael.Christensen@Sun.COM 	 * 'agent-system' client registration/message at a time.
72211833SMichael.Christensen@Sun.COM 	 */
72311833SMichael.Christensen@Sun.COM 	(void) mutex_lock(&v12n_ldma_lock);
724*12913SMichael.Christensen@Sun.COM 	if ((err = v12n_libds_init()) != 0) {
725*12913SMichael.Christensen@Sun.COM 		(void) mutex_unlock(&v12n_ldma_lock);
726*12913SMichael.Christensen@Sun.COM 		return (err);
727*12913SMichael.Christensen@Sun.COM 	}
72811833SMichael.Christensen@Sun.COM 
72911833SMichael.Christensen@Sun.COM 	v12n_ldma_msgtype = msgtype;
73011833SMichael.Christensen@Sun.COM 	v12n_ldma_msgstr = NULL;
73111833SMichael.Christensen@Sun.COM 
73211833SMichael.Christensen@Sun.COM 	/* initialize v12n_ldma_cv_state variable before registering service */
73311833SMichael.Christensen@Sun.COM 	(void) mutex_lock(&v12n_ldma_cv_lock);
73411833SMichael.Christensen@Sun.COM 	v12n_ldma_cv_state = V12N_LDMA_REGWAITING;
73511833SMichael.Christensen@Sun.COM 	(void) mutex_unlock(&v12n_ldma_cv_lock);
73611833SMichael.Christensen@Sun.COM 
73711833SMichael.Christensen@Sun.COM 	/*
73811833SMichael.Christensen@Sun.COM 	 * Other instances may be trying to load the "agent-system" service.
73911833SMichael.Christensen@Sun.COM 	 * If a collision happens (EBUSY error), wait and try again.
74011833SMichael.Christensen@Sun.COM 	 */
74111833SMichael.Christensen@Sun.COM 	for (tout = 0; tout < v12n_ldma_timeout; tout += v12n_ldma_sleeptime) {
74211833SMichael.Christensen@Sun.COM 		if ((err = v12n_ds_clnt_reg(&v12n_ldma_cap,
74311833SMichael.Christensen@Sun.COM 		    &v12n_ldma_ops)) == 0)
74411833SMichael.Christensen@Sun.COM 			break;
74511833SMichael.Christensen@Sun.COM 		if (err != EALREADY) {
74611833SMichael.Christensen@Sun.COM 			goto done;
74711833SMichael.Christensen@Sun.COM 		}
74811833SMichael.Christensen@Sun.COM 		(void) sleep(v12n_ldma_sleeptime);
74911833SMichael.Christensen@Sun.COM 	}
75011833SMichael.Christensen@Sun.COM 
75111833SMichael.Christensen@Sun.COM 	if (tout >= v12n_ldma_timeout) {
75211833SMichael.Christensen@Sun.COM 		err = EBUSY;
75311833SMichael.Christensen@Sun.COM 		goto done;
75411833SMichael.Christensen@Sun.COM 	}
75511833SMichael.Christensen@Sun.COM 
75611833SMichael.Christensen@Sun.COM 	/*
75711833SMichael.Christensen@Sun.COM 	 * Wait for control domain registration.
75811833SMichael.Christensen@Sun.COM 	 */
75911833SMichael.Christensen@Sun.COM 	timeout.tv_sec = v12n_ldma_timeout;
76011833SMichael.Christensen@Sun.COM 	timeout.tv_nsec = 0;
76111833SMichael.Christensen@Sun.COM 
76211833SMichael.Christensen@Sun.COM 	(void) mutex_lock(&v12n_ldma_cv_lock);
76311833SMichael.Christensen@Sun.COM 	while (v12n_ldma_cv_state == V12N_LDMA_REGWAITING) {
76411833SMichael.Christensen@Sun.COM 		if ((err = cond_reltimedwait(&v12n_ldma_cv,
76511833SMichael.Christensen@Sun.COM 		    &v12n_ldma_cv_lock, &timeout)) != EINTR)
76611833SMichael.Christensen@Sun.COM 			break;
76711833SMichael.Christensen@Sun.COM 	}
76811833SMichael.Christensen@Sun.COM 
76911833SMichael.Christensen@Sun.COM 	/*
77011833SMichael.Christensen@Sun.COM 	 * Check for timeout or an error.
77111833SMichael.Christensen@Sun.COM 	 */
77211833SMichael.Christensen@Sun.COM 	if (v12n_ldma_cv_state != V12N_LDMA_REGRECEIVED) {
77311833SMichael.Christensen@Sun.COM 		if (err == 0)
77411833SMichael.Christensen@Sun.COM 			err = EPROTO;
77511833SMichael.Christensen@Sun.COM 		(void) mutex_unlock(&v12n_ldma_cv_lock);
77611833SMichael.Christensen@Sun.COM 		goto done;
77711833SMichael.Christensen@Sun.COM 	}
77811833SMichael.Christensen@Sun.COM 
77911833SMichael.Christensen@Sun.COM 	/*
78011833SMichael.Christensen@Sun.COM 	 * Received a registration request, send the request message.
78111833SMichael.Christensen@Sun.COM 	 */
78211833SMichael.Christensen@Sun.COM 	v12n_ldma_cv_state = V12N_LDMA_MSGWAITING;
78311833SMichael.Christensen@Sun.COM 	if ((err = v12n_ldma_send_request()) != 0) {
78411833SMichael.Christensen@Sun.COM 		(void) mutex_unlock(&v12n_ldma_cv_lock);
78511833SMichael.Christensen@Sun.COM 		goto done;
78611833SMichael.Christensen@Sun.COM 	}
78711833SMichael.Christensen@Sun.COM 
78811833SMichael.Christensen@Sun.COM 	while (v12n_ldma_cv_state == V12N_LDMA_MSGWAITING) {
78911833SMichael.Christensen@Sun.COM 		if ((err = cond_reltimedwait(&v12n_ldma_cv,
79011833SMichael.Christensen@Sun.COM 		    &v12n_ldma_cv_lock, &timeout)) != EINTR)
79111833SMichael.Christensen@Sun.COM 			break;
79211833SMichael.Christensen@Sun.COM 	}
79311833SMichael.Christensen@Sun.COM 
79411833SMichael.Christensen@Sun.COM 	if (v12n_ldma_cv_state != V12N_LDMA_MSGRECEIVED) {
79511833SMichael.Christensen@Sun.COM 		if (err == 0)
79611833SMichael.Christensen@Sun.COM 			err = EPROTO;
79711833SMichael.Christensen@Sun.COM 		(void) mutex_unlock(&v12n_ldma_cv_lock);
79811833SMichael.Christensen@Sun.COM 		goto done;
79911833SMichael.Christensen@Sun.COM 	}
80011833SMichael.Christensen@Sun.COM 
80111833SMichael.Christensen@Sun.COM 	v12n_ldma_cv_state = V12N_LDMA_CVINVALID;
80211833SMichael.Christensen@Sun.COM 	(void) mutex_unlock(&v12n_ldma_cv_lock);
80311833SMichael.Christensen@Sun.COM 
80411833SMichael.Christensen@Sun.COM 	/*
80511833SMichael.Christensen@Sun.COM 	 * If v12n_ldma_msgstr is set, a valid data response was seen.
80611833SMichael.Christensen@Sun.COM 	 */
80711833SMichael.Christensen@Sun.COM 	if (v12n_ldma_msgstr == NULL)
80811833SMichael.Christensen@Sun.COM 		err = ENODATA;
80911833SMichael.Christensen@Sun.COM 	else {
81011833SMichael.Christensen@Sun.COM 		if (*v12n_ldma_msgstr == '\0' ||
81111833SMichael.Christensen@Sun.COM 		    (*strp = strdup(v12n_ldma_msgstr)) == NULL)
81211833SMichael.Christensen@Sun.COM 			err = ENODATA;
81311833SMichael.Christensen@Sun.COM 		free(v12n_ldma_msgstr);
81411833SMichael.Christensen@Sun.COM 		v12n_ldma_msgstr = NULL;
81511833SMichael.Christensen@Sun.COM 	}
81611833SMichael.Christensen@Sun.COM 
81711833SMichael.Christensen@Sun.COM done:
81811833SMichael.Christensen@Sun.COM 	v12n_ds_unreg_svc(LDMA_NAME_SYSTEM, B_TRUE);
81911833SMichael.Christensen@Sun.COM 	v12n_ldma_msgtype = -1;
82011833SMichael.Christensen@Sun.COM 	v12n_ldma_ctrl_hdl = DS_INVALID_HDL;
82111833SMichael.Christensen@Sun.COM 	(void) mutex_unlock(&v12n_ldma_lock);
82211833SMichael.Christensen@Sun.COM 
82311833SMichael.Christensen@Sun.COM 	return (err);
82411833SMichael.Christensen@Sun.COM }
82511833SMichael.Christensen@Sun.COM 
82611833SMichael.Christensen@Sun.COM /*
82711833SMichael.Christensen@Sun.COM  * Get the nodename of the control domain.  Returns the equivalent
82811833SMichael.Christensen@Sun.COM  * of 'uname -n' on the control domain.
82911833SMichael.Christensen@Sun.COM  *   This is obtained via the 'agent-system' domain service provided
83011833SMichael.Christensen@Sun.COM  *   by ldmad.
83111833SMichael.Christensen@Sun.COM  */
83211833SMichael.Christensen@Sun.COM size_t
v12n_ctrl_domain(char * buf,size_t count)83311833SMichael.Christensen@Sun.COM v12n_ctrl_domain(char *buf, size_t count)
83411833SMichael.Christensen@Sun.COM {
83511833SMichael.Christensen@Sun.COM 	char *str;
83611833SMichael.Christensen@Sun.COM 	int err;
83711833SMichael.Christensen@Sun.COM 	size_t rv = (size_t)(-1);
83811833SMichael.Christensen@Sun.COM 
83911833SMichael.Christensen@Sun.COM 	if (v12n_capabilities() != V12N_LDOMS_SUPPORTED) {
84011833SMichael.Christensen@Sun.COM 		errno = ENOTSUP;
84111833SMichael.Christensen@Sun.COM 	} else if ((err = v12n_get_ldma_system_msg(LDMA_MSGSYS_GET_SYSINFO,
84211833SMichael.Christensen@Sun.COM 	    &str)) != 0) {
84311833SMichael.Christensen@Sun.COM 		errno = err;
84411833SMichael.Christensen@Sun.COM 	} else {
84511833SMichael.Christensen@Sun.COM 		rv = v12n_string_copyout(buf, str, count);
84611833SMichael.Christensen@Sun.COM 	}
84711833SMichael.Christensen@Sun.COM 	return (rv);
84811833SMichael.Christensen@Sun.COM }
84911833SMichael.Christensen@Sun.COM 
85011833SMichael.Christensen@Sun.COM /*
85111833SMichael.Christensen@Sun.COM  * Get the Chassis serial number from the Control Domain.
85211833SMichael.Christensen@Sun.COM  *   This is obtained via the 'agent-system' domain service provided
85311833SMichael.Christensen@Sun.COM  *   by ldmad.
85411833SMichael.Christensen@Sun.COM  */
85511833SMichael.Christensen@Sun.COM size_t
v12n_chassis_serialno(char * buf,size_t count)85611833SMichael.Christensen@Sun.COM v12n_chassis_serialno(char *buf, size_t count)
85711833SMichael.Christensen@Sun.COM {
85811833SMichael.Christensen@Sun.COM 	char *str;
85911833SMichael.Christensen@Sun.COM 	int err;
86011833SMichael.Christensen@Sun.COM 	size_t rv = (size_t)(-1);
86111833SMichael.Christensen@Sun.COM 
86211833SMichael.Christensen@Sun.COM 	if (v12n_capabilities() != V12N_LDOMS_SUPPORTED) {
86311833SMichael.Christensen@Sun.COM 		errno = ENOTSUP;
86411833SMichael.Christensen@Sun.COM 	} else if ((err = v12n_get_ldma_system_msg(LDMA_MSGSYS_GET_CHASSISNO,
86511833SMichael.Christensen@Sun.COM 	    &str)) != 0) {
86611833SMichael.Christensen@Sun.COM 		errno = err;
86711833SMichael.Christensen@Sun.COM 	} else {
86811833SMichael.Christensen@Sun.COM 		rv = v12n_string_copyout(buf, str, count);
86911833SMichael.Christensen@Sun.COM 	}
87011833SMichael.Christensen@Sun.COM 	return (rv);
87111833SMichael.Christensen@Sun.COM }
872