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