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