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