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