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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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