12072Svn83148 /* 22072Svn83148 * CDDL HEADER START 32072Svn83148 * 42072Svn83148 * The contents of this file are subject to the terms of the 52072Svn83148 * Common Development and Distribution License (the "License"). 62072Svn83148 * You may not use this file except in compliance with the License. 72072Svn83148 * 82072Svn83148 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 92072Svn83148 * or http://www.opensolaris.org/os/licensing. 102072Svn83148 * See the License for the specific language governing permissions 112072Svn83148 * and limitations under the License. 122072Svn83148 * 132072Svn83148 * When distributing Covered Code, include this CDDL HEADER in each 142072Svn83148 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 152072Svn83148 * If applicable, add the following below this CDDL HEADER, with the 162072Svn83148 * fields enclosed by brackets "[]" replaced with your own identifying 172072Svn83148 * information: Portions Copyright [yyyy] [name of copyright owner] 182072Svn83148 * 192072Svn83148 * CDDL HEADER END 202072Svn83148 */ 212072Svn83148 /* 226111Scy152378 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 232072Svn83148 * Use is subject to license terms. 242072Svn83148 */ 252072Svn83148 262072Svn83148 #pragma ident "%Z%%M% %I% %E% SMI" 272072Svn83148 282072Svn83148 #include <stdlib.h> 292072Svn83148 #include <stdio.h> 302072Svn83148 #include <strings.h> 312072Svn83148 #include <sys/types.h> 322072Svn83148 #include <sys/stat.h> 332072Svn83148 #include <time.h> 342072Svn83148 #include <fcntl.h> 352072Svn83148 #include <unistd.h> 362072Svn83148 #include <errno.h> 372072Svn83148 #include <assert.h> 382072Svn83148 #include <umem.h> 392072Svn83148 #include <alloca.h> 402072Svn83148 #include <sys/processor.h> 412072Svn83148 #include <poll.h> 422072Svn83148 #include <pthread.h> 434358Srb144127 #include <values.h> 444358Srb144127 #include <libscf.h> 452072Svn83148 462072Svn83148 #include "ldmsvcs_utils.h" 472072Svn83148 482072Svn83148 #define ASSERT(cnd) \ 492072Svn83148 ((void) ((cnd) || ((void) fprintf(stderr, \ 502072Svn83148 "assertion failure in %s:%d: %s\n", \ 512072Svn83148 __FILE__, __LINE__, #cnd), 0))) 522072Svn83148 532072Svn83148 #define FDS_VLDC \ 542072Svn83148 "/devices/virtual-devices@100/channel-devices@200/" \ 552072Svn83148 "/virtual-channel-client@1:ldmfma" 562072Svn83148 574358Srb144127 /* allow timeouts in sec that are nearly forever but small enough for an int */ 584358Srb144127 #define LDM_TIMEOUT_CEILING (MAXINT / 2) 592072Svn83148 602072Svn83148 #define MIN(x, y) ((x) < (y) ? (x) : (y)) 612072Svn83148 622072Svn83148 /* 632072Svn83148 * functions in this file are for version 1.0 of FMA domain services 642072Svn83148 */ 652072Svn83148 static ds_ver_t ds_vers[] = { 662072Svn83148 { 1, 0 } 672072Svn83148 }; 682072Svn83148 692072Svn83148 #define DS_NUM_VER (sizeof (ds_vers) / sizeof (ds_ver_t)) 702072Svn83148 712072Svn83148 /* 722072Svn83148 * information for each channel 732072Svn83148 */ 742072Svn83148 struct ldmsvcs_info { 752072Svn83148 pthread_mutex_t mt; 762072Svn83148 pthread_cond_t cv; 772072Svn83148 fds_channel_t fds_chan; 782072Svn83148 fds_reg_svcs_t fmas_svcs; 792072Svn83148 int cv_twait; 802072Svn83148 }; 812072Svn83148 822072Svn83148 /* 832072Svn83148 * struct listdata_s and struct poller_s are used to maintain the state of 842072Svn83148 * the poller thread. this thread is used to manage incoming messages and 852072Svn83148 * pass those messages onto the correct requesting thread. see the "poller 862072Svn83148 * functions" section for more details. 872072Svn83148 */ 882072Svn83148 struct listdata_s { 892072Svn83148 enum { 902072Svn83148 UNUSED, 912072Svn83148 PENDING, 922072Svn83148 ARRIVED 932072Svn83148 } status; 942072Svn83148 uint64_t req_num; 952072Svn83148 int fd; 962072Svn83148 size_t datalen; 972072Svn83148 }; 982072Svn83148 992072Svn83148 static struct poller_s { 1002072Svn83148 pthread_mutex_t mt; 1012072Svn83148 pthread_cond_t cv; 1022072Svn83148 pthread_t polling_tid; 1032072Svn83148 int doreset; 1042072Svn83148 int doexit; 1052072Svn83148 int nclients; 1062072Svn83148 struct listdata_s **list; 1072072Svn83148 int list_len; 1082072Svn83148 int pending_count; 1092072Svn83148 } pollbase = { 1102072Svn83148 PTHREAD_MUTEX_INITIALIZER, 1112072Svn83148 PTHREAD_COND_INITIALIZER, 1122072Svn83148 0, 1132072Svn83148 1, 1142072Svn83148 0, 1152072Svn83148 0, 1162072Svn83148 NULL, 1172072Svn83148 0, 1182072Svn83148 0 1192072Svn83148 }; 1202072Svn83148 1212072Svn83148 1222072Svn83148 static struct ldmsvcs_info *channel_init(struct ldom_hdl *lhp); 1232072Svn83148 static int channel_openreset(struct ldmsvcs_info *lsp); 1242072Svn83148 static int read_msg(struct ldmsvcs_info *lsp); 1252072Svn83148 1262072Svn83148 1274358Srb144127 static int 1284358Srb144127 get_smf_int_val(char *prop_nm, int min, int max, int default_val) 1294358Srb144127 { 1304358Srb144127 scf_simple_prop_t *prop; /* SMF property */ 1314358Srb144127 int64_t *valp; /* prop value ptr */ 1324358Srb144127 int64_t val; /* prop value to return */ 1334358Srb144127 1344358Srb144127 val = default_val; 1354358Srb144127 if ((prop = scf_simple_prop_get(NULL, LDM_SVC_NM, LDM_PROP_GROUP_NM, 1364358Srb144127 prop_nm)) != NULL) { 1374358Srb144127 if ((valp = scf_simple_prop_next_integer(prop)) != NULL) { 1384358Srb144127 val = *valp; 1394358Srb144127 if (val < min) 1404358Srb144127 val = min; 1414358Srb144127 else if (val > max) 1424358Srb144127 val = max; 1434358Srb144127 } 1444358Srb144127 scf_simple_prop_free(prop); 1454358Srb144127 } 1464358Srb144127 return ((int)val); 1474358Srb144127 } 1484358Srb144127 1492072Svn83148 static void 1502072Svn83148 channel_close(struct ldmsvcs_info *lsp) 1512072Svn83148 { 1522072Svn83148 (void) pthread_mutex_lock(&lsp->mt); 1532072Svn83148 1543327Svn83148 if (lsp->fds_chan.state == CHANNEL_OPEN || 1554358Srb144127 lsp->fds_chan.state == CHANNEL_READY) { 1563327Svn83148 (void) close(lsp->fds_chan.fd); 1574358Srb144127 lsp->cv_twait = get_smf_int_val(LDM_INIT_TO_PROP_NM, 1584358Srb144127 0, LDM_TIMEOUT_CEILING, LDM_INIT_WAIT_TIME); 1593327Svn83148 lsp->fds_chan.state = CHANNEL_CLOSED; 1603327Svn83148 } 1612072Svn83148 1622072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 1632072Svn83148 } 1642072Svn83148 1652072Svn83148 /* 1662072Svn83148 * read size bytes of data from a streaming fd into buf 1672072Svn83148 */ 1682072Svn83148 static int 1692072Svn83148 read_stream(int fd, void *buf, size_t size) 1702072Svn83148 { 1712072Svn83148 pollfd_t pollfd; 1722072Svn83148 ssize_t rv; 1732072Svn83148 size_t data_left; 1742072Svn83148 ptrdiff_t currentp; 1752072Svn83148 1762072Svn83148 pollfd.events = POLLIN; 1772072Svn83148 pollfd.revents = 0; 1782072Svn83148 pollfd.fd = fd; 1792072Svn83148 1802072Svn83148 currentp = (ptrdiff_t)buf; 1812072Svn83148 data_left = size; 1822072Svn83148 1832072Svn83148 /* 1842072Svn83148 * data may come in bits and pieces 1852072Svn83148 */ 1862072Svn83148 do { 1872072Svn83148 if ((rv = read(fd, (void *)currentp, data_left)) < 0) { 1882072Svn83148 if (errno == EAGAIN && poll(&pollfd, 1, -1) > 0) 1892072Svn83148 continue; /* retry */ 1902072Svn83148 else 1912072Svn83148 return (1); 1922072Svn83148 } 1932072Svn83148 1942072Svn83148 data_left -= rv; 1952072Svn83148 currentp += rv; 1962072Svn83148 } while (data_left > 0); 1972072Svn83148 1982072Svn83148 return (0); 1992072Svn83148 } 2002072Svn83148 2012072Svn83148 2022072Svn83148 /* 2032072Svn83148 * poller functions 2042072Svn83148 * 2052072Svn83148 * at init time, a thread is created for the purpose of monitoring incoming 2062072Svn83148 * messages and doing one of the following: 2072072Svn83148 * 2082072Svn83148 * 1. doing the initial handshake and version negotiation 2092072Svn83148 * 2102072Svn83148 * 2. handing incoming data off to the requesting thread (which is an fmd 2112072Svn83148 * module or scheme thread) 2122072Svn83148 */ 2132072Svn83148 static int 2142072Svn83148 poller_handle_data(int fd, size_t payloadsize) 2152072Svn83148 { 2162072Svn83148 uint64_t *req_num; 2172072Svn83148 void *pr; 2182072Svn83148 size_t prlen; 2192072Svn83148 int i; 2202072Svn83148 2212072Svn83148 prlen = sizeof (ds_data_handle_t) + sizeof (uint64_t); 2222072Svn83148 2232072Svn83148 if (payloadsize < prlen) 2242072Svn83148 return (1); 2252072Svn83148 2262072Svn83148 pr = alloca(prlen); 2272072Svn83148 2282072Svn83148 if (read_stream(fd, pr, prlen) != 0) 2292072Svn83148 return (1); 2302072Svn83148 2312072Svn83148 req_num = (uint64_t *)((ptrdiff_t)pr + sizeof (ds_data_handle_t)); 2322072Svn83148 2332072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 2342072Svn83148 2352072Svn83148 for (i = 0; i < pollbase.list_len; i++) { 2362072Svn83148 if (pollbase.list[i]->req_num == *req_num) { 2372072Svn83148 ASSERT(pollbase.list[i]->status == PENDING); 2382072Svn83148 2392072Svn83148 pollbase.list[i]->status = ARRIVED; 2402072Svn83148 pollbase.list[i]->fd = fd; 2412072Svn83148 pollbase.list[i]->datalen = payloadsize - prlen; 2422072Svn83148 2432072Svn83148 pollbase.pending_count--; 2442072Svn83148 (void) pthread_cond_broadcast(&pollbase.cv); 2452072Svn83148 break; 2462072Svn83148 } 2472072Svn83148 } 2482072Svn83148 2492072Svn83148 /* 2502072Svn83148 * now wait for receiving thread to read in the data 2512072Svn83148 */ 2522072Svn83148 if (i < pollbase.list_len) { 2532072Svn83148 while (pollbase.list[i]->status == ARRIVED) 2542072Svn83148 (void) pthread_cond_wait(&pollbase.cv, &pollbase.mt); 2552072Svn83148 } 2562072Svn83148 2572072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 2582072Svn83148 2592072Svn83148 return (0); 2602072Svn83148 } 2612072Svn83148 2622072Svn83148 2632072Svn83148 /* 2642072Svn83148 * note that this function is meant to handle only DS_DATA messages 2652072Svn83148 */ 2662072Svn83148 static int 2672072Svn83148 poller_recv_data(struct ldom_hdl *lhp, uint64_t req_num, int index, 2682072Svn83148 void **resp, size_t *resplen) 2692072Svn83148 { 2702072Svn83148 struct timespec twait; 2712072Svn83148 int ier; 2722072Svn83148 2732072Svn83148 ier = 0; 2742072Svn83148 twait.tv_sec = time(NULL) + lhp->lsinfo->cv_twait; 2752072Svn83148 twait.tv_nsec = 0; 2762072Svn83148 2772072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 2782072Svn83148 2792072Svn83148 ASSERT(pollbase.list[index]->req_num == req_num); 2802072Svn83148 2812072Svn83148 while (pollbase.list[index]->status == PENDING && 2822072Svn83148 pollbase.doreset == 0 && ier == 0) 2832072Svn83148 ier = pthread_cond_timedwait(&pollbase.cv, &pollbase.mt, 2844358Srb144127 &twait); 2852072Svn83148 2862072Svn83148 if (ier == 0) { 2872072Svn83148 if (pollbase.doreset == 0) { 2882072Svn83148 ASSERT(pollbase.list[index]->status == ARRIVED); 2892072Svn83148 2902072Svn83148 /* 2912072Svn83148 * need to add req_num to beginning of resp 2922072Svn83148 */ 2932072Svn83148 *resplen = pollbase.list[index]->datalen + 2944358Srb144127 sizeof (uint64_t); 2952072Svn83148 *resp = lhp->allocp(*resplen); 2962072Svn83148 *((uint64_t *)*resp) = req_num; 2972072Svn83148 2982072Svn83148 if (read_stream(pollbase.list[index]->fd, 2994358Srb144127 (void *)((ptrdiff_t)*resp + sizeof (uint64_t)), 3004358Srb144127 *resplen - sizeof (uint64_t)) != 0) 3012072Svn83148 ier = ETIMEDOUT; 3022072Svn83148 3032072Svn83148 pollbase.list[index]->status = UNUSED; 3042072Svn83148 pollbase.list[index]->req_num = 0; 3052072Svn83148 (void) pthread_cond_broadcast(&pollbase.cv); 3062072Svn83148 } else { 3072072Svn83148 if (--(pollbase.pending_count) == 0) 3082072Svn83148 (void) pthread_cond_broadcast(&pollbase.cv); 3092072Svn83148 } 3102072Svn83148 } 3112072Svn83148 3122072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 3132072Svn83148 3142072Svn83148 ASSERT(ier == 0 || ier == ETIMEDOUT); 3152072Svn83148 3162072Svn83148 return (ier); 3172072Svn83148 } 3182072Svn83148 3192072Svn83148 3202072Svn83148 static void 3212072Svn83148 poller_add_client(void) 3222072Svn83148 { 3232072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 3242072Svn83148 pollbase.nclients++; 3252072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 3262072Svn83148 } 3272072Svn83148 3282072Svn83148 3292072Svn83148 static void 3302072Svn83148 poller_remove_client(void) 3312072Svn83148 { 3322072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 3332072Svn83148 pollbase.nclients--; 3342072Svn83148 ASSERT(pollbase.nclients >= 0); 3352072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 3362072Svn83148 } 3372072Svn83148 3382072Svn83148 3392072Svn83148 static int 3402072Svn83148 poller_add_pending(struct ldom_hdl *lhp, uint64_t req_num) 3412072Svn83148 { 3422072Svn83148 int newlen, index, i, j; 3432072Svn83148 3442072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 3452072Svn83148 pollbase.pending_count++; 3462072Svn83148 3472072Svn83148 for (j = 0, index = -1; j < 2 && index == -1; j++) { 3482072Svn83148 for (i = 0; i < pollbase.list_len; i++) { 3492072Svn83148 if (pollbase.list[i]->status == UNUSED) { 3502072Svn83148 pollbase.list[i]->status = PENDING; 3512072Svn83148 pollbase.list[i]->req_num = req_num; 3522072Svn83148 pollbase.list[i]->datalen = 0; 3532072Svn83148 index = i; 3542072Svn83148 break; 3552072Svn83148 } 3562072Svn83148 } 3572072Svn83148 3582072Svn83148 if (index == -1) { 3592072Svn83148 struct listdata_s **newlist, **oldlist; 3602072Svn83148 3612072Svn83148 /* 3622072Svn83148 * get to this point if list is not long enough. 3632072Svn83148 * check for a runaway list. since requests are 3642072Svn83148 * synchronous (clients send a request and need to 3652072Svn83148 * wait for the result before returning) the size 3662072Svn83148 * of the list cannot be much more than the number 3672072Svn83148 * of clients. 3682072Svn83148 */ 3692072Svn83148 ASSERT(pollbase.list_len < pollbase.nclients + 1); 3702072Svn83148 3712072Svn83148 newlen = pollbase.list_len + 5; 3722072Svn83148 newlist = lhp->allocp(newlen * 3734358Srb144127 sizeof (struct listdata_s)); 3742072Svn83148 3752072Svn83148 for (i = 0; i < pollbase.list_len; i++) 3762072Svn83148 newlist[i] = pollbase.list[i]; 3772072Svn83148 3782072Svn83148 oldlist = pollbase.list; 3792072Svn83148 pollbase.list = newlist; 3802072Svn83148 lhp->freep(oldlist, pollbase.list_len * 3814358Srb144127 sizeof (struct listdata_s)); 3822072Svn83148 3832072Svn83148 for (i = pollbase.list_len; i < newlen; i++) { 3842072Svn83148 pollbase.list[i] = 3852072Svn83148 lhp->allocp(sizeof (struct listdata_s)); 3862072Svn83148 pollbase.list[i]->status = UNUSED; 3872072Svn83148 } 3882072Svn83148 3892072Svn83148 pollbase.list_len = newlen; 3902072Svn83148 } 3912072Svn83148 } 3922072Svn83148 3932072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 3942072Svn83148 ASSERT(index != -1); 3952072Svn83148 3962072Svn83148 return (index); 3972072Svn83148 } 3982072Svn83148 3992072Svn83148 4002072Svn83148 static void 4012072Svn83148 poller_delete_pending(uint64_t req_num, int index) 4022072Svn83148 { 4032072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 4042072Svn83148 4052072Svn83148 ASSERT(pollbase.list[index]->req_num == req_num); 4062072Svn83148 pollbase.list[index]->status = UNUSED; 4072072Svn83148 4082072Svn83148 if (--(pollbase.pending_count) == 0 && pollbase.doreset == 1) 4092072Svn83148 (void) pthread_cond_broadcast(&pollbase.cv); 4102072Svn83148 4112072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 4122072Svn83148 } 4132072Svn83148 4142072Svn83148 4152072Svn83148 static void 4162072Svn83148 poller_shutdown(void) 4172072Svn83148 { 4182072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 4192072Svn83148 4202072Svn83148 pollbase.doexit = 1; 4212072Svn83148 4222072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 4232072Svn83148 } 4242072Svn83148 4252072Svn83148 4262072Svn83148 /* 4272072Svn83148 * perform the polling of incoming messages. manage any resets (usually 4282072Svn83148 * due to one end of the connection being closed) as well as exit 4292072Svn83148 * conditions. 4302072Svn83148 */ 4312072Svn83148 static void * 4322072Svn83148 poller_loop(void *arg) 4332072Svn83148 { 4342072Svn83148 struct ldmsvcs_info *lsp; 4352072Svn83148 pollfd_t pollfd; 4362072Svn83148 int ier; 4372072Svn83148 4382072Svn83148 lsp = (struct ldmsvcs_info *)arg; 4392072Svn83148 4402072Svn83148 for (;;) { 4412072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 4422072Svn83148 4432072Svn83148 if (pollbase.doexit) { 4442072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 4452072Svn83148 break; 4462072Svn83148 } 4472072Svn83148 4482072Svn83148 if (pollbase.doreset) { 4492072Svn83148 int i; 4502072Svn83148 4512072Svn83148 while (pollbase.pending_count > 0) 4522072Svn83148 (void) pthread_cond_wait(&pollbase.cv, 4534358Srb144127 &pollbase.mt); 4542072Svn83148 4552072Svn83148 ASSERT(pollbase.pending_count == 0); 4562072Svn83148 for (i = 0; i < pollbase.list_len; i++) 4572072Svn83148 pollbase.list[i]->status = UNUSED; 4582072Svn83148 4592072Svn83148 pollbase.doreset = 0; 4602072Svn83148 } 4612072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 4622072Svn83148 4632072Svn83148 if ((ier = channel_openreset(lsp)) == 1) { 4642072Svn83148 continue; 4652072Svn83148 } else if (ier == 2) { 4662072Svn83148 /* 4672072Svn83148 * start exit preparations 4682072Svn83148 */ 4692072Svn83148 poller_shutdown(); 4702072Svn83148 continue; 4712072Svn83148 } 4722072Svn83148 4732072Svn83148 pollfd.events = POLLIN; 4742072Svn83148 pollfd.revents = 0; 4752072Svn83148 pollfd.fd = lsp->fds_chan.fd; 4762072Svn83148 4772072Svn83148 if (poll(&pollfd, 1, -1) <= 0 || read_msg(lsp) != 0) { 4782072Svn83148 /* 4792072Svn83148 * read error and/or fd got closed 4802072Svn83148 */ 4812072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 4822072Svn83148 pollbase.doreset = 1; 4832072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 4842072Svn83148 4852072Svn83148 channel_close(lsp); 4862072Svn83148 } 4872072Svn83148 } 4882072Svn83148 4892072Svn83148 return (NULL); 4902072Svn83148 } 4912072Svn83148 4922072Svn83148 4932072Svn83148 /* 4942072Svn83148 * create the polling thread 4952072Svn83148 */ 4962072Svn83148 static int 4972072Svn83148 poller_init(struct ldmsvcs_info *lsp) 4982072Svn83148 { 4992072Svn83148 int rc = 0; 5002072Svn83148 5012072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 5022072Svn83148 5032072Svn83148 if (pollbase.polling_tid == 0) { 5042072Svn83148 pthread_attr_t attr; 5052072Svn83148 5062072Svn83148 /* 5072072Svn83148 * create polling thread for receiving messages 5082072Svn83148 */ 5092072Svn83148 (void) pthread_attr_init(&attr); 5102072Svn83148 (void) pthread_attr_setdetachstate(&attr, 5114358Srb144127 PTHREAD_CREATE_DETACHED); 5122072Svn83148 5132072Svn83148 if (pthread_create(&pollbase.polling_tid, &attr, 5144358Srb144127 poller_loop, lsp) != 0) 5152072Svn83148 rc = 1; 5162072Svn83148 5172072Svn83148 (void) pthread_attr_destroy(&attr); 5182072Svn83148 } 5192072Svn83148 5202072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 5212072Svn83148 5222072Svn83148 return (rc); 5232072Svn83148 } 5242072Svn83148 5252072Svn83148 5262072Svn83148 /* 5272072Svn83148 * utilities for message handlers 5282072Svn83148 */ 5292072Svn83148 static int 5302072Svn83148 fds_send(struct ldmsvcs_info *lsp, void *msg, size_t msglen) 5312072Svn83148 { 5322072Svn83148 static pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER; 5332072Svn83148 5342072Svn83148 (void) pthread_mutex_lock(&mt); 5352072Svn83148 5362072Svn83148 if (write(lsp->fds_chan.fd, msg, msglen) != msglen) { 5372072Svn83148 channel_close(lsp); 5382072Svn83148 (void) pthread_mutex_unlock(&mt); 5392072Svn83148 return (ETIMEDOUT); 5402072Svn83148 } 5412072Svn83148 5422072Svn83148 (void) pthread_mutex_unlock(&mt); 5432072Svn83148 return (0); 5442072Svn83148 } 5452072Svn83148 5462072Svn83148 5472072Svn83148 /* 5482072Svn83148 * Find the max and min version supported 5492072Svn83148 */ 5502072Svn83148 static void 5512072Svn83148 fds_min_max_versions(uint16_t *min_major, uint16_t *max_major) 5522072Svn83148 { 5532072Svn83148 int i; 5542072Svn83148 5552072Svn83148 *min_major = ds_vers[0].major; 5562072Svn83148 *max_major = *min_major; 5572072Svn83148 5582072Svn83148 for (i = 1; i < DS_NUM_VER; i++) { 5592072Svn83148 if (ds_vers[i].major < *min_major) 5602072Svn83148 *min_major = ds_vers[i].major; 5612072Svn83148 5622072Svn83148 if (ds_vers[i].major > *max_major) 5632072Svn83148 *max_major = ds_vers[i].major; 5642072Svn83148 } 5652072Svn83148 } 5662072Svn83148 5672072Svn83148 /* 5682072Svn83148 * check whether the major and minor numbers requested by remote ds client 5692072Svn83148 * can be satisfied. if the requested major is supported, true is 5702072Svn83148 * returned, and the agreed minor is returned in new_minor. if the 5712072Svn83148 * requested major is not supported, the routine returns false, and the 5722072Svn83148 * closest major is returned in *new_major, upon which the ds client should 5732072Svn83148 * renegotiate. the closest major is the just lower that the requested 5742072Svn83148 * major number. 5752072Svn83148 */ 5762072Svn83148 static boolean_t 5772072Svn83148 fds_negotiate_version(uint16_t req_major, uint16_t *new_majorp, 5782072Svn83148 uint16_t *new_minorp) 5792072Svn83148 { 5802072Svn83148 int i = 0; 5812072Svn83148 uint16_t major, lower_major; 5822072Svn83148 uint16_t min_major, max_major; 5832072Svn83148 boolean_t found_match = B_FALSE; 5842072Svn83148 5852072Svn83148 fds_min_max_versions(&min_major, &max_major); 5862072Svn83148 5872072Svn83148 /* 5882072Svn83148 * if the minimum version supported is greater than the version 5892072Svn83148 * requested, return the lowest version supported 5902072Svn83148 */ 5912072Svn83148 if (min_major > req_major) { 5922072Svn83148 *new_majorp = min_major; 5932072Svn83148 return (B_FALSE); 5942072Svn83148 } 5952072Svn83148 5962072Svn83148 /* 5972072Svn83148 * if the largest version supported is lower than the version 5982072Svn83148 * requested, return the largest version supported 5992072Svn83148 */ 6002072Svn83148 if (max_major < req_major) { 6012072Svn83148 *new_majorp = max_major; 6022072Svn83148 return (B_FALSE); 6032072Svn83148 } 6042072Svn83148 6052072Svn83148 /* 6062072Svn83148 * now we know that the requested version lies between the min and 6072072Svn83148 * max versions supported. check if the requested major can be 6082072Svn83148 * found in supported versions. 6092072Svn83148 */ 6102072Svn83148 lower_major = min_major; 6112072Svn83148 for (i = 0; i < DS_NUM_VER; i++) { 6122072Svn83148 major = ds_vers[i].major; 6132072Svn83148 if (major == req_major) { 6142072Svn83148 found_match = B_TRUE; 6152072Svn83148 *new_minorp = ds_vers[i].minor; 6162072Svn83148 *new_majorp = major; 6172072Svn83148 break; 6182072Svn83148 } else if ((major < req_major) && (major > lower_major)) 6192072Svn83148 lower_major = major; 6202072Svn83148 } 6212072Svn83148 6222072Svn83148 /* 6232072Svn83148 * If no match is found, return the closest available number 6242072Svn83148 */ 6252072Svn83148 if (!found_match) 6262072Svn83148 *new_majorp = lower_major; 6272072Svn83148 6282072Svn83148 return (found_match); 6292072Svn83148 } 6302072Svn83148 6312072Svn83148 6322072Svn83148 /* 6332072Svn83148 * return 0 if service is added; 1 if service is a duplicate 6342072Svn83148 */ 6352072Svn83148 static int 6362072Svn83148 fds_svc_add(struct ldmsvcs_info *lsp, ds_reg_req_t *req, int minor) 6372072Svn83148 { 6382072Svn83148 fds_svc_t *svc; 6392072Svn83148 int i, rc; 6402072Svn83148 6412072Svn83148 svc = NULL; 6422072Svn83148 for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) { 6432072Svn83148 if (strcmp(lsp->fmas_svcs.tbl[i]->name, req->svc_id) == 0) { 6442072Svn83148 svc = lsp->fmas_svcs.tbl[i]; 6452072Svn83148 break; 6462072Svn83148 } 6472072Svn83148 } 6482072Svn83148 6492072Svn83148 if (svc == NULL) 6502072Svn83148 return (0); /* we don't need this service */ 6512072Svn83148 6522072Svn83148 (void) pthread_mutex_lock(&lsp->fmas_svcs.mt); 6532072Svn83148 6542072Svn83148 /* 6552072Svn83148 * duplicate registration is OK --- we retain the previous entry 6562072Svn83148 * (which has not been unregistered anyway) 6572072Svn83148 */ 6582072Svn83148 if (svc->state == DS_SVC_ACTIVE) { 6592072Svn83148 rc = 1; 6602072Svn83148 } else { 6612072Svn83148 svc->state = DS_SVC_ACTIVE; 6622072Svn83148 svc->hdl = req->svc_handle; 6632072Svn83148 svc->ver.major = req->major_vers; 6642072Svn83148 svc->ver.minor = minor; 6652072Svn83148 6662072Svn83148 rc = 0; 6672072Svn83148 (void) pthread_cond_broadcast(&lsp->fmas_svcs.cv); 6682072Svn83148 } 6692072Svn83148 6702072Svn83148 (void) pthread_mutex_unlock(&lsp->fmas_svcs.mt); 6712072Svn83148 6722072Svn83148 return (rc); 6732072Svn83148 } 6742072Svn83148 6752072Svn83148 6762072Svn83148 static void 6772072Svn83148 fds_svc_reset(struct ldmsvcs_info *lsp, int index) 6782072Svn83148 { 6792072Svn83148 int i, start, end; 6802072Svn83148 6812072Svn83148 if (index >= 0) { 6822072Svn83148 start = index; 6832072Svn83148 end = index + 1; 6842072Svn83148 } else { 6852072Svn83148 start = 0; 6862072Svn83148 end = lsp->fmas_svcs.nsvcs; 6872072Svn83148 } 6882072Svn83148 6892072Svn83148 (void) pthread_mutex_lock(&lsp->fmas_svcs.mt); 6902072Svn83148 6912072Svn83148 for (i = start; i < end; i++) { 6922072Svn83148 lsp->fmas_svcs.tbl[i]->hdl = 0; 6932072Svn83148 lsp->fmas_svcs.tbl[i]->state = DS_SVC_INVAL; 6942072Svn83148 lsp->fmas_svcs.tbl[i]->ver.major = 6954358Srb144127 ds_vers[DS_NUM_VER - 1].major; 6962072Svn83148 lsp->fmas_svcs.tbl[i]->ver.minor = 6974358Srb144127 ds_vers[DS_NUM_VER - 1].minor; 6982072Svn83148 } 6992072Svn83148 7002072Svn83148 (void) pthread_mutex_unlock(&lsp->fmas_svcs.mt); 7012072Svn83148 } 7022072Svn83148 7032072Svn83148 7042072Svn83148 static int 7052072Svn83148 fds_svc_remove(struct ldmsvcs_info *lsp, ds_svc_hdl_t svc_handle) 7062072Svn83148 { 7072072Svn83148 int i; 7082072Svn83148 7092072Svn83148 for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) { 7102072Svn83148 if (lsp->fmas_svcs.tbl[i]->hdl == svc_handle) { 7112072Svn83148 fds_svc_reset(lsp, i); 7122072Svn83148 return (0); 7132072Svn83148 } 7142072Svn83148 } 7152072Svn83148 7162072Svn83148 return (1); 7172072Svn83148 } 7182072Svn83148 7192072Svn83148 7202072Svn83148 /* 7212072Svn83148 * message handlers 7222072Svn83148 */ 7232072Svn83148 /*ARGSUSED*/ 7242072Svn83148 static void 7252072Svn83148 ds_handle_msg_noop(struct ldmsvcs_info *lsp, void *buf, size_t len) 7262072Svn83148 { 7272072Svn83148 } 7282072Svn83148 7292072Svn83148 static void 7302072Svn83148 ds_handle_init_req(struct ldmsvcs_info *lsp, void *buf, size_t len) 7312072Svn83148 { 7322072Svn83148 ds_init_req_t *req; 7332072Svn83148 uint16_t new_major, new_minor; 7342072Svn83148 size_t msglen; 7352072Svn83148 7362072Svn83148 req = (ds_init_req_t *)buf; 7372072Svn83148 7382072Svn83148 /* sanity check the incoming message */ 7392072Svn83148 if (len != sizeof (ds_init_req_t)) { 7402072Svn83148 channel_close(lsp); 7412072Svn83148 return; 7422072Svn83148 } 7432072Svn83148 7442072Svn83148 /* 7452072Svn83148 * Check version info. ACK only if the major numbers exactly 7462072Svn83148 * match. The service entity can retry with a new minor 7472072Svn83148 * based on the response sent as part of the NACK. 7482072Svn83148 */ 7492072Svn83148 if (fds_negotiate_version(req->major_vers, &new_major, &new_minor)) { 7502072Svn83148 ds_hdr_t *H; 7512072Svn83148 ds_init_ack_t *R; 7522072Svn83148 7532072Svn83148 msglen = sizeof (ds_hdr_t) + sizeof (ds_init_ack_t); 7542072Svn83148 H = alloca(msglen); 7552072Svn83148 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 7562072Svn83148 7572072Svn83148 H->msg_type = DS_INIT_ACK; 7582072Svn83148 H->payload_len = sizeof (ds_init_ack_t); 7592072Svn83148 R->minor_vers = MIN(new_minor, req->minor_vers); 7602072Svn83148 7612072Svn83148 if (fds_send(lsp, H, msglen) != 0) 7622072Svn83148 return; 7632072Svn83148 7642072Svn83148 (void) pthread_mutex_lock(&lsp->mt); 7652072Svn83148 ASSERT(lsp->fds_chan.state == CHANNEL_OPEN); 7662072Svn83148 lsp->fds_chan.state = CHANNEL_READY; 7673327Svn83148 7683327Svn83148 /* 7693327Svn83148 * Now the channel is ready after the handshake completes. 7703327Svn83148 * Reset the timeout to a smaller value for receiving messages 7713327Svn83148 * from the domain services. 7723327Svn83148 */ 7734358Srb144127 lsp->cv_twait = get_smf_int_val(LDM_RUNNING_TO_PROP_NM, 7744358Srb144127 0, LDM_TIMEOUT_CEILING, LDM_RUNNING_WAIT_TIME); 7753327Svn83148 7762072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 7772072Svn83148 } else { 7782072Svn83148 ds_hdr_t *H; 7792072Svn83148 ds_init_nack_t *R; 7802072Svn83148 7812072Svn83148 msglen = sizeof (ds_hdr_t) + sizeof (ds_init_nack_t); 7822072Svn83148 H = alloca(msglen); 7832072Svn83148 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 7842072Svn83148 7852072Svn83148 H->msg_type = DS_INIT_NACK; 7862072Svn83148 H->payload_len = sizeof (ds_init_nack_t); 7872072Svn83148 R->major_vers = new_major; 7882072Svn83148 7892072Svn83148 (void) fds_send(lsp, H, msglen); 7902072Svn83148 /* 7912072Svn83148 * do not update state; remote end may attempt to initiate 7922072Svn83148 * connection with a different version 7932072Svn83148 */ 7942072Svn83148 } 7952072Svn83148 } 7962072Svn83148 7972072Svn83148 7982072Svn83148 /*ARGSUSED*/ 7992072Svn83148 static void 8002072Svn83148 ds_handle_reg_req(struct ldmsvcs_info *lsp, void *buf, size_t len) 8012072Svn83148 { 8022072Svn83148 ds_reg_req_t *req; 8032072Svn83148 char *msg; 8042072Svn83148 uint16_t new_major, new_minor; 8052072Svn83148 size_t msglen; 8062072Svn83148 int dup_svcreg = 0; 8072072Svn83148 8082072Svn83148 req = (ds_reg_req_t *)buf; 8092072Svn83148 msg = (char *)req->svc_id; 8102072Svn83148 8112072Svn83148 /* 8122072Svn83148 * Service must be NULL terminated 8132072Svn83148 */ 8142072Svn83148 if (req->svc_id == NULL || strlen(req->svc_id) == 0 || 8152072Svn83148 msg[strlen(req->svc_id)] != '\0') { 8162072Svn83148 channel_close(lsp); 8172072Svn83148 return; 8182072Svn83148 } 8192072Svn83148 8202072Svn83148 if (fds_negotiate_version(req->major_vers, &new_major, &new_minor) && 8212072Svn83148 (dup_svcreg = fds_svc_add(lsp, req, 8224358Srb144127 MIN(new_minor, req->minor_vers))) == 0) { 8232072Svn83148 8242072Svn83148 /* 8252072Svn83148 * Check version info. ACK only if the major numbers 8262072Svn83148 * exactly match. The service entity can retry with a new 8272072Svn83148 * minor based on the response sent as part of the NACK. 8282072Svn83148 */ 8292072Svn83148 ds_hdr_t *H; 8302072Svn83148 ds_reg_ack_t *R; 8312072Svn83148 8322072Svn83148 msglen = sizeof (ds_hdr_t) + sizeof (ds_reg_ack_t); 8332072Svn83148 H = alloca(msglen); 8342072Svn83148 bzero(H, msglen); 8352072Svn83148 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 8362072Svn83148 8372072Svn83148 H->msg_type = DS_REG_ACK; 8382072Svn83148 H->payload_len = sizeof (ds_reg_ack_t); 8392072Svn83148 R->svc_handle = req->svc_handle; 8402072Svn83148 R->minor_vers = MIN(new_minor, req->minor_vers); 8412072Svn83148 8422072Svn83148 (void) fds_send(lsp, H, msglen); 8432072Svn83148 } else { 8442072Svn83148 ds_hdr_t *H; 8452072Svn83148 ds_reg_nack_t *R; 8462072Svn83148 8472072Svn83148 msglen = sizeof (ds_hdr_t) + sizeof (ds_reg_nack_t); 8482072Svn83148 H = alloca(msglen); 8492072Svn83148 bzero(H, msglen); 8502072Svn83148 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 8512072Svn83148 8522072Svn83148 H->msg_type = DS_REG_NACK; 8532072Svn83148 H->payload_len = sizeof (ds_reg_nack_t); 8542072Svn83148 R->svc_handle = req->svc_handle; 8552072Svn83148 R->major_vers = new_major; 8562072Svn83148 8572072Svn83148 if (dup_svcreg) 8582072Svn83148 R->result = DS_REG_DUP; 8592072Svn83148 else 8602072Svn83148 R->result = DS_REG_VER_NACK; 8612072Svn83148 8622072Svn83148 (void) fds_send(lsp, H, msglen); 8632072Svn83148 } 8642072Svn83148 } 8652072Svn83148 8662072Svn83148 8672072Svn83148 /*ARGSUSED*/ 8682072Svn83148 static void 8692072Svn83148 ds_handle_unreg(struct ldmsvcs_info *lsp, void *buf, size_t len) 8702072Svn83148 { 8712072Svn83148 ds_unreg_req_t *req; 8722072Svn83148 size_t msglen; 8732072Svn83148 8742072Svn83148 req = (ds_unreg_req_t *)buf; 8752072Svn83148 8762072Svn83148 if (fds_svc_remove(lsp, req->svc_handle) == 0) { 8772072Svn83148 ds_hdr_t *H; 8782072Svn83148 ds_unreg_ack_t *R; 8792072Svn83148 8802072Svn83148 msglen = sizeof (ds_hdr_t) + sizeof (ds_unreg_ack_t); 8812072Svn83148 H = alloca(msglen); 8822072Svn83148 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 8832072Svn83148 8842072Svn83148 H->msg_type = DS_REG_ACK; 8852072Svn83148 H->payload_len = sizeof (ds_unreg_ack_t); 8862072Svn83148 R->svc_handle = req->svc_handle; 8872072Svn83148 8882072Svn83148 (void) fds_send(lsp, H, msglen); 8892072Svn83148 } else { 8902072Svn83148 ds_hdr_t *H; 8912072Svn83148 ds_unreg_nack_t *R; 8922072Svn83148 8932072Svn83148 msglen = sizeof (ds_hdr_t) + sizeof (ds_unreg_nack_t); 8942072Svn83148 H = alloca(msglen); 8952072Svn83148 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 8962072Svn83148 8972072Svn83148 H->msg_type = DS_REG_NACK; 8982072Svn83148 H->payload_len = sizeof (ds_unreg_nack_t); 8992072Svn83148 R->svc_handle = req->svc_handle; 9002072Svn83148 9012072Svn83148 (void) fds_send(lsp, H, msglen); 9022072Svn83148 } 9032072Svn83148 } 9042072Svn83148 9052072Svn83148 9062072Svn83148 /* 9072072Svn83148 * Message handler lookup table (v1.0 only for now) Future 9082072Svn83148 * versions can add their own lookup table. 9092072Svn83148 */ 9102072Svn83148 typedef void (*ds_msg_handler_t)(struct ldmsvcs_info *lsp, 9112072Svn83148 void *buf, size_t len); 9122072Svn83148 9132072Svn83148 static const ds_msg_handler_t ds_msg_handlers[] = { 9142072Svn83148 ds_handle_init_req, /* DS_INIT_REQ */ 9152072Svn83148 ds_handle_msg_noop, /* DS_INIT_ACK */ 9162072Svn83148 ds_handle_msg_noop, /* DS_INIT_NACK */ 9172072Svn83148 ds_handle_reg_req, /* DS_REG_REQ */ 9182072Svn83148 ds_handle_msg_noop, /* DS_REG_ACK */ 9192072Svn83148 ds_handle_msg_noop, /* DS_REG_NACK */ 9202072Svn83148 ds_handle_unreg, /* DS_UNREG */ 9212072Svn83148 ds_handle_msg_noop, /* DS_UNREG_ACK */ 9222072Svn83148 ds_handle_msg_noop, /* DS_UNREG_NACK */ 9232072Svn83148 ds_handle_msg_noop, /* DS_DATA */ 9242072Svn83148 ds_handle_msg_noop /* DS_NACK */ 9252072Svn83148 }; 9262072Svn83148 9272072Svn83148 9282072Svn83148 /* 9292072Svn83148 * message and service internal functions 9302072Svn83148 */ 9312072Svn83148 static void 9322072Svn83148 fds_svc_alloc(struct ldom_hdl *lhp, struct ldmsvcs_info *lsp) 9332072Svn83148 { 9342072Svn83148 int i; 9352072Svn83148 char *name[] = { "fma-phys-cpu-service", "fma-phys-mem-service", 9362072Svn83148 "fma-pri-service", NULL }; 9372072Svn83148 9382072Svn83148 (void) pthread_mutex_init(&lsp->fmas_svcs.mt, NULL); 9392072Svn83148 (void) pthread_cond_init(&lsp->fmas_svcs.cv, NULL); 9402072Svn83148 9412072Svn83148 for (lsp->fmas_svcs.nsvcs = 0; name[lsp->fmas_svcs.nsvcs] != NULL; 9422072Svn83148 lsp->fmas_svcs.nsvcs++) 9432072Svn83148 ; 9442072Svn83148 9452072Svn83148 lsp->fmas_svcs.tbl = (fds_svc_t **)lhp->allocp(sizeof (fds_svc_t *) * 9464358Srb144127 lsp->fmas_svcs.nsvcs); 9472072Svn83148 9482072Svn83148 for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) { 9492072Svn83148 lsp->fmas_svcs.tbl[i] = 9504358Srb144127 (fds_svc_t *)lhp->allocp(sizeof (fds_svc_t)); 9512072Svn83148 bzero(lsp->fmas_svcs.tbl[i], sizeof (fds_svc_t)); 9522072Svn83148 lsp->fmas_svcs.tbl[i]->name = name[i]; 9532072Svn83148 } 9542072Svn83148 } 9552072Svn83148 9562072Svn83148 9572072Svn83148 static fds_svc_t * 9582072Svn83148 fds_svc_lookup(struct ldmsvcs_info *lsp, char *name) 9592072Svn83148 { 9602072Svn83148 struct timespec twait; 9612072Svn83148 fds_svc_t *svc; 9622072Svn83148 int i, ier; 9632072Svn83148 9642072Svn83148 if (pthread_mutex_lock(&lsp->fmas_svcs.mt) == EINVAL) 9652072Svn83148 return (NULL); /* uninitialized or destroyed mutex */ 9662072Svn83148 9672072Svn83148 svc = NULL; 9682072Svn83148 for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) { 9692072Svn83148 if (strcmp(lsp->fmas_svcs.tbl[i]->name, name) == 0) { 9702072Svn83148 svc = lsp->fmas_svcs.tbl[i]; 9712072Svn83148 break; 9722072Svn83148 } 9732072Svn83148 } 9742072Svn83148 9752072Svn83148 ASSERT(svc != NULL); 9762072Svn83148 9772072Svn83148 ier = 0; 9782072Svn83148 twait.tv_sec = time(NULL) + lsp->cv_twait; 9792072Svn83148 twait.tv_nsec = 0; 9802072Svn83148 9812072Svn83148 while (svc->state != DS_SVC_ACTIVE && ier == 0 && 9822072Svn83148 lsp->fds_chan.state != CHANNEL_UNUSABLE) 9832072Svn83148 ier = pthread_cond_timedwait(&lsp->fmas_svcs.cv, 9844358Srb144127 &lsp->fmas_svcs.mt, &twait); 9852072Svn83148 9862072Svn83148 (void) pthread_mutex_unlock(&lsp->fmas_svcs.mt); 9872072Svn83148 9882072Svn83148 if (ier == 0) 9892072Svn83148 return (svc); 9902072Svn83148 else 9912072Svn83148 return (NULL); 9922072Svn83148 } 9932072Svn83148 9942072Svn83148 9952072Svn83148 static uint64_t 9962072Svn83148 fds_svc_req_num(void) 9972072Svn83148 { 9982072Svn83148 static uint64_t req_num = 1; 9992072Svn83148 10002072Svn83148 return (req_num++); 10012072Svn83148 } 10022072Svn83148 10032072Svn83148 10042072Svn83148 /* 10052072Svn83148 * return 0 if successful, 1 if otherwise 10062072Svn83148 */ 10072072Svn83148 static int 10082072Svn83148 read_msg(struct ldmsvcs_info *lsp) 10092072Svn83148 { 10102072Svn83148 ds_hdr_t header; 10112072Svn83148 void *msg_buf; 10122072Svn83148 10132072Svn83148 /* 10142072Svn83148 * read the header 10152072Svn83148 */ 10162072Svn83148 if (read_stream(lsp->fds_chan.fd, &header, sizeof (ds_hdr_t)) != 0) 10172072Svn83148 return (1); 10182072Svn83148 10192072Svn83148 if (header.msg_type >= 10202072Svn83148 sizeof (ds_msg_handlers) / sizeof (ds_msg_handler_t)) 10214358Srb144127 return (1); 10222072Svn83148 10232072Svn83148 /* 10242072Svn83148 * handle data as a special case 10252072Svn83148 */ 10262072Svn83148 if (header.msg_type == 9) 10272072Svn83148 return (poller_handle_data(lsp->fds_chan.fd, 10284358Srb144127 header.payload_len)); 10292072Svn83148 10302072Svn83148 /* 10312072Svn83148 * all other types of messages should be small 10322072Svn83148 */ 10332072Svn83148 ASSERT(header.payload_len < 1024); 10342072Svn83148 msg_buf = alloca(header.payload_len); 10352072Svn83148 10362072Svn83148 /* 10372072Svn83148 * read the payload 10382072Svn83148 */ 10392072Svn83148 if (read_stream(lsp->fds_chan.fd, msg_buf, header.payload_len) != 0) 10402072Svn83148 return (1); 10412072Svn83148 10422072Svn83148 (*ds_msg_handlers[header.msg_type])(lsp, msg_buf, header.payload_len); 10432072Svn83148 10442072Svn83148 return (0); 10452072Svn83148 } 10462072Svn83148 10472072Svn83148 10482072Svn83148 /* 10492072Svn83148 * return values: 10502072Svn83148 * 0 - success 10512072Svn83148 * 1 - problem with opening the channel 10522072Svn83148 * 2 - channed not opened; request to exit has been detected 10532072Svn83148 */ 10542072Svn83148 static int 10552072Svn83148 channel_openreset(struct ldmsvcs_info *lsp) 10562072Svn83148 { 10572072Svn83148 int ier; 10582072Svn83148 10592072Svn83148 ier = pthread_mutex_lock(&lsp->mt); 10602072Svn83148 10612072Svn83148 if (ier == EINVAL || lsp->fds_chan.state == CHANNEL_EXIT || 10622072Svn83148 lsp->fds_chan.state == CHANNEL_UNUSABLE) { 10632072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 10642072Svn83148 return (2); 10652072Svn83148 } 10662072Svn83148 10672072Svn83148 if (lsp->fds_chan.state == CHANNEL_UNINITIALIZED || 10682072Svn83148 lsp->fds_chan.state == CHANNEL_CLOSED) { 10692072Svn83148 (void) pthread_cond_broadcast(&lsp->cv); 10702072Svn83148 10712072Svn83148 if ((lsp->fds_chan.fd = open(FDS_VLDC, O_RDWR)) < 0) { 10722072Svn83148 lsp->fds_chan.state = CHANNEL_UNUSABLE; 10734358Srb144127 lsp->cv_twait = get_smf_int_val(LDM_RUNNING_TO_PROP_NM, 10744358Srb144127 0, LDM_TIMEOUT_CEILING, LDM_RUNNING_WAIT_TIME); 10752072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 10762072Svn83148 (void) pthread_cond_broadcast(&lsp->fmas_svcs.cv); 10772072Svn83148 10782072Svn83148 return (2); 10792072Svn83148 } else { 10802072Svn83148 vldc_opt_op_t op; 10812072Svn83148 10822072Svn83148 op.op_sel = VLDC_OP_SET; 10832072Svn83148 op.opt_sel = VLDC_OPT_MODE; 1084*6408Sha137994 op.opt_val = LDC_MODE_RELIABLE; 10852072Svn83148 10862072Svn83148 if (ioctl(lsp->fds_chan.fd, VLDC_IOCTL_OPT_OP, 10874358Srb144127 &op) != 0) { 10882072Svn83148 (void) close(lsp->fds_chan.fd); 10892072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 10902072Svn83148 return (1); 10912072Svn83148 } 10922072Svn83148 } 10932072Svn83148 lsp->fds_chan.state = CHANNEL_OPEN; 10942072Svn83148 } 10952072Svn83148 10962072Svn83148 if (lsp->fds_chan.state == CHANNEL_OPEN) { 10972072Svn83148 /* 10982072Svn83148 * reset various channel parameters 10992072Svn83148 */ 11002072Svn83148 lsp->fds_chan.ver.major = 0; 11012072Svn83148 lsp->fds_chan.ver.minor = 0; 11022072Svn83148 fds_svc_reset(lsp, -1); 11032072Svn83148 } 11042072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 11052072Svn83148 11062072Svn83148 return (0); 11072072Svn83148 } 11082072Svn83148 11092072Svn83148 11102072Svn83148 static void 11112072Svn83148 channel_fini(void) 11122072Svn83148 { 11132072Svn83148 struct ldmsvcs_info *lsp; 11142072Svn83148 11152072Svn83148 /* 11162072Svn83148 * End the poller thread 11172072Svn83148 */ 11182072Svn83148 poller_shutdown(); 11192072Svn83148 11202072Svn83148 if ((lsp = channel_init(NULL)) == NULL) 11212072Svn83148 return; 11222072Svn83148 11232072Svn83148 (void) pthread_mutex_lock(&lsp->mt); 11242072Svn83148 11252072Svn83148 lsp->fds_chan.state = CHANNEL_EXIT; 11262072Svn83148 (void) close(lsp->fds_chan.fd); 11272072Svn83148 11282072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 11292072Svn83148 } 11302072Svn83148 11312072Svn83148 11322072Svn83148 static struct ldmsvcs_info * 11332072Svn83148 channel_init(struct ldom_hdl *lhp) 11342072Svn83148 { 11352072Svn83148 static pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER; 11362072Svn83148 static pthread_cond_t cv = PTHREAD_COND_INITIALIZER; 11372072Svn83148 static struct ldmsvcs_info *root = NULL; 11382072Svn83148 static int busy_init = 0; 11392072Svn83148 11402072Svn83148 struct timespec twait; 11412072Svn83148 int expired; 11422072Svn83148 11432072Svn83148 (void) pthread_mutex_lock(&mt); 11442072Svn83148 11452072Svn83148 while (busy_init == 1) 11462072Svn83148 (void) pthread_cond_wait(&cv, &mt); 11472072Svn83148 11482072Svn83148 if (root != NULL || (lhp == NULL && root == NULL)) { 11492072Svn83148 (void) pthread_mutex_unlock(&mt); 11502072Svn83148 return (root); 11512072Svn83148 } 11522072Svn83148 11532072Svn83148 /* 11542072Svn83148 * get to this point if we need to open the channel 11552072Svn83148 */ 11562072Svn83148 busy_init = 1; 11572072Svn83148 (void) pthread_mutex_unlock(&mt); 11582072Svn83148 11592072Svn83148 root = (struct ldmsvcs_info *) 11604358Srb144127 lhp->allocp(sizeof (struct ldmsvcs_info)); 11612072Svn83148 bzero(root, sizeof (struct ldmsvcs_info)); 11622072Svn83148 11632072Svn83148 root->fds_chan.state = CHANNEL_UNINITIALIZED; 11644358Srb144127 root->cv_twait = get_smf_int_val(LDM_INIT_TO_PROP_NM, 11654358Srb144127 0, LDM_TIMEOUT_CEILING, LDM_INIT_WAIT_TIME); 11662072Svn83148 11672072Svn83148 if (pthread_mutex_init(&root->mt, NULL) != 0 || 11682072Svn83148 pthread_cond_init(&root->cv, NULL) != 0) { 11692072Svn83148 lhp->freep(root, sizeof (struct ldmsvcs_info)); 11702072Svn83148 return (NULL); 11712072Svn83148 } 11722072Svn83148 11732072Svn83148 fds_svc_alloc(lhp, root); 11742072Svn83148 fds_svc_reset(root, -1); 11752072Svn83148 11762072Svn83148 (void) poller_init(root); 11772072Svn83148 11782072Svn83148 expired = 0; 11792072Svn83148 twait.tv_sec = time(NULL) + 10; 11802072Svn83148 twait.tv_nsec = 0; 11812072Svn83148 11822072Svn83148 (void) pthread_mutex_lock(&root->mt); 11832072Svn83148 11842072Svn83148 /* 11852072Svn83148 * wait for channel to become uninitialized. this should be quick. 11862072Svn83148 */ 11872072Svn83148 while (root->fds_chan.state == CHANNEL_UNINITIALIZED && expired == 0) 11882072Svn83148 expired = pthread_cond_timedwait(&root->cv, &root->mt, &twait); 11892072Svn83148 11902072Svn83148 if (root->fds_chan.state == CHANNEL_UNUSABLE) 11912072Svn83148 expired = 1; 11922072Svn83148 11932072Svn83148 (void) pthread_mutex_unlock(&root->mt); 11942072Svn83148 11952072Svn83148 (void) pthread_mutex_lock(&mt); 11962072Svn83148 busy_init = 0; 11972072Svn83148 (void) pthread_mutex_unlock(&mt); 11982072Svn83148 (void) pthread_cond_broadcast(&cv); 11992072Svn83148 12002072Svn83148 (void) atexit(channel_fini); 12012072Svn83148 12022072Svn83148 if (expired == 0) 12032072Svn83148 return (root); 12042072Svn83148 else 12052072Svn83148 return (NULL); 12062072Svn83148 } 12072072Svn83148 12082072Svn83148 12092072Svn83148 static int 12102072Svn83148 sendrecv(struct ldom_hdl *lhp, uint64_t req_num, 12112072Svn83148 void *msg, size_t msglen, ds_svc_hdl_t *svc_hdl, char *svcname, 12122072Svn83148 void **resp, size_t *resplen) 12132072Svn83148 { 12142072Svn83148 struct ldmsvcs_info *lsp; 12152072Svn83148 fds_svc_t *svc; 12162072Svn83148 int maxretries, index, i, ier; 12172072Svn83148 12182072Svn83148 lsp = lhp->lsinfo; 12192072Svn83148 i = 0; 12202072Svn83148 maxretries = 1; 12212072Svn83148 12222072Svn83148 do { 12232072Svn83148 /* 12242072Svn83148 * if any of the calls in this loop fail, retry some number 12252072Svn83148 * of times before giving up. 12262072Svn83148 */ 12272072Svn83148 if ((svc = fds_svc_lookup(lsp, svcname)) == NULL) { 12282072Svn83148 (void) pthread_mutex_lock(&lsp->mt); 12292072Svn83148 12302072Svn83148 if (lsp->fds_chan.state != CHANNEL_READY) 12312072Svn83148 ier = ETIMEDOUT; /* channel not ready */ 12322072Svn83148 else 12332072Svn83148 ier = ENOTSUP; /* service not ready */ 12342072Svn83148 12352072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 12362072Svn83148 12372072Svn83148 continue; 12382072Svn83148 } else { 12392072Svn83148 ier = 0; 12402072Svn83148 *svc_hdl = svc->hdl; 12412072Svn83148 } 12422072Svn83148 12432072Svn83148 index = poller_add_pending(lhp, req_num); 12442072Svn83148 12452072Svn83148 if ((ier = fds_send(lsp, msg, msglen)) != 0 || 12462072Svn83148 (ier = poller_recv_data(lhp, req_num, index, resp, 12474358Srb144127 resplen)) != 0) 12482072Svn83148 poller_delete_pending(req_num, index); 12492072Svn83148 12502072Svn83148 } while (i++ < maxretries && ier != 0); 12512072Svn83148 12522072Svn83148 ASSERT(ier == 0 || ier == ETIMEDOUT || ier == ENOTSUP); 12532072Svn83148 12542072Svn83148 return (ier); 12552072Svn83148 } 12562072Svn83148 12572072Svn83148 12582072Svn83148 /* 12592072Svn83148 * input: 12602072Svn83148 * msg_type - requested operation: FMA_CPU_REQ_STATUS or FMA_CPU_REQ_OFFLINE 12612072Svn83148 * cpuid - physical cpu id 12622072Svn83148 * 12632072Svn83148 * normal return values: 12642072Svn83148 * P_OFFLINE - cpu is offline 12652072Svn83148 * P_ONLINE - cpu is online 12662072Svn83148 * 12672072Svn83148 * abnormal return values: 12682072Svn83148 * ETIMEDOUT - LDOM manager is not responding 12692072Svn83148 * ENOTSUP - LDOM service for cpu offlining/status is not available 12702072Svn83148 * ENOMSG - got an unexpected response from the LDOM cpu service 12712072Svn83148 */ 12722072Svn83148 static int 12732072Svn83148 cpu_request(struct ldom_hdl *lhp, uint32_t msg_type, uint32_t cpuid) 12742072Svn83148 { 12752072Svn83148 ds_hdr_t *H; 12762072Svn83148 ds_data_handle_t *D; 12772072Svn83148 fma_cpu_service_req_t *R; 12782072Svn83148 12792072Svn83148 char *svcname = "fma-phys-cpu-service"; 12802072Svn83148 fma_cpu_resp_t *respmsg; 12812072Svn83148 void *resp; 12822072Svn83148 size_t resplen, reqmsglen; 12832072Svn83148 int rc; 12842072Svn83148 12852072Svn83148 if (lhp->lsinfo == NULL) 12862072Svn83148 return (ENOMSG); 12872072Svn83148 12882072Svn83148 reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) + 12894358Srb144127 sizeof (fma_cpu_service_req_t); 12902072Svn83148 12912072Svn83148 H = lhp->allocp(reqmsglen); 12922072Svn83148 D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 12932072Svn83148 R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t)); 12942072Svn83148 12952072Svn83148 H->msg_type = DS_DATA; 12962072Svn83148 H->payload_len = sizeof (ds_data_handle_t) + 12974358Srb144127 sizeof (fma_cpu_service_req_t); 12982072Svn83148 12992072Svn83148 R->req_num = fds_svc_req_num(); 13002072Svn83148 R->msg_type = msg_type; 13012072Svn83148 R->cpu_id = cpuid; 13022072Svn83148 13032072Svn83148 if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen, 13044358Srb144127 &D->svc_handle, svcname, &resp, &resplen)) != 0) { 13052072Svn83148 lhp->freep(H, reqmsglen); 13062072Svn83148 return (rc); 13072072Svn83148 } 13082072Svn83148 13092072Svn83148 lhp->freep(H, reqmsglen); 13102072Svn83148 13112072Svn83148 ASSERT(resplen == sizeof (fma_cpu_resp_t)); 13122072Svn83148 respmsg = (fma_cpu_resp_t *)resp; 13132072Svn83148 13142072Svn83148 rc = ENOMSG; 13152072Svn83148 if (respmsg->result == FMA_CPU_RESP_OK) { 13162072Svn83148 if (respmsg->status == FMA_CPU_STAT_ONLINE) 13172072Svn83148 rc = P_ONLINE; 13182072Svn83148 else if (respmsg->status == FMA_CPU_STAT_OFFLINE) 13192072Svn83148 rc = P_OFFLINE; 13202072Svn83148 } else { 13212072Svn83148 if (msg_type == FMA_CPU_REQ_OFFLINE && 13222072Svn83148 respmsg->status == FMA_CPU_STAT_OFFLINE) 13232072Svn83148 rc = P_OFFLINE; 13242072Svn83148 } 13252072Svn83148 13262072Svn83148 lhp->freep(resp, resplen); 13272072Svn83148 13282072Svn83148 return (rc); 13292072Svn83148 } 13302072Svn83148 13312072Svn83148 13322072Svn83148 /* 13332072Svn83148 * input: 13342072Svn83148 * msg_type - requested operation: FMA_MEM_REQ_STATUS or FMA_MEM_REQ_RETIRE 13352072Svn83148 * pa - starting address of memory page 13362072Svn83148 * pgsize - memory page size in bytes 13372072Svn83148 * 13382072Svn83148 * normal return values for msg_type == FMA_MEM_REQ_STATUS: 13392072Svn83148 * 0 - page is retired 13402072Svn83148 * EAGAIN - page is scheduled for retirement 13412072Svn83148 * EIO - page not scheduled for retirement 13422072Svn83148 * EINVAL - error 13432072Svn83148 * 13442072Svn83148 * normal return values for msg_type == FMA_MEM_REQ_RETIRE: 13452072Svn83148 * 0 - success in retiring page 13462072Svn83148 * EIO - page is already retired 13472072Svn83148 * EAGAIN - page is scheduled for retirement 13482072Svn83148 * EINVAL - error 13492072Svn83148 * 13502072Svn83148 * abnormal return values (regardless of msg_type) 13512072Svn83148 * ETIMEDOUT - LDOM manager is not responding 13522072Svn83148 * ENOTSUP - LDOM service for cpu offlining/status is not available 13532072Svn83148 * ENOMSG - got an unexpected response from the LDOM cpu service 13542072Svn83148 */ 13552072Svn83148 static int 13562072Svn83148 mem_request(struct ldom_hdl *lhp, uint32_t msg_type, uint64_t pa, 13572072Svn83148 uint64_t pgsize) 13582072Svn83148 { 13592072Svn83148 ds_hdr_t *H; 13602072Svn83148 ds_data_handle_t *D; 13612072Svn83148 fma_mem_service_req_t *R; 13622072Svn83148 13632072Svn83148 char *svcname = "fma-phys-mem-service"; 13642072Svn83148 fma_mem_resp_t *respmsg; 13652072Svn83148 void *resp; 13662072Svn83148 size_t resplen, reqmsglen; 13672072Svn83148 int rc; 13682072Svn83148 13692072Svn83148 if (lhp->lsinfo == NULL) 13702072Svn83148 return (ENOMSG); 13712072Svn83148 13722072Svn83148 reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) + 13734358Srb144127 sizeof (fma_mem_service_req_t); 13742072Svn83148 13752072Svn83148 H = lhp->allocp(reqmsglen); 13762072Svn83148 bzero(H, reqmsglen); 13772072Svn83148 D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 13782072Svn83148 R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t)); 13792072Svn83148 13802072Svn83148 H->msg_type = DS_DATA; 13812072Svn83148 H->payload_len = sizeof (ds_data_handle_t) + 13824358Srb144127 sizeof (fma_mem_service_req_t); 13832072Svn83148 13842072Svn83148 R->req_num = fds_svc_req_num(); 13852072Svn83148 R->msg_type = msg_type; 13862072Svn83148 R->real_addr = pa; 13872072Svn83148 R->length = pgsize; 13882072Svn83148 13892072Svn83148 if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen, 13904358Srb144127 &D->svc_handle, svcname, &resp, &resplen)) != 0) { 13912072Svn83148 lhp->freep(H, reqmsglen); 13922072Svn83148 return (rc); 13932072Svn83148 } 13942072Svn83148 13952072Svn83148 lhp->freep(H, reqmsglen); 13962072Svn83148 13972072Svn83148 ASSERT(resplen == sizeof (fma_mem_resp_t)); 13982072Svn83148 respmsg = (fma_mem_resp_t *)resp; 13992072Svn83148 14002072Svn83148 rc = ENOMSG; 14012072Svn83148 if (msg_type == FMA_MEM_REQ_STATUS) { 14022072Svn83148 if (respmsg->result == FMA_MEM_RESP_OK) { 14032072Svn83148 if (respmsg->status == FMA_MEM_STAT_RETIRED) 14044655Svn83148 rc = 0; /* page is retired */ 14052072Svn83148 else if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 14064655Svn83148 rc = EIO; /* page is not scheduled */ 14072072Svn83148 } else if (respmsg->result == FMA_MEM_RESP_FAILURE) { 14084655Svn83148 if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 14094655Svn83148 rc = EAGAIN; /* page is scheduled */ 14104655Svn83148 else if (respmsg->status == FMA_MEM_STAT_ILLEGAL) 14112072Svn83148 rc = EINVAL; 14122072Svn83148 } 14132072Svn83148 } else if (msg_type == FMA_MEM_REQ_RETIRE) { 14142072Svn83148 if (respmsg->result == FMA_MEM_RESP_OK) { 14152072Svn83148 if (respmsg->status == FMA_MEM_STAT_RETIRED) 14164655Svn83148 rc = 0; /* is successfully retired */ 14172072Svn83148 } else if (respmsg->result == FMA_MEM_RESP_FAILURE) { 14182072Svn83148 if (respmsg->status == FMA_MEM_STAT_RETIRED) 14194655Svn83148 rc = EIO; /* is already retired */ 14204655Svn83148 else if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 14214655Svn83148 rc = EAGAIN; /* is scheduled to retire */ 14222072Svn83148 else if (respmsg->status == FMA_MEM_STAT_ILLEGAL) 14232072Svn83148 rc = EINVAL; 14242072Svn83148 } 14252072Svn83148 } 14262072Svn83148 14272072Svn83148 lhp->freep(resp, resplen); 14282072Svn83148 14292072Svn83148 return (rc); 14302072Svn83148 } 14312072Svn83148 14322072Svn83148 14332072Svn83148 /* 14342072Svn83148 * APIs 14352072Svn83148 */ 14362072Svn83148 int 14372072Svn83148 ldmsvcs_check_channel(void) 14382072Svn83148 { 14392072Svn83148 struct stat buf; 14402072Svn83148 14412072Svn83148 if (stat(FDS_VLDC, &buf) == 0) 14422072Svn83148 return (0); /* vldc exists */ 14432072Svn83148 else if (errno == ENOENT || errno == ENOTDIR) 14442072Svn83148 return (1); /* vldc does not exist */ 14452072Svn83148 else 14462072Svn83148 return (-1); /* miscellaneous error */ 14472072Svn83148 } 14482072Svn83148 14492072Svn83148 14502072Svn83148 /*ARGSUSED*/ 14512072Svn83148 void 14522072Svn83148 ldmsvcs_init(struct ldom_hdl *lhp) 14532072Svn83148 { 14542072Svn83148 if (ldmsvcs_check_channel() != 0) 14552072Svn83148 return; 14562072Svn83148 14572072Svn83148 lhp->lsinfo = channel_init(lhp); 14582072Svn83148 poller_add_client(); 14592072Svn83148 } 14602072Svn83148 14612072Svn83148 14622072Svn83148 /*ARGSUSED*/ 14632072Svn83148 void 14642072Svn83148 ldmsvcs_fini(struct ldom_hdl *lhp) 14652072Svn83148 { 14662072Svn83148 if (ldmsvcs_check_channel() != 0) 14672072Svn83148 return; 14682072Svn83148 14692072Svn83148 poller_remove_client(); 14702072Svn83148 } 14712072Svn83148 14722072Svn83148 14732072Svn83148 /*ARGSUSED*/ 14742072Svn83148 ssize_t 14752072Svn83148 ldmsvcs_get_core_md(struct ldom_hdl *lhp, uint64_t **buf) 14762072Svn83148 { 14772072Svn83148 ds_hdr_t *H; 14782072Svn83148 ds_data_handle_t *D; 14792072Svn83148 fma_req_pri_t *R; 14802072Svn83148 14812072Svn83148 char *svcname = "fma-pri-service"; 14822072Svn83148 void *resp; 14832072Svn83148 size_t resplen, reqmsglen; 14842072Svn83148 ssize_t buflen; 14852072Svn83148 int rc; 14862072Svn83148 14872072Svn83148 if (lhp->lsinfo == NULL) 14882072Svn83148 return (-1); 14892072Svn83148 14902072Svn83148 reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) + 14914358Srb144127 sizeof (fma_req_pri_t); 14922072Svn83148 14932072Svn83148 H = lhp->allocp(reqmsglen); 14942072Svn83148 D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 14952072Svn83148 R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t)); 14962072Svn83148 14972072Svn83148 H->msg_type = DS_DATA; 14982072Svn83148 H->payload_len = sizeof (ds_data_handle_t) + 14994358Srb144127 sizeof (fma_req_pri_t); 15002072Svn83148 15012072Svn83148 R->req_num = fds_svc_req_num(); 15022072Svn83148 15032072Svn83148 if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen, 15044358Srb144127 &D->svc_handle, svcname, &resp, &resplen)) != 0) { 15052072Svn83148 lhp->freep(H, reqmsglen); 15062072Svn83148 errno = rc; 15072072Svn83148 return (-1); 15082072Svn83148 } 15092072Svn83148 15102072Svn83148 lhp->freep(H, reqmsglen); 15112072Svn83148 15122072Svn83148 /* 15132072Svn83148 * resp should contain the req_num immediately followed by the PRI 15142072Svn83148 * (the latter may or may not be present). unfortunately, the 15152072Svn83148 * current compiler flags cause a warning for the following 15162072Svn83148 * definition 15172072Svn83148 * 15182072Svn83148 * typedef struct { 15192072Svn83148 * uint64_t req_num; 15202072Svn83148 * uint8_t pri[]; 15212072Svn83148 * } fma_pri_resp_t; 15222072Svn83148 * 15232072Svn83148 * so we do not use the struct here. 15242072Svn83148 */ 15252072Svn83148 if (resplen <= sizeof (uint64_t)) { 15262072Svn83148 lhp->freep(resp, resplen); 15272072Svn83148 if (resplen == sizeof (uint64_t)) 15282072Svn83148 return (0); 15292072Svn83148 else 15302072Svn83148 return (-1); 15312072Svn83148 } 15322072Svn83148 15332072Svn83148 buflen = resplen - sizeof (uint64_t); 15342072Svn83148 *buf = lhp->allocp(buflen); 15352072Svn83148 15362072Svn83148 bcopy((void *)((ptrdiff_t)resp + sizeof (uint64_t)), *buf, buflen); 15372072Svn83148 lhp->freep(resp, resplen); 15382072Svn83148 15392072Svn83148 return (buflen); 15402072Svn83148 } 15412072Svn83148 15422072Svn83148 15432072Svn83148 /* 15442072Svn83148 * see cpu_request() for a description of return values 15452072Svn83148 */ 15462072Svn83148 int 15472072Svn83148 ldmsvcs_cpu_req_status(struct ldom_hdl *lhp, uint32_t cpuid) 15482072Svn83148 { 15492072Svn83148 return (cpu_request(lhp, FMA_CPU_REQ_STATUS, cpuid)); 15502072Svn83148 } 15512072Svn83148 15522072Svn83148 15532072Svn83148 int 15542072Svn83148 ldmsvcs_cpu_req_offline(struct ldom_hdl *lhp, uint32_t cpuid) 15552072Svn83148 { 15562072Svn83148 return (cpu_request(lhp, FMA_CPU_REQ_OFFLINE, cpuid)); 15572072Svn83148 } 15582072Svn83148 15596111Scy152378 int 15606111Scy152378 ldmsvcs_cpu_req_online(struct ldom_hdl *lhp, uint32_t cpuid) 15616111Scy152378 { 15626111Scy152378 return (cpu_request(lhp, FMA_CPU_REQ_ONLINE, cpuid)); 15636111Scy152378 } 15642072Svn83148 15652072Svn83148 /* 15662072Svn83148 * see mem_request() for a description of return values 15672072Svn83148 */ 15682072Svn83148 int 15692072Svn83148 ldmsvcs_mem_req_status(struct ldom_hdl *lhp, uint64_t pa) 15702072Svn83148 { 15712072Svn83148 return (mem_request(lhp, FMA_MEM_REQ_STATUS, pa, getpagesize())); 15722072Svn83148 } 15732072Svn83148 15742072Svn83148 int 15752072Svn83148 ldmsvcs_mem_req_retire(struct ldom_hdl *lhp, uint64_t pa) 15762072Svn83148 { 15772072Svn83148 return (mem_request(lhp, FMA_MEM_REQ_RETIRE, pa, getpagesize())); 15782072Svn83148 } 15792072Svn83148 15806111Scy152378 int 15816111Scy152378 ldmsvcs_mem_req_unretire(struct ldom_hdl *lhp, uint64_t pa) 15826111Scy152378 { 15836111Scy152378 return (mem_request(lhp, FMA_MEM_REQ_RESURRECT, pa, getpagesize())); 15846111Scy152378 } 15856111Scy152378 15862072Svn83148 /* end file */ 1587