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 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 #include <dlfcn.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <strings.h>
31 #include <synch.h>
32 #include <thread.h>
33 #include <unistd.h>
34 #include <utility.h>
35 #include <sys/mdesc.h>
36 #include <sys/mdesc_impl.h>
37 #include <sys/debug.h>
38 #include <sys/stat.h>
39 #include <sys/types.h>
40 #include <sys/utsname.h>
41
42 #include "ldma.h"
43 #include "libds.h"
44 #include "libv12n.h"
45
46 /*
47 * sun4 support for libv12n.
48 *
49 * Non-sun4v support is minimal. The v12n_capabilities() function will
50 * only return 0 (not supported, not enabled, no implementation).
51 *
52 * For sun4v the support for v12n_capabilities(), v12n_domain_roles(),
53 * v12n_domain_name() and v12n_domain_uuid() are supported by scanning the
54 * MD from /dev/mdesc for specific properties. For v12n_ctrl_domain() and
55 * v12n_chassis_serialno(), the ldoms agent daemon (ldmad) on the control
56 * domain supplies the required information via the "agent-system" domain
57 * service.
58 */
59
60 /* libds statics */
61 static void *v12n_ds_dlhdl = NULL;
62 static int (*v12n_ds_send_msg)(ds_hdl_t, void *, size_t) = NULL;
63 static int (*v12n_ds_clnt_reg)(ds_capability_t *, ds_ops_t *);
64 static int (*v12n_ds_unreg_svc)(char *, boolean_t);
65
66 /*
67 * Defines to support the 'agent-system' domain service.
68 */
69
70 #define LDMA_SYSTEM_NVERS \
71 (sizeof (v12n_ldma_system_vers) / sizeof (ds_ver_t))
72 static ds_ver_t v12n_ldma_system_vers[] = { { 1, 0} };
73
74 static ds_capability_t v12n_ldma_cap = {
75 LDMA_NAME_SYSTEM, /* svc_id */
76 v12n_ldma_system_vers, /* vers */
77 LDMA_SYSTEM_NVERS /* nvers */
78 };
79
80 static void v12n_ldma_register_handler(ds_hdl_t hdl, ds_cb_arg_t arg,
81 ds_ver_t *ver, ds_domain_hdl_t dhdl);
82 static void v12n_ldma_data_handler(ds_hdl_t hdl, ds_cb_arg_t arg, void *buf,
83 size_t buflen);
84
85 static ds_ops_t v12n_ldma_ops = {
86 v12n_ldma_register_handler, /* ds_reg_cb */
87 NULL, /* ds_unreg_cb */
88 v12n_ldma_data_handler, /* ds_data_cb */
89 NULL /* ds_cb_arg */
90 };
91
92 /* v12n_ldma_cv_state values */
93 #define V12N_LDMA_CVINVALID -1 /* invalid value for cv_state */
94 #define V12N_LDMA_REGWAITING 0 /* waiting for ctrl domain reg */
95 #define V12N_LDMA_REGRECEIVED 1 /* received ctrl domain reg */
96 #define V12N_LDMA_MSGWAITING 2 /* waiting for message response */
97 #define V12N_LDMA_MSGRECEIVED 3 /* received message response */
98 #define V12N_LDMA_MSGERROR 4 /* received a bad message */
99
100 /* 'agent-system' data used in async registration/data message handlers */
101 static ds_hdl_t v12n_ldma_ctrl_hdl = DS_INVALID_HDL;
102 static int v12n_ldma_msgtype;
103 static char *v12n_ldma_msgstr;
104 static mutex_t v12n_ldma_lock = DEFAULTMUTEX;
105 static cond_t v12n_ldma_cv = DEFAULTCV;
106 static int v12n_ldma_cv_state = V12N_LDMA_CVINVALID;
107 static mutex_t v12n_ldma_cv_lock = DEFAULTMUTEX;
108
109 /* 'agent-system' timeout values in seconds */
110 static int v12n_ldma_timeout = 15;
111 static int v12n_ldma_sleeptime = 1;
112
113
114 #define V12N_LDOMS_SUPPORTED (V12N_CAP_SUPPORTED | V12N_CAP_ENABLED | \
115 V12N_CAP_IMPL_LDOMS)
116
117 #define MD_DEVICE "/dev/mdesc"
118
119 /*
120 * libv12n routines to support /dev/mdesc.
121 */
122
123 /*
124 * Wrapper for MD free: need unused size argument.
125 */
126 /* ARGSUSED */
127 static void
v12n_md_free(void * buf,size_t n)128 v12n_md_free(void *buf, size_t n)
129 {
130 free(buf);
131 }
132
133 /*
134 * Wrapper for MD init: read MD and invoke md_init_intern.
135 */
136 static md_t *
v12n_md_init()137 v12n_md_init()
138 {
139 md_t *mdp;
140 char *buf = NULL;
141 md_header_t mdh;
142 int md_size;
143 int fd;
144
145 /*
146 * Open the Machine Description (MD)
147 */
148 fd = open(MD_DEVICE, O_RDONLY);
149 if (fd == -1) {
150 return (NULL);
151 }
152
153 if (read(fd, &mdh, sizeof (md_header_t)) != sizeof (md_header_t))
154 goto errdone;
155
156 md_size = sizeof (md_header_t) + mdh.node_blk_sz + mdh.name_blk_sz +
157 mdh.data_blk_sz;
158
159 if ((buf = malloc(md_size)) == NULL)
160 goto errdone;
161
162 (void) memcpy(buf, &mdh, sizeof (md_header_t));
163 if (read(fd, buf + sizeof (md_header_t),
164 md_size - sizeof (md_header_t)) != md_size - sizeof (md_header_t)) {
165 goto errdone;
166 }
167
168 mdp = md_init_intern((uint64_t *)((void *)buf), malloc, v12n_md_free);
169
170 (void) close(fd);
171
172 return (mdp);
173
174 errdone:
175 (void) close(fd);
176 free(buf);
177
178 return (NULL);
179 }
180
181 /*
182 * Wrapper for md_fini. Allow NULL md ptr and free MD buffer.
183 */
184 static void
v12n_md_fini(void * md)185 v12n_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
195 /*
196 * See if LDoms domaining is enabled, returns 1 if enabled.
197 * Get the value of the 'domaining-enabled' property under the
198 * 'platform' node. Value of 1 => domaining is enabled.
199 */
200 static int
v12n_domaining_enabled()201 v12n_domaining_enabled()
202 {
203 mde_cookie_t *nodes, rootnode;
204 int nnodes;
205 uint64_t prop_val = 0;
206 md_t *mdp;
207
208 if ((mdp = v12n_md_init()) == NULL) {
209 return (0);
210 }
211
212 nnodes = md_node_count(mdp);
213 nodes = malloc(nnodes * sizeof (mde_cookie_t));
214 if (nodes == NULL) {
215 v12n_md_fini(mdp);
216 return (0);
217 }
218
219 rootnode = md_root_node(mdp);
220
221 nnodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "platform"),
222 md_find_name(mdp, "fwd"), nodes);
223
224 if (nnodes >= 1) {
225 (void) md_get_prop_val(mdp, nodes[0], "domaining-enabled",
226 &prop_val);
227 }
228
229 v12n_md_fini(mdp);
230 free(nodes);
231 return (prop_val == 1);
232 }
233
234 int
v12n_capabilities()235 v12n_capabilities()
236 {
237 struct utsname uinfo;
238 struct stat st;
239 int cap;
240
241 /*
242 * Check if this is an LDoms system. When using LDoms each
243 * domain should have a /dev/mdesc device providing access to
244 * the Machine Description (MD) of the domain. If this device
245 * does not exist then this is not an LDoms system.
246 */
247 if (uname(&uinfo) == -1 || strcmp(uinfo.machine, "sun4v")) {
248 /*
249 * Not sun4v -> LDoms not supported
250 */
251 cap = 0;
252 } else if (stat(MD_DEVICE, &st) == 0) {
253 /*
254 * sun4v + /dev/mdesc exists -> Check if LDoms enabled
255 * via the 'domaining-enabled' property.
256 */
257 cap = (V12N_CAP_SUPPORTED | V12N_CAP_IMPL_LDOMS |
258 (v12n_domaining_enabled() ? V12N_CAP_ENABLED : 0));
259 } else if (errno == ENOENT) {
260 /*
261 * sun4v + /dev/mdesc does not exist -> LDoms supported
262 * but not enabled.
263 */
264 cap = (V12N_CAP_SUPPORTED | V12N_CAP_IMPL_LDOMS);
265 }
266
267 return (cap);
268 }
269
270 /*
271 * Routines to support v12n_domain_roles.
272 */
273 static int
v12n_scan_md_nodes(md_t * mdp,char * node_name,char * node_str_prop,char ** props)274 v12n_scan_md_nodes(md_t *mdp, char *node_name, char *node_str_prop,
275 char **props)
276 {
277 mde_cookie_t *nodes, rootnode;
278 int nnodes, i, j;
279 char *prop_str;
280
281 nnodes = md_node_count(mdp);
282 nodes = malloc(nnodes * sizeof (mde_cookie_t));
283 if (nodes == NULL) {
284 return (0);
285 }
286
287 rootnode = md_root_node(mdp);
288
289 nnodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, node_name),
290 md_find_name(mdp, "fwd"), nodes);
291
292 if (node_str_prop == NULL)
293 return (nnodes > 0);
294
295 for (i = 0; i < nnodes; i++) {
296 if (md_get_prop_str(mdp, nodes[i], node_str_prop, &prop_str))
297 continue;
298 for (j = 0; props[j] != NULL; j++) {
299 if (strcmp(prop_str, props[j]) == 0) {
300 free(nodes);
301 return (1);
302 }
303 }
304 }
305 free(nodes);
306 return (0);
307 }
308
309 /*
310 * Check if MD has a hypervisor access point, returns 1 if true.
311 * Check the MD for a 'virtual-device-port' node whose 'vldc-svc-name' is
312 * 'hvctl'.
313 */
314 static int
v12n_check_hv_access(md_t * mdp)315 v12n_check_hv_access(md_t *mdp)
316 {
317 static char *hvctl_str[] = {
318 "hvctl",
319 NULL
320 };
321
322 return (v12n_scan_md_nodes(mdp, "virtual-device-port", "vldc-svc-name",
323 hvctl_str));
324 }
325
326 /*
327 * Check if MD has a virtual device service (vcc, vsw, vds), returns 1 if true.
328 * Need to check all the MD 'virtual-device' nodes for a 'device-type' property
329 * of 'vcc', 'vsw' or 'vds'.
330 */
331 static int
v12n_check_virtual_service(md_t * mdp)332 v12n_check_virtual_service(md_t *mdp)
333 {
334 static char *vdevs[] = {
335 "vcc",
336 "vsw",
337 "vds",
338 NULL
339 };
340
341 return (v12n_scan_md_nodes(mdp, "virtual-device", "device-type",
342 vdevs));
343 }
344
345 /*
346 * Check if MD has an physical I/O device node, returns 1 if true.
347 */
348 static int
v12n_check_io_service(md_t * mdp)349 v12n_check_io_service(md_t *mdp)
350 {
351 return (v12n_scan_md_nodes(mdp, "iodevice", NULL, NULL));
352 }
353
354 /*
355 * Check if a MD node is root PCI device, returns 1 if true.
356 * Need to check all the MD 'iodevice' nodes for a 'device-type' property
357 * of 'pciex'.
358 */
359 static int
v12n_check_root(md_t * mdp)360 v12n_check_root(md_t *mdp)
361 {
362 static char *pciex[] = {
363 "pciex",
364 NULL
365 };
366
367 return (v12n_scan_md_nodes(mdp, "iodevice", "device-type", pciex));
368 }
369
370 /*
371 * Get the domain roles for the domain.
372 */
373 int
v12n_domain_roles()374 v12n_domain_roles()
375 {
376 md_t *mdp;
377 int roles = 0;
378
379 if (v12n_capabilities() != V12N_LDOMS_SUPPORTED) {
380 errno = ENOTSUP;
381 return (-1);
382 }
383
384 if ((mdp = v12n_md_init()) == NULL) {
385 errno = EACCES;
386 return (-1);
387 }
388
389 if (v12n_check_hv_access(mdp))
390 roles |= V12N_ROLE_CONTROL;
391
392 if (v12n_check_virtual_service(mdp))
393 roles |= V12N_ROLE_SERVICE;
394
395 if (v12n_check_io_service(mdp))
396 roles |= V12N_ROLE_IO;
397
398 if (v12n_check_root(mdp))
399 roles |= V12N_ROLE_ROOT;
400
401 v12n_md_fini(mdp);
402
403 return (roles);
404 }
405
406 /*
407 * Get domain name from MD's virtual domain service node, returns 1 on success.
408 * The domain name is a string property 'vlds-domain-name' under the
409 * 'virtual-device' device node whose name is 'virtual-domain-service'.
410 */
411 static int
v12n_get_md_domain_name(md_t * mdp,char ** vds_dnamep)412 v12n_get_md_domain_name(md_t *mdp, char **vds_dnamep)
413 {
414 mde_cookie_t *vdev_nodes, rootnode;
415 int list_size, nvdevs, num_nodes, i, rv;
416 char *vldc_name;
417
418 num_nodes = md_node_count(mdp);
419 list_size = num_nodes * sizeof (mde_cookie_t);
420 vdev_nodes = malloc(list_size);
421 if (vdev_nodes == NULL) {
422 return (0);
423 }
424
425 rootnode = md_root_node(mdp);
426
427 nvdevs = md_scan_dag(mdp, rootnode, md_find_name(mdp, "virtual-device"),
428 md_find_name(mdp, "fwd"), vdev_nodes);
429
430 rv = 0;
431 for (i = 0; i < nvdevs; i++) {
432 if (md_get_prop_str(mdp, vdev_nodes[i], "name", &vldc_name))
433 continue;
434 if (strcmp(vldc_name, "virtual-domain-service") == 0) {
435 rv = (md_get_prop_str(mdp, vdev_nodes[i],
436 "vlds-domain-name", vds_dnamep) == 0);
437 break;
438 }
439 }
440 free(vdev_nodes);
441 return (rv);
442 }
443
444 /*
445 * String copyout utility.
446 */
447 static size_t
v12n_string_copyout(char * sout,char * sfrom,size_t count)448 v12n_string_copyout(char *sout, char *sfrom, size_t count)
449 {
450 size_t ret = strlen(sfrom) + 1;
451
452 if (sout != NULL && count > 0) {
453 count = MIN(ret, count);
454 (void) memcpy(sout, sfrom, count);
455 }
456 return (ret);
457 }
458
459 /*
460 * Get the domain name of this domain.
461 */
462 size_t
v12n_domain_name(char * buf,size_t count)463 v12n_domain_name(char *buf, size_t count)
464 {
465 md_t *mdp = NULL;
466 char *ldmname;
467 int rv = -1;
468
469 if (v12n_capabilities() != V12N_LDOMS_SUPPORTED) {
470 errno = ENOTSUP;
471 } else if ((mdp = v12n_md_init()) == NULL) {
472 errno = EACCES;
473 } else if (!v12n_get_md_domain_name(mdp, &ldmname)) {
474 errno = ESRCH;
475 } else {
476 rv = v12n_string_copyout(buf, ldmname, count);
477 }
478
479 v12n_md_fini(mdp);
480 return (rv);
481 }
482
483 /*
484 * Get UUID string from MD, returns 1 on success.
485 * The UUID is a string property 'uuid' under the 'platform' node of the MD.
486 */
487 static int
v12n_get_md_uuid_str(md_t * mdp,char ** uuid_strp)488 v12n_get_md_uuid_str(md_t *mdp, char **uuid_strp)
489 {
490 mde_cookie_t *plat_nodes, rootnode;
491 int list_size, npnodes, num_nodes, rv;
492
493 num_nodes = md_node_count(mdp);
494 list_size = num_nodes * sizeof (mde_cookie_t);
495 plat_nodes = malloc(list_size);
496 if (plat_nodes == NULL) {
497 return (0);
498 }
499
500 rootnode = md_root_node(mdp);
501
502 npnodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "platform"),
503 md_find_name(mdp, "fwd"), plat_nodes);
504
505 if (npnodes >= 1)
506 rv = !md_get_prop_str(mdp, plat_nodes[0], "uuid", uuid_strp);
507 else
508 rv = 0;
509
510 free(plat_nodes);
511 return (rv);
512 }
513
514 /*
515 * Get the domain UUID.
516 */
517 int
v12n_domain_uuid(uuid_t uuid)518 v12n_domain_uuid(uuid_t uuid)
519 {
520 md_t *mdp = NULL;
521 char *uuid_str;
522 int rv = -1;
523
524 if (v12n_capabilities() != V12N_LDOMS_SUPPORTED) {
525 errno = ENOTSUP;
526 } else if ((mdp = v12n_md_init()) == NULL) {
527 errno = EACCES;
528 } else if (!v12n_get_md_uuid_str(mdp, &uuid_str)) {
529 errno = ESRCH;
530 } else {
531 rv = uuid_parse(uuid_str, uuid);
532 }
533
534 v12n_md_fini(mdp);
535
536 return (rv);
537 }
538
539 /*
540 * Send 'agent-sytem' request message.
541 */
542 static int
v12n_ldma_send_request()543 v12n_ldma_send_request()
544 {
545 ldma_message_header_t ldmamsg;
546
547 if (v12n_ds_send_msg == NULL || v12n_ldma_ctrl_hdl == DS_INVALID_HDL)
548 return (ENOENT);
549
550 ldmamsg.msg_num = 0;
551 ldmamsg.msg_type = v12n_ldma_msgtype;
552 ldmamsg.msg_info = 0;
553 return (v12n_ds_send_msg(v12n_ldma_ctrl_hdl, (char *)&ldmamsg,
554 sizeof (ldmamsg)));
555 }
556
557 /*
558 * 'agent-system' registration handler.
559 * If we get a registration from the control domain (domain 0), then send
560 * the requested message. Otherwise, ignore the registration.
561 */
562 /* ARGSUSED */
563 static void
v12n_ldma_register_handler(ds_hdl_t hdl,ds_cb_arg_t arg,ds_ver_t * ver,ds_domain_hdl_t dhdl)564 v12n_ldma_register_handler(ds_hdl_t hdl, ds_cb_arg_t arg, ds_ver_t *ver,
565 ds_domain_hdl_t dhdl)
566 {
567
568 /* got registration from control domain */
569 if (dhdl == 0) {
570 (void) mutex_lock(&v12n_ldma_cv_lock);
571 if (v12n_ldma_cv_state == V12N_LDMA_REGWAITING) {
572 v12n_ldma_ctrl_hdl = hdl;
573 v12n_ldma_cv_state = V12N_LDMA_REGRECEIVED;
574 (void) cond_signal(&v12n_ldma_cv);
575 }
576 (void) mutex_unlock(&v12n_ldma_cv_lock);
577 }
578 }
579
580 /*
581 * 'agent-system' data handler.
582 */
583 /* ARGSUSED */
584 static void
v12n_ldma_data_handler(ds_hdl_t hdl,ds_cb_arg_t arg,void * buf,size_t buflen)585 v12n_ldma_data_handler(ds_hdl_t hdl, ds_cb_arg_t arg, void *buf,
586 size_t buflen)
587 {
588 char *data;
589 ldma_message_header_t *ldmp;
590 int n;
591 int cv_state = V12N_LDMA_MSGERROR;
592
593 /*
594 * Ignore any message not from the control domain.
595 */
596 if (v12n_ldma_ctrl_hdl != hdl)
597 return;
598
599 /*
600 * Ignore any unexpected message.
601 */
602 if (buflen < LDMA_MESSAGE_HEADER_SIZE)
603 return;
604
605 /*
606 * Ignore message with unexpected msgnum.
607 */
608 ldmp = (ldma_message_header_t *)buf;
609 if (ldmp->msg_num != 0)
610 return;
611
612 switch (ldmp->msg_type) {
613
614 case LDMA_MSG_RESULT:
615 if (ldmp->msg_info == 0 ||
616 ldmp->msg_info > LDMA_MESSAGE_DLEN(buflen)) {
617 cv_state = V12N_LDMA_MSGERROR;
618 break;
619 }
620 data = LDMA_HDR2DATA(buf);
621
622 /* ensure that data ends with a '\0' */
623 data[ldmp->msg_info - 1] = '\0';
624 switch (v12n_ldma_msgtype) {
625
626 case LDMA_MSGSYS_GET_SYSINFO:
627 /*
628 * Control domain nodename is second string in the
629 * message. Make sure there is enough data in the msg
630 * to have a second string.
631 */
632 n = strlen(data);
633 if (LDMA_MESSAGE_DLEN(buflen) <= n + 3) {
634 cv_state = V12N_LDMA_MSGERROR;
635 break;
636 }
637 data += n + 1;
638 if ((v12n_ldma_msgstr = strdup(data)) == NULL)
639 cv_state = V12N_LDMA_MSGERROR;
640 else
641 cv_state = V12N_LDMA_MSGRECEIVED;
642 break;
643
644 case LDMA_MSGSYS_GET_CHASSISNO:
645 if ((v12n_ldma_msgstr = strdup(data)) == NULL)
646 cv_state = V12N_LDMA_MSGERROR;
647 else
648 cv_state = V12N_LDMA_MSGRECEIVED;
649 break;
650
651 default:
652 /* v12n_ldma_msgtype must be valid */
653 ASSERT(0);
654 }
655 break;
656
657 case LDMA_MSG_ERROR:
658 cv_state = V12N_LDMA_MSGERROR;
659 break;
660
661 default:
662 /* unexpected message, ignored */
663 return;
664 }
665
666 (void) mutex_lock(&v12n_ldma_cv_lock);
667 v12n_ldma_cv_state = cv_state;
668 (void) cond_signal(&v12n_ldma_cv);
669 (void) mutex_unlock(&v12n_ldma_cv_lock);
670 }
671
672
673 /*
674 * libds doesn't exist on non-sun4v, dynamically load it and get the
675 * function pointers to the needed lib functions.
676 */
677 static int
v12n_libds_init(void)678 v12n_libds_init(void)
679 {
680 if (v12n_ds_dlhdl != NULL) {
681 if (v12n_ds_clnt_reg == NULL || v12n_ds_send_msg == NULL ||
682 v12n_ds_unreg_svc == NULL)
683 return (ENOENT);
684 return (0);
685 }
686
687 if ((v12n_ds_dlhdl = dlopen("libds.so.1",
688 RTLD_NOW | RTLD_GLOBAL)) == NULL)
689 return (ENOENT);
690
691 if ((v12n_ds_clnt_reg = (int (*)(ds_capability_t *, ds_ops_t *))
692 dlsym(v12n_ds_dlhdl, "ds_clnt_reg")) == NULL)
693 return (ENOENT);
694
695 if ((v12n_ds_send_msg = (int (*)(ds_hdl_t, void *, size_t))
696 dlsym(v12n_ds_dlhdl, "ds_send_msg")) == NULL)
697 return (ENOENT);
698
699 if ((v12n_ds_unreg_svc = (int (*)(char *, boolean_t))
700 dlsym(v12n_ds_dlhdl, "ds_unreg_svc")) == NULL)
701 return (ENOENT);
702
703 return (0);
704 }
705
706 /*
707 * Initiate and wait for an ldmad 'agent-system' domain service.
708 * Dynamically load libds, register the client 'agent-system' service
709 * and wait for a specified amount of time for the 'agent-system'
710 * service on the control domain to respond to the request.
711 */
712 static int
v12n_get_ldma_system_msg(int msgtype,char ** strp)713 v12n_get_ldma_system_msg(int msgtype, char **strp)
714 {
715 int tout;
716 int err = 0;
717 timestruc_t timeout;
718
719 /*
720 * Ensure that there's only one thread trying to do a
721 * 'agent-system' client registration/message at a time.
722 */
723 (void) mutex_lock(&v12n_ldma_lock);
724 if ((err = v12n_libds_init()) != 0) {
725 (void) mutex_unlock(&v12n_ldma_lock);
726 return (err);
727 }
728
729 v12n_ldma_msgtype = msgtype;
730 v12n_ldma_msgstr = NULL;
731
732 /* initialize v12n_ldma_cv_state variable before registering service */
733 (void) mutex_lock(&v12n_ldma_cv_lock);
734 v12n_ldma_cv_state = V12N_LDMA_REGWAITING;
735 (void) mutex_unlock(&v12n_ldma_cv_lock);
736
737 /*
738 * Other instances may be trying to load the "agent-system" service.
739 * If a collision happens (EBUSY error), wait and try again.
740 */
741 for (tout = 0; tout < v12n_ldma_timeout; tout += v12n_ldma_sleeptime) {
742 if ((err = v12n_ds_clnt_reg(&v12n_ldma_cap,
743 &v12n_ldma_ops)) == 0)
744 break;
745 if (err != EALREADY) {
746 goto done;
747 }
748 (void) sleep(v12n_ldma_sleeptime);
749 }
750
751 if (tout >= v12n_ldma_timeout) {
752 err = EBUSY;
753 goto done;
754 }
755
756 /*
757 * Wait for control domain registration.
758 */
759 timeout.tv_sec = v12n_ldma_timeout;
760 timeout.tv_nsec = 0;
761
762 (void) mutex_lock(&v12n_ldma_cv_lock);
763 while (v12n_ldma_cv_state == V12N_LDMA_REGWAITING) {
764 if ((err = cond_reltimedwait(&v12n_ldma_cv,
765 &v12n_ldma_cv_lock, &timeout)) != EINTR)
766 break;
767 }
768
769 /*
770 * Check for timeout or an error.
771 */
772 if (v12n_ldma_cv_state != V12N_LDMA_REGRECEIVED) {
773 if (err == 0)
774 err = EPROTO;
775 (void) mutex_unlock(&v12n_ldma_cv_lock);
776 goto done;
777 }
778
779 /*
780 * Received a registration request, send the request message.
781 */
782 v12n_ldma_cv_state = V12N_LDMA_MSGWAITING;
783 if ((err = v12n_ldma_send_request()) != 0) {
784 (void) mutex_unlock(&v12n_ldma_cv_lock);
785 goto done;
786 }
787
788 while (v12n_ldma_cv_state == V12N_LDMA_MSGWAITING) {
789 if ((err = cond_reltimedwait(&v12n_ldma_cv,
790 &v12n_ldma_cv_lock, &timeout)) != EINTR)
791 break;
792 }
793
794 if (v12n_ldma_cv_state != V12N_LDMA_MSGRECEIVED) {
795 if (err == 0)
796 err = EPROTO;
797 (void) mutex_unlock(&v12n_ldma_cv_lock);
798 goto done;
799 }
800
801 v12n_ldma_cv_state = V12N_LDMA_CVINVALID;
802 (void) mutex_unlock(&v12n_ldma_cv_lock);
803
804 /*
805 * If v12n_ldma_msgstr is set, a valid data response was seen.
806 */
807 if (v12n_ldma_msgstr == NULL)
808 err = ENODATA;
809 else {
810 if (*v12n_ldma_msgstr == '\0' ||
811 (*strp = strdup(v12n_ldma_msgstr)) == NULL)
812 err = ENODATA;
813 free(v12n_ldma_msgstr);
814 v12n_ldma_msgstr = NULL;
815 }
816
817 done:
818 v12n_ds_unreg_svc(LDMA_NAME_SYSTEM, B_TRUE);
819 v12n_ldma_msgtype = -1;
820 v12n_ldma_ctrl_hdl = DS_INVALID_HDL;
821 (void) mutex_unlock(&v12n_ldma_lock);
822
823 return (err);
824 }
825
826 /*
827 * Get the nodename of the control domain. Returns the equivalent
828 * of 'uname -n' on the control domain.
829 * This is obtained via the 'agent-system' domain service provided
830 * by ldmad.
831 */
832 size_t
v12n_ctrl_domain(char * buf,size_t count)833 v12n_ctrl_domain(char *buf, size_t count)
834 {
835 char *str;
836 int err;
837 size_t rv = (size_t)(-1);
838
839 if (v12n_capabilities() != V12N_LDOMS_SUPPORTED) {
840 errno = ENOTSUP;
841 } else if ((err = v12n_get_ldma_system_msg(LDMA_MSGSYS_GET_SYSINFO,
842 &str)) != 0) {
843 errno = err;
844 } else {
845 rv = v12n_string_copyout(buf, str, count);
846 }
847 return (rv);
848 }
849
850 /*
851 * Get the Chassis serial number from the Control Domain.
852 * This is obtained via the 'agent-system' domain service provided
853 * by ldmad.
854 */
855 size_t
v12n_chassis_serialno(char * buf,size_t count)856 v12n_chassis_serialno(char *buf, size_t count)
857 {
858 char *str;
859 int err;
860 size_t rv = (size_t)(-1);
861
862 if (v12n_capabilities() != V12N_LDOMS_SUPPORTED) {
863 errno = ENOTSUP;
864 } else if ((err = v12n_get_ldma_system_msg(LDMA_MSGSYS_GET_CHASSISNO,
865 &str)) != 0) {
866 errno = err;
867 } else {
868 rv = v12n_string_copyout(buf, str, count);
869 }
870 return (rv);
871 }
872