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