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