ldma_system.c revision 11833:3b3fe296598b
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*
28 * Logical Domains System Agent
29 */
30
31#include <errno.h>
32#include <fcntl.h>
33#include <libds.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <strings.h>
37#include <synch.h>
38#include <thread.h>
39#include <unistd.h>
40#include <sys/utsname.h>
41#include <sys/mdesc.h>
42#include <sys/mdesc_impl.h>
43
44#include "ldma.h"
45#include "pri.h"
46
47#define	LDMA_MODULE	LDMA_NAME_SYSTEM
48
49#define	LDMA_NVERSIONS	(sizeof (ldma_versions) / sizeof (ds_ver_t))
50#define	LDMA_NHANDLERS	(sizeof (ldma_handlers) / sizeof (ldma_msg_handler_t))
51
52static ldm_msg_func_t ldma_sys_get_sysinfo;
53static ldm_msg_func_t ldma_sys_get_chassisno;
54
55/* ptr to cached value of chassisno */
56static char *ldma_sys_chassisno = NULL;
57mutex_t ldma_chassisno_lock = DEFAULTMUTEX;
58
59static ds_ver_t ldma_versions[] = { { 1, 0 } };
60
61static ldma_msg_handler_t ldma_handlers[] = {
62	{ LDMA_MSGSYS_GET_SYSINFO,   LDMA_MSGFLG_ACCESS_ANY,
63	    ldma_sys_get_sysinfo },
64	{ LDMA_MSGSYS_GET_CHASSISNO, LDMA_MSGFLG_ACCESS_ANY,
65	    ldma_sys_get_chassisno }
66};
67
68ldma_agent_info_t ldma_system_info = {
69	LDMA_NAME_SYSTEM,
70	ldma_versions, LDMA_NVERSIONS,
71	ldma_handlers, LDMA_NHANDLERS
72};
73
74/*ARGSUSED*/
75static ldma_request_status_t
76ldma_sys_get_sysinfo(ds_ver_t *ver, ldma_message_header_t *request,
77    size_t request_dlen, ldma_message_header_t **replyp, size_t *reply_dlenp)
78{
79	ldma_message_header_t *reply;
80	struct utsname name;
81	size_t syslen, nodlen, rellen, maclen, verlen;
82	size_t rlen;
83	char *data;
84	int status;
85
86	LDMA_DBG("GET_SYSINFO");
87
88	if (request->msg_info != 0 || request_dlen != 0) {
89		status = LDMA_REQ_INVALID;
90		goto done;
91	}
92
93	if (uname(&name) == -1) {
94		LDMA_DBG("GET_SYSINFO: uname failed with error %d", errno);
95		status = LDMA_REQ_FAILED;
96		goto done;
97	}
98
99	syslen = strlen(name.sysname) + 1;
100	nodlen = strlen(name.nodename) + 1;
101	rellen = strlen(name.release) + 1;
102	verlen = strlen(name.version) + 1;
103	maclen = strlen(name.machine) + 1;
104
105	rlen = syslen + nodlen + rellen + verlen + maclen;
106
107	reply = ldma_alloc_result_msg(request, rlen);
108
109	if (reply == NULL) {
110		status = LDMA_REQ_FAILED;
111		goto done;
112	}
113
114	reply->msg_info = rlen;
115
116	data = LDMA_HDR2DATA(reply);
117
118	(void) strcpy(data, name.sysname);
119	data += syslen;
120
121	(void) strcpy(data, name.nodename);
122	data += nodlen;
123
124	(void) strcpy(data, name.release);
125	data += rellen;
126
127	(void) strcpy(data, name.version);
128	data += verlen;
129
130	(void) strcpy(data, name.machine);
131
132	LDMA_DBG("GET_SYSINFO: return info=%u, {%s, %s, %s, %s, %s}", rlen,
133	    name.sysname, name.nodename, name.release, name.version,
134	    name.machine);
135
136	*replyp = reply;
137	*reply_dlenp = rlen;
138
139	return (LDMA_REQ_COMPLETED);
140
141done:
142	LDMA_DBG("GET_SYSINFO: return error %d", status);
143	return (status);
144}
145
146/*
147 * Wrapper for MD free: need unused size argument.
148 */
149/* ARGSUSED */
150static void
151ldma_md_free(void *buf, size_t n)
152{
153	free(buf);
154}
155
156/*
157 * Wrapper for MD init: read PRI MD and invoke md_init_intern.
158 */
159static md_t *
160ldma_md_init()
161{
162	md_t *mdp;
163	uint64_t *buf = NULL;
164	uint64_t token;
165	ssize_t status;
166
167	if (pri_init() == -1)
168		return (NULL);
169
170	status = pri_get(PRI_GET, &token, &buf, malloc, ldma_md_free);
171	pri_fini();
172
173	if (status == (ssize_t)(-1))
174		return (NULL);
175
176	mdp = md_init_intern(buf, malloc, ldma_md_free);
177
178	return (mdp);
179}
180
181/*
182 * Wrapper for md_fini.  Allow NULL md ptr and free MD buffer.
183 */
184static void
185ldma_md_fini(void *md)
186{
187	md_impl_t *mdp = (md_impl_t *)md;
188
189	if (mdp) {
190		free(mdp->caddr);
191		(void) md_fini(md);
192	}
193}
194
195static int
196ldma_get_chassis_serialno(char **strp)
197{
198	md_t *mdp;
199	mde_cookie_t *component_nodes, rootnode;
200	int list_size, ncomponents, num_nodes, i;
201	char *component_type, *serialno;
202	int rv = 0;
203
204	(void) mutex_lock(&ldma_chassisno_lock);
205	if (ldma_sys_chassisno != NULL) {
206		*strp = ldma_sys_chassisno;
207		(void) mutex_unlock(&ldma_chassisno_lock);
208		return (1);
209	}
210
211	mdp = ldma_md_init();
212	if (mdp == NULL) {
213		(void) mutex_unlock(&ldma_chassisno_lock);
214		return (0);
215	}
216
217	num_nodes = md_node_count(mdp);
218	list_size = num_nodes * sizeof (mde_cookie_t);
219	component_nodes = malloc(list_size);
220	if (component_nodes == NULL) {
221		(void) mutex_unlock(&ldma_chassisno_lock);
222		ldma_md_fini(mdp);
223		return (0);
224	}
225
226	rootnode = md_root_node(mdp);
227
228	ncomponents = md_scan_dag(mdp, rootnode, md_find_name(mdp, "component"),
229	    md_find_name(mdp, "fwd"), component_nodes);
230
231	for (i = 0; i < ncomponents; i++) {
232		if (md_get_prop_str(mdp, component_nodes[i], "type",
233		    &component_type))
234			continue;
235		if (strcmp(component_type, "chassis") != 0)
236			continue;
237		if (md_get_prop_str(mdp, component_nodes[i],
238		    "serial_number", &serialno) == 0) {
239			ldma_sys_chassisno = strdup(serialno);
240			*strp = ldma_sys_chassisno;
241			rv = 1;
242			break;
243		}
244	}
245	(void) mutex_unlock(&ldma_chassisno_lock);
246	free(component_nodes);
247	ldma_md_fini(mdp);
248	return (rv);
249}
250
251/*ARGSUSED*/
252static ldma_request_status_t
253ldma_sys_get_chassisno(ds_ver_t *ver, ldma_message_header_t *request,
254    size_t request_dlen, ldma_message_header_t **replyp, size_t *reply_dlenp)
255{
256	ldma_message_header_t *reply;
257	char *str;
258	size_t rlen;
259	char *data;
260	int status;
261
262	LDMA_DBG("GET_CHASSISNO");
263
264	if (request->msg_info != 0 || request_dlen != 0) {
265		status = LDMA_REQ_INVALID;
266		goto done;
267	}
268
269	if (ldma_get_chassis_serialno(&str) == 0) {
270		LDMA_DBG("GET_CHASSISNO: ldma_get_chassisno failed "
271		    "with error %d", errno);
272		status = LDMA_REQ_FAILED;
273		goto done;
274	}
275
276	rlen = strlen(str) + 1;
277
278	reply = ldma_alloc_result_msg(request, rlen);
279
280	if (reply == NULL) {
281		status = LDMA_REQ_FAILED;
282		goto done;
283	}
284
285	reply->msg_info = rlen;
286
287	data = LDMA_HDR2DATA(reply);
288
289	(void) strcpy(data, str);
290
291	LDMA_DBG("GET_CHASSISNO: return info=%u, {%s}", rlen, str);
292
293	*replyp = reply;
294	*reply_dlenp = rlen;
295
296	return (LDMA_REQ_COMPLETED);
297
298done:
299	LDMA_DBG("GET_CHASSISNO: return error %d", status);
300	return (status);
301}
302