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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdlib.h> 27 #include <stdio.h> 28 29 #include <strings.h> 30 #include <sys/types.h> 31 #include <sys/stat.h> 32 #include <time.h> 33 #include <fcntl.h> 34 #include <unistd.h> 35 #include <errno.h> 36 #include <assert.h> 37 #include <umem.h> 38 #include <alloca.h> 39 #include <sys/processor.h> 40 #include <poll.h> 41 #include <pthread.h> 42 #include <values.h> 43 #include <libscf.h> 44 45 #include <ctype.h> 46 47 #include "ldmsvcs_utils.h" 48 49 #define ASSERT(cnd) \ 50 ((void) ((cnd) || ((void) fprintf(stderr, \ 51 "assertion failure in %s:%d: %s\n", \ 52 __FILE__, __LINE__, #cnd), 0))) 53 54 #define FDS_VLDC \ 55 "/devices/virtual-devices@100/channel-devices@200/" \ 56 "/virtual-channel-client@1:ldmfma" 57 58 /* allow timeouts in sec that are nearly forever but small enough for an int */ 59 #define LDM_TIMEOUT_CEILING (MAXINT / 2) 60 61 #define MIN(x, y) ((x) < (y) ? (x) : (y)) 62 63 /* 64 * functions in this file are for version 1.0 of FMA domain services 65 */ 66 static ds_ver_t ds_vers[] = { 67 { 1, 0 } 68 }; 69 70 #define DS_NUM_VER (sizeof (ds_vers) / sizeof (ds_ver_t)) 71 72 /* 73 * information for each channel 74 */ 75 struct ldmsvcs_info { 76 pthread_mutex_t mt; 77 pthread_cond_t cv; 78 fds_channel_t fds_chan; 79 fds_reg_svcs_t fmas_svcs; 80 int cv_twait; 81 }; 82 83 /* 84 * struct listdata_s and struct poller_s are used to maintain the state of 85 * the poller thread. this thread is used to manage incoming messages and 86 * pass those messages onto the correct requesting thread. see the "poller 87 * functions" section for more details. 88 */ 89 struct listdata_s { 90 enum { 91 UNUSED, 92 PENDING, 93 ARRIVED 94 } status; 95 uint64_t req_num; 96 int fd; 97 size_t datalen; 98 }; 99 100 static struct poller_s { 101 pthread_mutex_t mt; 102 pthread_cond_t cv; 103 pthread_t polling_tid; 104 int doreset; 105 int doexit; 106 int nclients; 107 struct listdata_s **list; 108 int list_len; 109 int pending_count; 110 } pollbase = { 111 PTHREAD_MUTEX_INITIALIZER, 112 PTHREAD_COND_INITIALIZER, 113 0, 114 1, 115 0, 116 0, 117 NULL, 118 0, 119 0 120 }; 121 122 123 static struct ldmsvcs_info *channel_init(struct ldom_hdl *lhp); 124 static int channel_openreset(struct ldmsvcs_info *lsp); 125 static int read_msg(struct ldmsvcs_info *lsp); 126 127 static int 128 get_smf_int_val(char *prop_nm, int min, int max, int default_val) 129 { 130 scf_simple_prop_t *prop; /* SMF property */ 131 int64_t *valp; /* prop value ptr */ 132 int64_t val; /* prop value to return */ 133 134 val = default_val; 135 if ((prop = scf_simple_prop_get(NULL, LDM_SVC_NM, LDM_PROP_GROUP_NM, 136 prop_nm)) != NULL) { 137 if ((valp = scf_simple_prop_next_integer(prop)) != NULL) { 138 val = *valp; 139 if (val < min) 140 val = min; 141 else if (val > max) 142 val = max; 143 } 144 scf_simple_prop_free(prop); 145 } 146 return ((int)val); 147 } 148 149 static void 150 channel_close(struct ldmsvcs_info *lsp) 151 { 152 (void) pthread_mutex_lock(&lsp->mt); 153 154 if (lsp->fds_chan.state == CHANNEL_OPEN || 155 lsp->fds_chan.state == CHANNEL_READY) { 156 (void) close(lsp->fds_chan.fd); 157 lsp->cv_twait = get_smf_int_val(LDM_INIT_TO_PROP_NM, 158 0, LDM_TIMEOUT_CEILING, LDM_INIT_WAIT_TIME); 159 lsp->fds_chan.state = CHANNEL_CLOSED; 160 } 161 162 (void) pthread_mutex_unlock(&lsp->mt); 163 } 164 165 /* 166 * read size bytes of data from a streaming fd into buf 167 */ 168 static int 169 read_stream(int fd, void *buf, size_t size) 170 { 171 pollfd_t pollfd; 172 ssize_t rv; 173 size_t data_left; 174 ptrdiff_t currentp; 175 176 pollfd.events = POLLIN; 177 pollfd.revents = 0; 178 pollfd.fd = fd; 179 180 currentp = (ptrdiff_t)buf; 181 data_left = size; 182 183 /* 184 * data may come in bits and pieces 185 */ 186 do { 187 if ((rv = read(fd, (void *)currentp, data_left)) < 0) { 188 if (errno == EAGAIN && poll(&pollfd, 1, -1) > 0) 189 continue; /* retry */ 190 else 191 return (1); 192 } 193 194 data_left -= rv; 195 currentp += rv; 196 } while (data_left > 0); 197 198 return (0); 199 } 200 201 202 /* 203 * poller functions 204 * 205 * at init time, a thread is created for the purpose of monitoring incoming 206 * messages and doing one of the following: 207 * 208 * 1. doing the initial handshake and version negotiation 209 * 210 * 2. handing incoming data off to the requesting thread (which is an fmd 211 * module or scheme thread) 212 */ 213 static int 214 poller_handle_data(int fd, size_t payloadsize) 215 { 216 uint64_t *req_num; 217 void *pr; 218 size_t prlen; 219 int i; 220 221 prlen = sizeof (ds_data_handle_t) + sizeof (uint64_t); 222 223 if (payloadsize < prlen) 224 return (1); 225 226 pr = alloca(prlen); 227 228 if (read_stream(fd, pr, prlen) != 0) 229 return (1); 230 231 req_num = (uint64_t *)((ptrdiff_t)pr + sizeof (ds_data_handle_t)); 232 233 (void) pthread_mutex_lock(&pollbase.mt); 234 235 for (i = 0; i < pollbase.list_len; i++) { 236 if (pollbase.list[i]->req_num == *req_num) { 237 ASSERT(pollbase.list[i]->status == PENDING); 238 239 pollbase.list[i]->status = ARRIVED; 240 pollbase.list[i]->fd = fd; 241 pollbase.list[i]->datalen = payloadsize - prlen; 242 243 pollbase.pending_count--; 244 (void) pthread_cond_broadcast(&pollbase.cv); 245 break; 246 } 247 } 248 249 /* 250 * now wait for receiving thread to read in the data 251 */ 252 if (i < pollbase.list_len) { 253 while (pollbase.list[i]->status == ARRIVED) 254 (void) pthread_cond_wait(&pollbase.cv, &pollbase.mt); 255 } 256 257 (void) pthread_mutex_unlock(&pollbase.mt); 258 259 return (0); 260 } 261 262 263 /* 264 * note that this function is meant to handle only DS_DATA messages 265 */ 266 static int 267 poller_recv_data(struct ldom_hdl *lhp, uint64_t req_num, int index, 268 void **resp, size_t *resplen) 269 { 270 struct timespec twait; 271 int ier; 272 273 ier = 0; 274 twait.tv_sec = time(NULL) + lhp->lsinfo->cv_twait; 275 twait.tv_nsec = 0; 276 277 (void) pthread_mutex_lock(&pollbase.mt); 278 279 ASSERT(pollbase.list[index]->req_num == req_num); 280 281 while (pollbase.list[index]->status == PENDING && 282 pollbase.doreset == 0 && ier == 0) 283 ier = pthread_cond_timedwait(&pollbase.cv, &pollbase.mt, 284 &twait); 285 286 if (ier == 0) { 287 if (pollbase.doreset == 0) { 288 ASSERT(pollbase.list[index]->status == ARRIVED); 289 290 /* 291 * need to add req_num to beginning of resp 292 */ 293 *resplen = pollbase.list[index]->datalen + 294 sizeof (uint64_t); 295 *resp = lhp->allocp(*resplen); 296 *((uint64_t *)*resp) = req_num; 297 298 if (read_stream(pollbase.list[index]->fd, 299 (void *)((ptrdiff_t)*resp + sizeof (uint64_t)), 300 *resplen - sizeof (uint64_t)) != 0) 301 ier = ETIMEDOUT; 302 303 pollbase.list[index]->status = UNUSED; 304 pollbase.list[index]->req_num = 0; 305 (void) pthread_cond_broadcast(&pollbase.cv); 306 } else { 307 if (--(pollbase.pending_count) == 0) 308 (void) pthread_cond_broadcast(&pollbase.cv); 309 } 310 } 311 312 (void) pthread_mutex_unlock(&pollbase.mt); 313 314 ASSERT(ier == 0 || ier == ETIMEDOUT); 315 316 return (ier); 317 } 318 319 320 static void 321 poller_add_client(void) 322 { 323 (void) pthread_mutex_lock(&pollbase.mt); 324 pollbase.nclients++; 325 (void) pthread_mutex_unlock(&pollbase.mt); 326 } 327 328 329 static void 330 poller_remove_client(void) 331 { 332 (void) pthread_mutex_lock(&pollbase.mt); 333 pollbase.nclients--; 334 ASSERT(pollbase.nclients >= 0); 335 (void) pthread_mutex_unlock(&pollbase.mt); 336 } 337 338 339 static int 340 poller_add_pending(struct ldom_hdl *lhp, uint64_t req_num) 341 { 342 int newlen, index, i, j; 343 344 (void) pthread_mutex_lock(&pollbase.mt); 345 pollbase.pending_count++; 346 347 for (j = 0, index = -1; j < 2 && index == -1; j++) { 348 for (i = 0; i < pollbase.list_len; i++) { 349 if (pollbase.list[i]->status == UNUSED) { 350 pollbase.list[i]->status = PENDING; 351 pollbase.list[i]->req_num = req_num; 352 pollbase.list[i]->datalen = 0; 353 index = i; 354 break; 355 } 356 } 357 358 if (index == -1) { 359 struct listdata_s **newlist, **oldlist; 360 361 /* 362 * get to this point if list is not long enough. 363 * check for a runaway list. since requests are 364 * synchronous (clients send a request and need to 365 * wait for the result before returning) the size 366 * of the list cannot be much more than the number 367 * of clients. 368 */ 369 ASSERT(pollbase.list_len < pollbase.nclients + 1); 370 371 newlen = pollbase.list_len + 5; 372 newlist = lhp->allocp(newlen * 373 sizeof (struct listdata_s)); 374 375 for (i = 0; i < pollbase.list_len; i++) 376 newlist[i] = pollbase.list[i]; 377 378 oldlist = pollbase.list; 379 pollbase.list = newlist; 380 lhp->freep(oldlist, pollbase.list_len * 381 sizeof (struct listdata_s)); 382 383 for (i = pollbase.list_len; i < newlen; i++) { 384 pollbase.list[i] = 385 lhp->allocp(sizeof (struct listdata_s)); 386 pollbase.list[i]->status = UNUSED; 387 } 388 389 pollbase.list_len = newlen; 390 } 391 } 392 393 (void) pthread_mutex_unlock(&pollbase.mt); 394 ASSERT(index != -1); 395 396 return (index); 397 } 398 399 400 static void 401 poller_delete_pending(uint64_t req_num, int index) 402 { 403 (void) pthread_mutex_lock(&pollbase.mt); 404 405 ASSERT(pollbase.list[index]->req_num == req_num); 406 pollbase.list[index]->status = UNUSED; 407 408 if (--(pollbase.pending_count) == 0 && pollbase.doreset == 1) 409 (void) pthread_cond_broadcast(&pollbase.cv); 410 411 (void) pthread_mutex_unlock(&pollbase.mt); 412 } 413 414 415 static void 416 poller_shutdown(void) 417 { 418 (void) pthread_mutex_lock(&pollbase.mt); 419 420 pollbase.doexit = 1; 421 422 (void) pthread_mutex_unlock(&pollbase.mt); 423 } 424 425 426 /* 427 * perform the polling of incoming messages. manage any resets (usually 428 * due to one end of the connection being closed) as well as exit 429 * conditions. 430 */ 431 static void * 432 poller_loop(void *arg) 433 { 434 struct ldmsvcs_info *lsp; 435 pollfd_t pollfd; 436 int ier; 437 438 lsp = (struct ldmsvcs_info *)arg; 439 440 for (;;) { 441 (void) pthread_mutex_lock(&pollbase.mt); 442 443 if (pollbase.doexit) { 444 (void) pthread_mutex_unlock(&pollbase.mt); 445 break; 446 } 447 448 if (pollbase.doreset) { 449 int i; 450 451 while (pollbase.pending_count > 0) 452 (void) pthread_cond_wait(&pollbase.cv, 453 &pollbase.mt); 454 455 ASSERT(pollbase.pending_count == 0); 456 for (i = 0; i < pollbase.list_len; i++) 457 pollbase.list[i]->status = UNUSED; 458 459 pollbase.doreset = 0; 460 } 461 (void) pthread_mutex_unlock(&pollbase.mt); 462 463 if ((ier = channel_openreset(lsp)) == 1) { 464 continue; 465 } else if (ier == 2) { 466 /* 467 * start exit preparations 468 */ 469 poller_shutdown(); 470 continue; 471 } 472 473 pollfd.events = POLLIN; 474 pollfd.revents = 0; 475 pollfd.fd = lsp->fds_chan.fd; 476 477 if (poll(&pollfd, 1, -1) <= 0 || read_msg(lsp) != 0) { 478 /* 479 * read error and/or fd got closed 480 */ 481 (void) pthread_mutex_lock(&pollbase.mt); 482 pollbase.doreset = 1; 483 (void) pthread_mutex_unlock(&pollbase.mt); 484 485 channel_close(lsp); 486 } 487 } 488 489 return (NULL); 490 } 491 492 493 /* 494 * create the polling thread 495 */ 496 static int 497 poller_init(struct ldmsvcs_info *lsp) 498 { 499 int rc = 0; 500 501 (void) pthread_mutex_lock(&pollbase.mt); 502 503 if (pollbase.polling_tid == 0) { 504 pthread_attr_t attr; 505 506 /* 507 * create polling thread for receiving messages 508 */ 509 (void) pthread_attr_init(&attr); 510 (void) pthread_attr_setdetachstate(&attr, 511 PTHREAD_CREATE_DETACHED); 512 513 if (pthread_create(&pollbase.polling_tid, &attr, 514 poller_loop, lsp) != 0) 515 rc = 1; 516 517 (void) pthread_attr_destroy(&attr); 518 } 519 520 (void) pthread_mutex_unlock(&pollbase.mt); 521 522 return (rc); 523 } 524 525 526 /* 527 * utilities for message handlers 528 */ 529 static int 530 fds_send(struct ldmsvcs_info *lsp, void *msg, size_t msglen) 531 { 532 static pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER; 533 534 (void) pthread_mutex_lock(&mt); 535 536 if (write(lsp->fds_chan.fd, msg, msglen) != msglen) { 537 channel_close(lsp); 538 (void) pthread_mutex_unlock(&mt); 539 return (ETIMEDOUT); 540 } 541 542 (void) pthread_mutex_unlock(&mt); 543 return (0); 544 } 545 546 547 /* 548 * Find the max and min version supported 549 */ 550 static void 551 fds_min_max_versions(uint16_t *min_major, uint16_t *max_major) 552 { 553 int i; 554 555 *min_major = ds_vers[0].major; 556 *max_major = *min_major; 557 558 for (i = 1; i < DS_NUM_VER; i++) { 559 if (ds_vers[i].major < *min_major) 560 *min_major = ds_vers[i].major; 561 562 if (ds_vers[i].major > *max_major) 563 *max_major = ds_vers[i].major; 564 } 565 } 566 567 /* 568 * check whether the major and minor numbers requested by remote ds client 569 * can be satisfied. if the requested major is supported, true is 570 * returned, and the agreed minor is returned in new_minor. if the 571 * requested major is not supported, the routine returns false, and the 572 * closest major is returned in *new_major, upon which the ds client should 573 * renegotiate. the closest major is the just lower that the requested 574 * major number. 575 */ 576 static boolean_t 577 fds_negotiate_version(uint16_t req_major, uint16_t *new_majorp, 578 uint16_t *new_minorp) 579 { 580 int i = 0; 581 uint16_t major, lower_major; 582 uint16_t min_major, max_major; 583 boolean_t found_match = B_FALSE; 584 585 fds_min_max_versions(&min_major, &max_major); 586 587 /* 588 * if the minimum version supported is greater than the version 589 * requested, return the lowest version supported 590 */ 591 if (min_major > req_major) { 592 *new_majorp = min_major; 593 return (B_FALSE); 594 } 595 596 /* 597 * if the largest version supported is lower than the version 598 * requested, return the largest version supported 599 */ 600 if (max_major < req_major) { 601 *new_majorp = max_major; 602 return (B_FALSE); 603 } 604 605 /* 606 * now we know that the requested version lies between the min and 607 * max versions supported. check if the requested major can be 608 * found in supported versions. 609 */ 610 lower_major = min_major; 611 for (i = 0; i < DS_NUM_VER; i++) { 612 major = ds_vers[i].major; 613 if (major == req_major) { 614 found_match = B_TRUE; 615 *new_minorp = ds_vers[i].minor; 616 *new_majorp = major; 617 break; 618 } else if ((major < req_major) && (major > lower_major)) 619 lower_major = major; 620 } 621 622 /* 623 * If no match is found, return the closest available number 624 */ 625 if (!found_match) 626 *new_majorp = lower_major; 627 628 return (found_match); 629 } 630 631 632 /* 633 * return 0 if service is added; 1 if service is a duplicate 634 */ 635 static int 636 fds_svc_add(struct ldmsvcs_info *lsp, ds_reg_req_t *req, int minor) 637 { 638 fds_svc_t *svc; 639 int i, rc; 640 641 svc = NULL; 642 for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) { 643 if (strcmp(lsp->fmas_svcs.tbl[i]->name, req->svc_id) == 0) { 644 svc = lsp->fmas_svcs.tbl[i]; 645 break; 646 } 647 } 648 649 if (svc == NULL) 650 return (0); /* we don't need this service */ 651 652 (void) pthread_mutex_lock(&lsp->fmas_svcs.mt); 653 654 /* 655 * duplicate registration is OK --- we retain the previous entry 656 * (which has not been unregistered anyway) 657 */ 658 if (svc->state == DS_SVC_ACTIVE) { 659 rc = 1; 660 } else { 661 svc->state = DS_SVC_ACTIVE; 662 svc->hdl = req->svc_handle; 663 svc->ver.major = req->major_vers; 664 svc->ver.minor = minor; 665 666 rc = 0; 667 (void) pthread_cond_broadcast(&lsp->fmas_svcs.cv); 668 } 669 670 (void) pthread_mutex_unlock(&lsp->fmas_svcs.mt); 671 672 return (rc); 673 } 674 675 676 static void 677 fds_svc_reset(struct ldmsvcs_info *lsp, int index) 678 { 679 int i, start, end; 680 681 if (index >= 0) { 682 start = index; 683 end = index + 1; 684 } else { 685 start = 0; 686 end = lsp->fmas_svcs.nsvcs; 687 } 688 689 (void) pthread_mutex_lock(&lsp->fmas_svcs.mt); 690 691 for (i = start; i < end; i++) { 692 lsp->fmas_svcs.tbl[i]->hdl = 0; 693 lsp->fmas_svcs.tbl[i]->state = DS_SVC_INVAL; 694 lsp->fmas_svcs.tbl[i]->ver.major = 695 ds_vers[DS_NUM_VER - 1].major; 696 lsp->fmas_svcs.tbl[i]->ver.minor = 697 ds_vers[DS_NUM_VER - 1].minor; 698 } 699 700 (void) pthread_mutex_unlock(&lsp->fmas_svcs.mt); 701 } 702 703 704 static int 705 fds_svc_remove(struct ldmsvcs_info *lsp, ds_svc_hdl_t svc_handle) 706 { 707 int i; 708 709 for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) { 710 if (lsp->fmas_svcs.tbl[i]->hdl == svc_handle) { 711 fds_svc_reset(lsp, i); 712 return (0); 713 } 714 } 715 716 return (1); 717 } 718 719 720 /* 721 * message handlers 722 */ 723 /*ARGSUSED*/ 724 static void 725 ds_handle_msg_noop(struct ldmsvcs_info *lsp, void *buf, size_t len) 726 { 727 } 728 729 static void 730 ds_handle_init_req(struct ldmsvcs_info *lsp, void *buf, size_t len) 731 { 732 ds_init_req_t *req; 733 uint16_t new_major, new_minor; 734 size_t msglen; 735 736 req = (ds_init_req_t *)buf; 737 738 /* sanity check the incoming message */ 739 if (len != sizeof (ds_init_req_t)) { 740 channel_close(lsp); 741 return; 742 } 743 744 /* 745 * Check version info. ACK only if the major numbers exactly 746 * match. The service entity can retry with a new minor 747 * based on the response sent as part of the NACK. 748 */ 749 if (fds_negotiate_version(req->major_vers, &new_major, &new_minor)) { 750 ds_hdr_t *H; 751 ds_init_ack_t *R; 752 753 msglen = sizeof (ds_hdr_t) + sizeof (ds_init_ack_t); 754 H = alloca(msglen); 755 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 756 757 H->msg_type = DS_INIT_ACK; 758 H->payload_len = sizeof (ds_init_ack_t); 759 R->minor_vers = MIN(new_minor, req->minor_vers); 760 761 if (fds_send(lsp, H, msglen) != 0) 762 return; 763 764 (void) pthread_mutex_lock(&lsp->mt); 765 ASSERT(lsp->fds_chan.state == CHANNEL_OPEN); 766 lsp->fds_chan.state = CHANNEL_READY; 767 768 /* 769 * Now the channel is ready after the handshake completes. 770 * Reset the timeout to a smaller value for receiving messages 771 * from the domain services. 772 */ 773 lsp->cv_twait = get_smf_int_val(LDM_RUNNING_TO_PROP_NM, 774 0, LDM_TIMEOUT_CEILING, LDM_RUNNING_WAIT_TIME); 775 776 (void) pthread_mutex_unlock(&lsp->mt); 777 } else { 778 ds_hdr_t *H; 779 ds_init_nack_t *R; 780 781 msglen = sizeof (ds_hdr_t) + sizeof (ds_init_nack_t); 782 H = alloca(msglen); 783 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 784 785 H->msg_type = DS_INIT_NACK; 786 H->payload_len = sizeof (ds_init_nack_t); 787 R->major_vers = new_major; 788 789 (void) fds_send(lsp, H, msglen); 790 /* 791 * do not update state; remote end may attempt to initiate 792 * connection with a different version 793 */ 794 } 795 } 796 797 798 /*ARGSUSED*/ 799 static void 800 ds_handle_reg_req(struct ldmsvcs_info *lsp, void *buf, size_t len) 801 { 802 ds_reg_req_t *req; 803 char *msg; 804 uint16_t new_major, new_minor; 805 size_t msglen; 806 int dup_svcreg = 0; 807 808 req = (ds_reg_req_t *)buf; 809 msg = (char *)req->svc_id; 810 811 /* 812 * Service must be NULL terminated 813 */ 814 if (req->svc_id == NULL || strlen(req->svc_id) == 0 || 815 msg[strlen(req->svc_id)] != '\0') { 816 channel_close(lsp); 817 return; 818 } 819 820 if (fds_negotiate_version(req->major_vers, &new_major, &new_minor) && 821 (dup_svcreg = fds_svc_add(lsp, req, 822 MIN(new_minor, req->minor_vers))) == 0) { 823 824 /* 825 * Check version info. ACK only if the major numbers 826 * exactly match. The service entity can retry with a new 827 * minor based on the response sent as part of the NACK. 828 */ 829 ds_hdr_t *H; 830 ds_reg_ack_t *R; 831 832 msglen = sizeof (ds_hdr_t) + sizeof (ds_reg_ack_t); 833 H = alloca(msglen); 834 bzero(H, msglen); 835 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 836 837 H->msg_type = DS_REG_ACK; 838 H->payload_len = sizeof (ds_reg_ack_t); 839 R->svc_handle = req->svc_handle; 840 R->minor_vers = MIN(new_minor, req->minor_vers); 841 842 (void) fds_send(lsp, H, msglen); 843 } else { 844 ds_hdr_t *H; 845 ds_reg_nack_t *R; 846 847 msglen = sizeof (ds_hdr_t) + sizeof (ds_reg_nack_t); 848 H = alloca(msglen); 849 bzero(H, msglen); 850 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 851 852 H->msg_type = DS_REG_NACK; 853 H->payload_len = sizeof (ds_reg_nack_t); 854 R->svc_handle = req->svc_handle; 855 R->major_vers = new_major; 856 857 if (dup_svcreg) 858 R->result = DS_REG_DUP; 859 else 860 R->result = DS_REG_VER_NACK; 861 862 (void) fds_send(lsp, H, msglen); 863 } 864 } 865 866 867 /*ARGSUSED*/ 868 static void 869 ds_handle_unreg(struct ldmsvcs_info *lsp, void *buf, size_t len) 870 { 871 ds_unreg_req_t *req; 872 size_t msglen; 873 874 req = (ds_unreg_req_t *)buf; 875 876 if (fds_svc_remove(lsp, req->svc_handle) == 0) { 877 ds_hdr_t *H; 878 ds_unreg_ack_t *R; 879 880 msglen = sizeof (ds_hdr_t) + sizeof (ds_unreg_ack_t); 881 H = alloca(msglen); 882 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 883 884 H->msg_type = DS_REG_ACK; 885 H->payload_len = sizeof (ds_unreg_ack_t); 886 R->svc_handle = req->svc_handle; 887 888 (void) fds_send(lsp, H, msglen); 889 } else { 890 ds_hdr_t *H; 891 ds_unreg_nack_t *R; 892 893 msglen = sizeof (ds_hdr_t) + sizeof (ds_unreg_nack_t); 894 H = alloca(msglen); 895 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 896 897 H->msg_type = DS_REG_NACK; 898 H->payload_len = sizeof (ds_unreg_nack_t); 899 R->svc_handle = req->svc_handle; 900 901 (void) fds_send(lsp, H, msglen); 902 } 903 } 904 905 906 /* 907 * Message handler lookup table (v1.0 only for now) Future 908 * versions can add their own lookup table. 909 */ 910 typedef void (*ds_msg_handler_t)(struct ldmsvcs_info *lsp, 911 void *buf, size_t len); 912 913 static const ds_msg_handler_t ds_msg_handlers[] = { 914 ds_handle_init_req, /* DS_INIT_REQ */ 915 ds_handle_msg_noop, /* DS_INIT_ACK */ 916 ds_handle_msg_noop, /* DS_INIT_NACK */ 917 ds_handle_reg_req, /* DS_REG_REQ */ 918 ds_handle_msg_noop, /* DS_REG_ACK */ 919 ds_handle_msg_noop, /* DS_REG_NACK */ 920 ds_handle_unreg, /* DS_UNREG */ 921 ds_handle_msg_noop, /* DS_UNREG_ACK */ 922 ds_handle_msg_noop, /* DS_UNREG_NACK */ 923 ds_handle_msg_noop, /* DS_DATA */ 924 ds_handle_msg_noop /* DS_NACK */ 925 }; 926 927 928 /* 929 * message and service internal functions 930 */ 931 static void 932 fds_svc_alloc(struct ldom_hdl *lhp, struct ldmsvcs_info *lsp) 933 { 934 int i; 935 static char *name[] = { LDM_DS_NAME_CPU, LDM_DS_NAME_MEM, 936 LDM_DS_NAME_PRI, LDM_DS_NAME_IOD, NULL }; 937 938 (void) pthread_mutex_init(&lsp->fmas_svcs.mt, NULL); 939 (void) pthread_cond_init(&lsp->fmas_svcs.cv, NULL); 940 941 for (lsp->fmas_svcs.nsvcs = 0; name[lsp->fmas_svcs.nsvcs] != NULL; 942 lsp->fmas_svcs.nsvcs++) 943 ; 944 945 lsp->fmas_svcs.tbl = (fds_svc_t **)lhp->allocp(sizeof (fds_svc_t *) * 946 lsp->fmas_svcs.nsvcs); 947 948 for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) { 949 lsp->fmas_svcs.tbl[i] = 950 (fds_svc_t *)lhp->allocp(sizeof (fds_svc_t)); 951 bzero(lsp->fmas_svcs.tbl[i], sizeof (fds_svc_t)); 952 lsp->fmas_svcs.tbl[i]->name = name[i]; 953 } 954 } 955 956 957 static fds_svc_t * 958 fds_svc_lookup(struct ldmsvcs_info *lsp, char *name) 959 { 960 struct timespec twait; 961 fds_svc_t *svc; 962 int i, ier; 963 964 if (pthread_mutex_lock(&lsp->fmas_svcs.mt) == EINVAL) 965 return (NULL); /* uninitialized or destroyed mutex */ 966 967 svc = NULL; 968 for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) { 969 if (strcmp(lsp->fmas_svcs.tbl[i]->name, name) == 0) { 970 svc = lsp->fmas_svcs.tbl[i]; 971 break; 972 } 973 } 974 975 ASSERT(svc != NULL); 976 977 if (svc->state == DS_SVC_INACTIVE) { 978 /* service is not registered */ 979 ier = ETIMEDOUT; 980 } else { 981 ier = 0; 982 twait.tv_sec = time(NULL) + lsp->cv_twait; 983 twait.tv_nsec = 0; 984 985 while (svc->state != DS_SVC_ACTIVE && ier == 0 && 986 lsp->fds_chan.state != CHANNEL_UNUSABLE) 987 ier = pthread_cond_timedwait(&lsp->fmas_svcs.cv, 988 &lsp->fmas_svcs.mt, &twait); 989 990 /* 991 * By now, the ds service should have registered already. 992 * If it does not, ldmd probably does not support this service. 993 * Then mark the service state as inactive. 994 */ 995 if (ier == ETIMEDOUT) { 996 svc->state = DS_SVC_INACTIVE; 997 } 998 } 999 1000 (void) pthread_mutex_unlock(&lsp->fmas_svcs.mt); 1001 1002 if (ier == 0) 1003 return (svc); 1004 else 1005 return (NULL); 1006 } 1007 1008 1009 static uint64_t 1010 fds_svc_req_num(void) 1011 { 1012 static uint64_t req_num = 1; 1013 1014 return (req_num++); 1015 } 1016 1017 1018 /* 1019 * return 0 if successful, 1 if otherwise 1020 */ 1021 static int 1022 read_msg(struct ldmsvcs_info *lsp) 1023 { 1024 ds_hdr_t header; 1025 void *msg_buf; 1026 1027 /* 1028 * read the header 1029 */ 1030 if (read_stream(lsp->fds_chan.fd, &header, sizeof (ds_hdr_t)) != 0) 1031 return (1); 1032 1033 if (header.msg_type >= 1034 sizeof (ds_msg_handlers) / sizeof (ds_msg_handler_t)) 1035 return (1); 1036 1037 /* 1038 * handle data as a special case 1039 */ 1040 if (header.msg_type == 9) 1041 return (poller_handle_data(lsp->fds_chan.fd, 1042 header.payload_len)); 1043 1044 /* 1045 * all other types of messages should be small 1046 */ 1047 ASSERT(header.payload_len < 1024); 1048 msg_buf = alloca(header.payload_len); 1049 1050 /* 1051 * read the payload 1052 */ 1053 if (read_stream(lsp->fds_chan.fd, msg_buf, header.payload_len) != 0) 1054 return (1); 1055 1056 (*ds_msg_handlers[header.msg_type])(lsp, msg_buf, header.payload_len); 1057 1058 return (0); 1059 } 1060 1061 1062 /* 1063 * return values: 1064 * 0 - success 1065 * 1 - problem with opening the channel 1066 * 2 - channed not opened; request to exit has been detected 1067 */ 1068 static int 1069 channel_openreset(struct ldmsvcs_info *lsp) 1070 { 1071 int ier; 1072 1073 ier = pthread_mutex_lock(&lsp->mt); 1074 1075 if (ier == EINVAL || lsp->fds_chan.state == CHANNEL_EXIT || 1076 lsp->fds_chan.state == CHANNEL_UNUSABLE) { 1077 (void) pthread_mutex_unlock(&lsp->mt); 1078 return (2); 1079 } 1080 1081 if (lsp->fds_chan.state == CHANNEL_UNINITIALIZED || 1082 lsp->fds_chan.state == CHANNEL_CLOSED) { 1083 (void) pthread_cond_broadcast(&lsp->cv); 1084 1085 if ((lsp->fds_chan.fd = open(FDS_VLDC, O_RDWR)) < 0) { 1086 lsp->fds_chan.state = CHANNEL_UNUSABLE; 1087 lsp->cv_twait = get_smf_int_val(LDM_RUNNING_TO_PROP_NM, 1088 0, LDM_TIMEOUT_CEILING, LDM_RUNNING_WAIT_TIME); 1089 (void) pthread_mutex_unlock(&lsp->mt); 1090 (void) pthread_cond_broadcast(&lsp->fmas_svcs.cv); 1091 1092 return (2); 1093 } else { 1094 vldc_opt_op_t op; 1095 1096 op.op_sel = VLDC_OP_SET; 1097 op.opt_sel = VLDC_OPT_MODE; 1098 op.opt_val = LDC_MODE_RELIABLE; 1099 1100 if (ioctl(lsp->fds_chan.fd, VLDC_IOCTL_OPT_OP, 1101 &op) != 0) { 1102 (void) close(lsp->fds_chan.fd); 1103 (void) pthread_mutex_unlock(&lsp->mt); 1104 return (1); 1105 } 1106 } 1107 lsp->fds_chan.state = CHANNEL_OPEN; 1108 } 1109 1110 if (lsp->fds_chan.state == CHANNEL_OPEN) { 1111 /* 1112 * reset various channel parameters 1113 */ 1114 lsp->fds_chan.ver.major = 0; 1115 lsp->fds_chan.ver.minor = 0; 1116 fds_svc_reset(lsp, -1); 1117 } 1118 (void) pthread_mutex_unlock(&lsp->mt); 1119 1120 return (0); 1121 } 1122 1123 1124 static void 1125 channel_fini(void) 1126 { 1127 struct ldmsvcs_info *lsp; 1128 1129 /* 1130 * End the poller thread 1131 */ 1132 poller_shutdown(); 1133 1134 if ((lsp = channel_init(NULL)) == NULL) 1135 return; 1136 1137 (void) pthread_mutex_lock(&lsp->mt); 1138 1139 lsp->fds_chan.state = CHANNEL_EXIT; 1140 (void) close(lsp->fds_chan.fd); 1141 1142 (void) pthread_mutex_unlock(&lsp->mt); 1143 } 1144 1145 1146 static struct ldmsvcs_info * 1147 channel_init(struct ldom_hdl *lhp) 1148 { 1149 static pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER; 1150 static pthread_cond_t cv = PTHREAD_COND_INITIALIZER; 1151 static struct ldmsvcs_info *root = NULL; 1152 static int busy_init = 0; 1153 1154 struct timespec twait; 1155 int expired; 1156 1157 (void) pthread_mutex_lock(&mt); 1158 1159 while (busy_init == 1) 1160 (void) pthread_cond_wait(&cv, &mt); 1161 1162 if (root != NULL || (lhp == NULL && root == NULL)) { 1163 (void) pthread_mutex_unlock(&mt); 1164 return (root); 1165 } 1166 1167 /* 1168 * get to this point if we need to open the channel 1169 */ 1170 busy_init = 1; 1171 (void) pthread_mutex_unlock(&mt); 1172 1173 root = (struct ldmsvcs_info *) 1174 lhp->allocp(sizeof (struct ldmsvcs_info)); 1175 bzero(root, sizeof (struct ldmsvcs_info)); 1176 1177 root->fds_chan.state = CHANNEL_UNINITIALIZED; 1178 root->cv_twait = get_smf_int_val(LDM_INIT_TO_PROP_NM, 1179 0, LDM_TIMEOUT_CEILING, LDM_INIT_WAIT_TIME); 1180 1181 if (pthread_mutex_init(&root->mt, NULL) != 0 || 1182 pthread_cond_init(&root->cv, NULL) != 0) { 1183 lhp->freep(root, sizeof (struct ldmsvcs_info)); 1184 return (NULL); 1185 } 1186 1187 fds_svc_alloc(lhp, root); 1188 fds_svc_reset(root, -1); 1189 1190 (void) poller_init(root); 1191 1192 expired = 0; 1193 twait.tv_sec = time(NULL) + 10; 1194 twait.tv_nsec = 0; 1195 1196 (void) pthread_mutex_lock(&root->mt); 1197 1198 /* 1199 * wait for channel to become uninitialized. this should be quick. 1200 */ 1201 while (root->fds_chan.state == CHANNEL_UNINITIALIZED && expired == 0) 1202 expired = pthread_cond_timedwait(&root->cv, &root->mt, &twait); 1203 1204 if (root->fds_chan.state == CHANNEL_UNUSABLE) 1205 expired = 1; 1206 1207 (void) pthread_mutex_unlock(&root->mt); 1208 1209 (void) pthread_mutex_lock(&mt); 1210 busy_init = 0; 1211 (void) pthread_mutex_unlock(&mt); 1212 (void) pthread_cond_broadcast(&cv); 1213 1214 (void) atexit(channel_fini); 1215 1216 if (expired == 0) 1217 return (root); 1218 else 1219 return (NULL); 1220 } 1221 1222 1223 static int 1224 sendrecv(struct ldom_hdl *lhp, uint64_t req_num, 1225 void *msg, size_t msglen, ds_svc_hdl_t *svc_hdl, char *svcname, 1226 void **resp, size_t *resplen) 1227 { 1228 struct ldmsvcs_info *lsp; 1229 fds_svc_t *svc; 1230 int maxretries, index, i, ier; 1231 1232 lsp = lhp->lsinfo; 1233 i = 0; 1234 maxretries = 1; 1235 1236 do { 1237 /* 1238 * if any of the calls in this loop fail, retry some number 1239 * of times before giving up. 1240 */ 1241 if ((svc = fds_svc_lookup(lsp, svcname)) == NULL) { 1242 (void) pthread_mutex_lock(&lsp->mt); 1243 1244 if (lsp->fds_chan.state != CHANNEL_READY) 1245 ier = ETIMEDOUT; /* channel not ready */ 1246 else 1247 ier = ENOTSUP; /* service not ready */ 1248 1249 (void) pthread_mutex_unlock(&lsp->mt); 1250 1251 continue; 1252 } else { 1253 ier = 0; 1254 *svc_hdl = svc->hdl; 1255 } 1256 1257 index = poller_add_pending(lhp, req_num); 1258 1259 if ((ier = fds_send(lsp, msg, msglen)) != 0 || 1260 (ier = poller_recv_data(lhp, req_num, index, resp, 1261 resplen)) != 0) 1262 poller_delete_pending(req_num, index); 1263 1264 } while (i++ < maxretries && ier != 0); 1265 1266 ASSERT(ier == 0 || ier == ETIMEDOUT || ier == ENOTSUP); 1267 1268 return (ier); 1269 } 1270 1271 1272 /* 1273 * input: 1274 * msg_type - requested operation: FMA_CPU_REQ_STATUS or FMA_CPU_REQ_OFFLINE 1275 * cpuid - physical cpu id 1276 * 1277 * normal return values: 1278 * P_OFFLINE - cpu is offline 1279 * P_ONLINE - cpu is online 1280 * 1281 * abnormal return values: 1282 * ETIMEDOUT - LDOM manager is not responding 1283 * ENOTSUP - LDOM service for cpu offlining/status is not available 1284 * ENOMSG - got an unexpected response from the LDOM cpu service 1285 */ 1286 static int 1287 cpu_request(struct ldom_hdl *lhp, uint32_t msg_type, uint32_t cpuid) 1288 { 1289 ds_hdr_t *H; 1290 ds_data_handle_t *D; 1291 fma_cpu_service_req_t *R; 1292 1293 char *svcname = LDM_DS_NAME_CPU; 1294 fma_cpu_resp_t *respmsg; 1295 void *resp; 1296 size_t resplen, reqmsglen; 1297 int rc; 1298 1299 if (lhp->lsinfo == NULL) 1300 return (ENOMSG); 1301 1302 reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) + 1303 sizeof (fma_cpu_service_req_t); 1304 1305 H = lhp->allocp(reqmsglen); 1306 D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 1307 R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t)); 1308 1309 H->msg_type = DS_DATA; 1310 H->payload_len = sizeof (ds_data_handle_t) + 1311 sizeof (fma_cpu_service_req_t); 1312 1313 R->req_num = fds_svc_req_num(); 1314 R->msg_type = msg_type; 1315 R->cpu_id = cpuid; 1316 1317 if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen, 1318 &D->svc_handle, svcname, &resp, &resplen)) != 0) { 1319 lhp->freep(H, reqmsglen); 1320 return (rc); 1321 } 1322 1323 lhp->freep(H, reqmsglen); 1324 1325 ASSERT(resplen == sizeof (fma_cpu_resp_t)); 1326 respmsg = (fma_cpu_resp_t *)resp; 1327 1328 rc = ENOMSG; 1329 if (respmsg->result == FMA_CPU_RESP_OK) { 1330 if (respmsg->status == FMA_CPU_STAT_ONLINE) 1331 rc = P_ONLINE; 1332 else if (respmsg->status == FMA_CPU_STAT_OFFLINE) 1333 rc = P_OFFLINE; 1334 } else { 1335 if (msg_type == FMA_CPU_REQ_OFFLINE && 1336 respmsg->status == FMA_CPU_STAT_OFFLINE) 1337 rc = P_OFFLINE; 1338 } 1339 1340 lhp->freep(resp, resplen); 1341 1342 return (rc); 1343 } 1344 1345 1346 /* 1347 * input: 1348 * msg_type - requested operation: FMA_MEM_REQ_STATUS or FMA_MEM_REQ_RETIRE 1349 * pa - starting address of memory page 1350 * pgsize - memory page size in bytes 1351 * 1352 * normal return values for msg_type == FMA_MEM_REQ_STATUS: 1353 * 0 - page is retired 1354 * EAGAIN - page is scheduled for retirement 1355 * EIO - page not scheduled for retirement 1356 * EINVAL - error 1357 * 1358 * normal return values for msg_type == FMA_MEM_REQ_RETIRE: 1359 * 0 - success in retiring page 1360 * EIO - page is already retired 1361 * EAGAIN - page is scheduled for retirement 1362 * EINVAL - error 1363 * 1364 * abnormal return values (regardless of msg_type) 1365 * ETIMEDOUT - LDOM manager is not responding 1366 * ENOTSUP - LDOM service for cpu offlining/status is not available 1367 * ENOMSG - got an unexpected response from the LDOM cpu service 1368 */ 1369 static int 1370 mem_request(struct ldom_hdl *lhp, uint32_t msg_type, uint64_t pa, 1371 uint64_t pgsize) 1372 { 1373 ds_hdr_t *H; 1374 ds_data_handle_t *D; 1375 fma_mem_service_req_t *R; 1376 1377 char *svcname = LDM_DS_NAME_MEM; 1378 fma_mem_resp_t *respmsg; 1379 void *resp; 1380 size_t resplen, reqmsglen; 1381 int rc; 1382 1383 if (lhp->lsinfo == NULL) 1384 return (ENOMSG); 1385 1386 reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) + 1387 sizeof (fma_mem_service_req_t); 1388 1389 H = lhp->allocp(reqmsglen); 1390 bzero(H, reqmsglen); 1391 D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 1392 R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t)); 1393 1394 H->msg_type = DS_DATA; 1395 H->payload_len = sizeof (ds_data_handle_t) + 1396 sizeof (fma_mem_service_req_t); 1397 1398 R->req_num = fds_svc_req_num(); 1399 R->msg_type = msg_type; 1400 R->real_addr = pa; 1401 R->length = pgsize; 1402 1403 if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen, 1404 &D->svc_handle, svcname, &resp, &resplen)) != 0) { 1405 lhp->freep(H, reqmsglen); 1406 return (rc); 1407 } 1408 1409 lhp->freep(H, reqmsglen); 1410 1411 ASSERT(resplen == sizeof (fma_mem_resp_t)); 1412 respmsg = (fma_mem_resp_t *)resp; 1413 1414 rc = ENOMSG; 1415 if (msg_type == FMA_MEM_REQ_STATUS) { 1416 if (respmsg->result == FMA_MEM_RESP_OK) { 1417 if (respmsg->status == FMA_MEM_STAT_RETIRED) 1418 rc = 0; /* page is retired */ 1419 else if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 1420 rc = EIO; /* page is not scheduled */ 1421 } else if (respmsg->result == FMA_MEM_RESP_FAILURE) { 1422 if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 1423 rc = EAGAIN; /* page is scheduled */ 1424 else if (respmsg->status == FMA_MEM_STAT_ILLEGAL) 1425 rc = EINVAL; 1426 } 1427 } else if (msg_type == FMA_MEM_REQ_RETIRE) { 1428 if (respmsg->result == FMA_MEM_RESP_OK) { 1429 if (respmsg->status == FMA_MEM_STAT_RETIRED) 1430 rc = 0; /* is successfully retired */ 1431 } else if (respmsg->result == FMA_MEM_RESP_FAILURE) { 1432 if (respmsg->status == FMA_MEM_STAT_RETIRED) 1433 rc = EIO; /* is already retired */ 1434 else if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 1435 rc = EAGAIN; /* is scheduled to retire */ 1436 else if (respmsg->status == FMA_MEM_STAT_ILLEGAL) 1437 rc = EINVAL; 1438 } 1439 } else if (msg_type == FMA_MEM_REQ_RESURRECT) { 1440 if (respmsg->result == FMA_MEM_RESP_OK) { 1441 if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 1442 rc = 0; /* is successfully unretired */ 1443 } if (respmsg->result == FMA_MEM_RESP_FAILURE) { 1444 if (respmsg->status == FMA_MEM_STAT_RETIRED) 1445 rc = EAGAIN; /* page couldn't be locked */ 1446 else if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 1447 rc = EIO; /* page isn't retired already */ 1448 else if (respmsg->status == FMA_MEM_STAT_ILLEGAL) 1449 rc = EINVAL; 1450 } 1451 } 1452 1453 lhp->freep(resp, resplen); 1454 1455 return (rc); 1456 } 1457 1458 1459 /* 1460 * APIs 1461 */ 1462 int 1463 ldmsvcs_check_channel(void) 1464 { 1465 struct stat buf; 1466 1467 if (stat(FDS_VLDC, &buf) == 0) 1468 return (0); /* vldc exists */ 1469 else if (errno == ENOENT || errno == ENOTDIR) 1470 return (1); /* vldc does not exist */ 1471 else 1472 return (-1); /* miscellaneous error */ 1473 } 1474 1475 1476 /*ARGSUSED*/ 1477 void 1478 ldmsvcs_init(struct ldom_hdl *lhp) 1479 { 1480 if (ldmsvcs_check_channel() != 0) 1481 return; 1482 1483 lhp->lsinfo = channel_init(lhp); 1484 poller_add_client(); 1485 } 1486 1487 1488 /*ARGSUSED*/ 1489 void 1490 ldmsvcs_fini(struct ldom_hdl *lhp) 1491 { 1492 if (ldmsvcs_check_channel() != 0) 1493 return; 1494 1495 poller_remove_client(); 1496 } 1497 1498 1499 /*ARGSUSED*/ 1500 ssize_t 1501 ldmsvcs_get_core_md(struct ldom_hdl *lhp, uint64_t **buf) 1502 { 1503 ds_hdr_t *H; 1504 ds_data_handle_t *D; 1505 fma_req_pri_t *R; 1506 1507 char *svcname = LDM_DS_NAME_PRI; 1508 void *resp; 1509 size_t resplen, reqmsglen; 1510 ssize_t buflen; 1511 int rc; 1512 1513 if (lhp->lsinfo == NULL) 1514 return (-1); 1515 1516 reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) + 1517 sizeof (fma_req_pri_t); 1518 1519 H = lhp->allocp(reqmsglen); 1520 D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 1521 R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t)); 1522 1523 H->msg_type = DS_DATA; 1524 H->payload_len = sizeof (ds_data_handle_t) + 1525 sizeof (fma_req_pri_t); 1526 1527 R->req_num = fds_svc_req_num(); 1528 1529 if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen, 1530 &D->svc_handle, svcname, &resp, &resplen)) != 0) { 1531 lhp->freep(H, reqmsglen); 1532 errno = rc; 1533 return (-1); 1534 } 1535 1536 lhp->freep(H, reqmsglen); 1537 1538 /* 1539 * resp should contain the req_num immediately followed by the PRI 1540 * (the latter may or may not be present). unfortunately, the 1541 * current compiler flags cause a warning for the following 1542 * definition 1543 * 1544 * typedef struct { 1545 * uint64_t req_num; 1546 * uint8_t pri[]; 1547 * } fma_pri_resp_t; 1548 * 1549 * so we do not use the struct here. 1550 */ 1551 if (resplen <= sizeof (uint64_t)) { 1552 lhp->freep(resp, resplen); 1553 if (resplen == sizeof (uint64_t)) 1554 return (0); 1555 else 1556 return (-1); 1557 } 1558 1559 buflen = resplen - sizeof (uint64_t); 1560 *buf = lhp->allocp(buflen); 1561 1562 bcopy((void *)((ptrdiff_t)resp + sizeof (uint64_t)), *buf, buflen); 1563 lhp->freep(resp, resplen); 1564 1565 return (buflen); 1566 } 1567 1568 1569 /* 1570 * see cpu_request() for a description of return values 1571 */ 1572 int 1573 ldmsvcs_cpu_req_status(struct ldom_hdl *lhp, uint32_t cpuid) 1574 { 1575 return (cpu_request(lhp, FMA_CPU_REQ_STATUS, cpuid)); 1576 } 1577 1578 1579 int 1580 ldmsvcs_cpu_req_offline(struct ldom_hdl *lhp, uint32_t cpuid) 1581 { 1582 return (cpu_request(lhp, FMA_CPU_REQ_OFFLINE, cpuid)); 1583 } 1584 1585 int 1586 ldmsvcs_cpu_req_online(struct ldom_hdl *lhp, uint32_t cpuid) 1587 { 1588 return (cpu_request(lhp, FMA_CPU_REQ_ONLINE, cpuid)); 1589 } 1590 1591 /* 1592 * see mem_request() for a description of return values 1593 */ 1594 int 1595 ldmsvcs_mem_req_status(struct ldom_hdl *lhp, uint64_t pa) 1596 { 1597 return (mem_request(lhp, FMA_MEM_REQ_STATUS, pa, getpagesize())); 1598 } 1599 1600 int 1601 ldmsvcs_mem_req_retire(struct ldom_hdl *lhp, uint64_t pa) 1602 { 1603 return (mem_request(lhp, FMA_MEM_REQ_RETIRE, pa, getpagesize())); 1604 } 1605 1606 int 1607 ldmsvcs_mem_req_unretire(struct ldom_hdl *lhp, uint64_t pa) 1608 { 1609 return (mem_request(lhp, FMA_MEM_REQ_RESURRECT, pa, getpagesize())); 1610 } 1611 1612 int 1613 ldmsvcs_io_req_id(struct ldom_hdl *lhp, uint64_t addr, uint_t type, 1614 uint64_t *virt_addr, char *name, int name_len, uint64_t *did) 1615 { 1616 1617 ds_hdr_t *H; 1618 ds_data_handle_t *D; 1619 fma_io_req_t *R; 1620 1621 char *svcname = LDM_DS_NAME_IOD; 1622 void *resp; 1623 fma_io_resp_t *iop; 1624 size_t resplen, reqmsglen; 1625 int offset; 1626 int rc; 1627 1628 if (lhp->lsinfo == NULL) 1629 return (-1); 1630 1631 reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) + 1632 sizeof (fma_io_req_t); 1633 1634 H = lhp->allocp(reqmsglen); 1635 D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 1636 R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t)); 1637 1638 H->msg_type = DS_DATA; 1639 H->payload_len = sizeof (ds_data_handle_t) + sizeof (fma_io_req_t); 1640 1641 R->req_num = fds_svc_req_num(); 1642 R->msg_type = type; 1643 R->rsrc_address = addr; 1644 1645 rc = ENOMSG; 1646 if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen, 1647 &D->svc_handle, svcname, &resp, &resplen)) != 0) { 1648 lhp->freep(H, reqmsglen); 1649 return (rc); 1650 } 1651 lhp->freep(H, reqmsglen); 1652 1653 /* 1654 * resp should contain the req_num, status, virtual addr, domain id 1655 * and the domain name. The domain name may or may not be present. 1656 */ 1657 offset = sizeof (fma_io_resp_t); 1658 if (resplen < offset) { 1659 lhp->freep(resp, resplen); 1660 return (-1); 1661 } 1662 1663 iop = (fma_io_resp_t *)resp; 1664 switch (iop->result) { 1665 case FMA_IO_RESP_OK: 1666 /* success */ 1667 rc = 0; 1668 *virt_addr = iop->virt_rsrc_address; 1669 *did = iop->domain_id; 1670 if (name == NULL || name_len <= 0) 1671 break; 1672 *name = '\0'; 1673 if (resplen > offset) { 1674 (void) strncpy(name, (char *)((ptrdiff_t)resp + offset), 1675 name_len); 1676 } 1677 break; 1678 default: 1679 rc = -1; 1680 break; 1681 } 1682 1683 lhp->freep(resp, resplen); 1684 return (rc); 1685 } 1686 1687 /* end file */ 1688