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> 28*7850SVuong.Nguyen@Sun.COM 292072Svn83148 #include <strings.h> 302072Svn83148 #include <sys/types.h> 312072Svn83148 #include <sys/stat.h> 322072Svn83148 #include <time.h> 332072Svn83148 #include <fcntl.h> 342072Svn83148 #include <unistd.h> 352072Svn83148 #include <errno.h> 362072Svn83148 #include <assert.h> 372072Svn83148 #include <umem.h> 382072Svn83148 #include <alloca.h> 392072Svn83148 #include <sys/processor.h> 402072Svn83148 #include <poll.h> 412072Svn83148 #include <pthread.h> 424358Srb144127 #include <values.h> 434358Srb144127 #include <libscf.h> 442072Svn83148 45*7850SVuong.Nguyen@Sun.COM #include <ctype.h> 46*7850SVuong.Nguyen@Sun.COM 472072Svn83148 #include "ldmsvcs_utils.h" 482072Svn83148 492072Svn83148 #define ASSERT(cnd) \ 502072Svn83148 ((void) ((cnd) || ((void) fprintf(stderr, \ 512072Svn83148 "assertion failure in %s:%d: %s\n", \ 522072Svn83148 __FILE__, __LINE__, #cnd), 0))) 532072Svn83148 542072Svn83148 #define FDS_VLDC \ 552072Svn83148 "/devices/virtual-devices@100/channel-devices@200/" \ 562072Svn83148 "/virtual-channel-client@1:ldmfma" 572072Svn83148 584358Srb144127 /* allow timeouts in sec that are nearly forever but small enough for an int */ 594358Srb144127 #define LDM_TIMEOUT_CEILING (MAXINT / 2) 602072Svn83148 612072Svn83148 #define MIN(x, y) ((x) < (y) ? (x) : (y)) 622072Svn83148 632072Svn83148 /* 642072Svn83148 * functions in this file are for version 1.0 of FMA domain services 652072Svn83148 */ 662072Svn83148 static ds_ver_t ds_vers[] = { 672072Svn83148 { 1, 0 } 682072Svn83148 }; 692072Svn83148 702072Svn83148 #define DS_NUM_VER (sizeof (ds_vers) / sizeof (ds_ver_t)) 712072Svn83148 722072Svn83148 /* 732072Svn83148 * information for each channel 742072Svn83148 */ 752072Svn83148 struct ldmsvcs_info { 762072Svn83148 pthread_mutex_t mt; 772072Svn83148 pthread_cond_t cv; 782072Svn83148 fds_channel_t fds_chan; 792072Svn83148 fds_reg_svcs_t fmas_svcs; 802072Svn83148 int cv_twait; 812072Svn83148 }; 822072Svn83148 832072Svn83148 /* 842072Svn83148 * struct listdata_s and struct poller_s are used to maintain the state of 852072Svn83148 * the poller thread. this thread is used to manage incoming messages and 862072Svn83148 * pass those messages onto the correct requesting thread. see the "poller 872072Svn83148 * functions" section for more details. 882072Svn83148 */ 892072Svn83148 struct listdata_s { 902072Svn83148 enum { 912072Svn83148 UNUSED, 922072Svn83148 PENDING, 932072Svn83148 ARRIVED 942072Svn83148 } status; 952072Svn83148 uint64_t req_num; 962072Svn83148 int fd; 972072Svn83148 size_t datalen; 982072Svn83148 }; 992072Svn83148 1002072Svn83148 static struct poller_s { 1012072Svn83148 pthread_mutex_t mt; 1022072Svn83148 pthread_cond_t cv; 1032072Svn83148 pthread_t polling_tid; 1042072Svn83148 int doreset; 1052072Svn83148 int doexit; 1062072Svn83148 int nclients; 1072072Svn83148 struct listdata_s **list; 1082072Svn83148 int list_len; 1092072Svn83148 int pending_count; 1102072Svn83148 } pollbase = { 1112072Svn83148 PTHREAD_MUTEX_INITIALIZER, 1122072Svn83148 PTHREAD_COND_INITIALIZER, 1132072Svn83148 0, 1142072Svn83148 1, 1152072Svn83148 0, 1162072Svn83148 0, 1172072Svn83148 NULL, 1182072Svn83148 0, 1192072Svn83148 0 1202072Svn83148 }; 1212072Svn83148 1222072Svn83148 1232072Svn83148 static struct ldmsvcs_info *channel_init(struct ldom_hdl *lhp); 1242072Svn83148 static int channel_openreset(struct ldmsvcs_info *lsp); 1252072Svn83148 static int read_msg(struct ldmsvcs_info *lsp); 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; 935*7850SVuong.Nguyen@Sun.COM static char *name[] = { LDM_DS_NAME_CPU, LDM_DS_NAME_MEM, 936*7850SVuong.Nguyen@Sun.COM LDM_DS_NAME_PRI, LDM_DS_NAME_IOD, 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 977*7850SVuong.Nguyen@Sun.COM if (svc->state == DS_SVC_INACTIVE) { 978*7850SVuong.Nguyen@Sun.COM /* service is not registered */ 979*7850SVuong.Nguyen@Sun.COM ier = ETIMEDOUT; 980*7850SVuong.Nguyen@Sun.COM } else { 981*7850SVuong.Nguyen@Sun.COM ier = 0; 982*7850SVuong.Nguyen@Sun.COM twait.tv_sec = time(NULL) + lsp->cv_twait; 983*7850SVuong.Nguyen@Sun.COM twait.tv_nsec = 0; 9842072Svn83148 985*7850SVuong.Nguyen@Sun.COM while (svc->state != DS_SVC_ACTIVE && ier == 0 && 986*7850SVuong.Nguyen@Sun.COM lsp->fds_chan.state != CHANNEL_UNUSABLE) 987*7850SVuong.Nguyen@Sun.COM ier = pthread_cond_timedwait(&lsp->fmas_svcs.cv, 988*7850SVuong.Nguyen@Sun.COM &lsp->fmas_svcs.mt, &twait); 989*7850SVuong.Nguyen@Sun.COM 990*7850SVuong.Nguyen@Sun.COM /* 991*7850SVuong.Nguyen@Sun.COM * By now, the ds service should have registered already. 992*7850SVuong.Nguyen@Sun.COM * If it does not, ldmd probably does not support this service. 993*7850SVuong.Nguyen@Sun.COM * Then mark the service state as inactive. 994*7850SVuong.Nguyen@Sun.COM */ 995*7850SVuong.Nguyen@Sun.COM if (ier == ETIMEDOUT) { 996*7850SVuong.Nguyen@Sun.COM svc->state = DS_SVC_INACTIVE; 997*7850SVuong.Nguyen@Sun.COM } 998*7850SVuong.Nguyen@Sun.COM } 9992072Svn83148 10002072Svn83148 (void) pthread_mutex_unlock(&lsp->fmas_svcs.mt); 10012072Svn83148 10022072Svn83148 if (ier == 0) 10032072Svn83148 return (svc); 10042072Svn83148 else 10052072Svn83148 return (NULL); 10062072Svn83148 } 10072072Svn83148 10082072Svn83148 10092072Svn83148 static uint64_t 10102072Svn83148 fds_svc_req_num(void) 10112072Svn83148 { 10122072Svn83148 static uint64_t req_num = 1; 10132072Svn83148 10142072Svn83148 return (req_num++); 10152072Svn83148 } 10162072Svn83148 10172072Svn83148 10182072Svn83148 /* 10192072Svn83148 * return 0 if successful, 1 if otherwise 10202072Svn83148 */ 10212072Svn83148 static int 10222072Svn83148 read_msg(struct ldmsvcs_info *lsp) 10232072Svn83148 { 10242072Svn83148 ds_hdr_t header; 10252072Svn83148 void *msg_buf; 10262072Svn83148 10272072Svn83148 /* 10282072Svn83148 * read the header 10292072Svn83148 */ 10302072Svn83148 if (read_stream(lsp->fds_chan.fd, &header, sizeof (ds_hdr_t)) != 0) 10312072Svn83148 return (1); 10322072Svn83148 10332072Svn83148 if (header.msg_type >= 10342072Svn83148 sizeof (ds_msg_handlers) / sizeof (ds_msg_handler_t)) 10354358Srb144127 return (1); 10362072Svn83148 10372072Svn83148 /* 10382072Svn83148 * handle data as a special case 10392072Svn83148 */ 10402072Svn83148 if (header.msg_type == 9) 10412072Svn83148 return (poller_handle_data(lsp->fds_chan.fd, 10424358Srb144127 header.payload_len)); 10432072Svn83148 10442072Svn83148 /* 10452072Svn83148 * all other types of messages should be small 10462072Svn83148 */ 10472072Svn83148 ASSERT(header.payload_len < 1024); 10482072Svn83148 msg_buf = alloca(header.payload_len); 10492072Svn83148 10502072Svn83148 /* 10512072Svn83148 * read the payload 10522072Svn83148 */ 10532072Svn83148 if (read_stream(lsp->fds_chan.fd, msg_buf, header.payload_len) != 0) 10542072Svn83148 return (1); 10552072Svn83148 10562072Svn83148 (*ds_msg_handlers[header.msg_type])(lsp, msg_buf, header.payload_len); 10572072Svn83148 10582072Svn83148 return (0); 10592072Svn83148 } 10602072Svn83148 10612072Svn83148 10622072Svn83148 /* 10632072Svn83148 * return values: 10642072Svn83148 * 0 - success 10652072Svn83148 * 1 - problem with opening the channel 10662072Svn83148 * 2 - channed not opened; request to exit has been detected 10672072Svn83148 */ 10682072Svn83148 static int 10692072Svn83148 channel_openreset(struct ldmsvcs_info *lsp) 10702072Svn83148 { 10712072Svn83148 int ier; 10722072Svn83148 10732072Svn83148 ier = pthread_mutex_lock(&lsp->mt); 10742072Svn83148 10752072Svn83148 if (ier == EINVAL || lsp->fds_chan.state == CHANNEL_EXIT || 10762072Svn83148 lsp->fds_chan.state == CHANNEL_UNUSABLE) { 10772072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 10782072Svn83148 return (2); 10792072Svn83148 } 10802072Svn83148 10812072Svn83148 if (lsp->fds_chan.state == CHANNEL_UNINITIALIZED || 10822072Svn83148 lsp->fds_chan.state == CHANNEL_CLOSED) { 10832072Svn83148 (void) pthread_cond_broadcast(&lsp->cv); 10842072Svn83148 10852072Svn83148 if ((lsp->fds_chan.fd = open(FDS_VLDC, O_RDWR)) < 0) { 10862072Svn83148 lsp->fds_chan.state = CHANNEL_UNUSABLE; 10874358Srb144127 lsp->cv_twait = get_smf_int_val(LDM_RUNNING_TO_PROP_NM, 10884358Srb144127 0, LDM_TIMEOUT_CEILING, LDM_RUNNING_WAIT_TIME); 10892072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 10902072Svn83148 (void) pthread_cond_broadcast(&lsp->fmas_svcs.cv); 10912072Svn83148 10922072Svn83148 return (2); 10932072Svn83148 } else { 10942072Svn83148 vldc_opt_op_t op; 10952072Svn83148 10962072Svn83148 op.op_sel = VLDC_OP_SET; 10972072Svn83148 op.opt_sel = VLDC_OPT_MODE; 10986408Sha137994 op.opt_val = LDC_MODE_RELIABLE; 10992072Svn83148 11002072Svn83148 if (ioctl(lsp->fds_chan.fd, VLDC_IOCTL_OPT_OP, 11014358Srb144127 &op) != 0) { 11022072Svn83148 (void) close(lsp->fds_chan.fd); 11032072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 11042072Svn83148 return (1); 11052072Svn83148 } 11062072Svn83148 } 11072072Svn83148 lsp->fds_chan.state = CHANNEL_OPEN; 11082072Svn83148 } 11092072Svn83148 11102072Svn83148 if (lsp->fds_chan.state == CHANNEL_OPEN) { 11112072Svn83148 /* 11122072Svn83148 * reset various channel parameters 11132072Svn83148 */ 11142072Svn83148 lsp->fds_chan.ver.major = 0; 11152072Svn83148 lsp->fds_chan.ver.minor = 0; 11162072Svn83148 fds_svc_reset(lsp, -1); 11172072Svn83148 } 11182072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 11192072Svn83148 11202072Svn83148 return (0); 11212072Svn83148 } 11222072Svn83148 11232072Svn83148 11242072Svn83148 static void 11252072Svn83148 channel_fini(void) 11262072Svn83148 { 11272072Svn83148 struct ldmsvcs_info *lsp; 11282072Svn83148 11292072Svn83148 /* 11302072Svn83148 * End the poller thread 11312072Svn83148 */ 11322072Svn83148 poller_shutdown(); 11332072Svn83148 11342072Svn83148 if ((lsp = channel_init(NULL)) == NULL) 11352072Svn83148 return; 11362072Svn83148 11372072Svn83148 (void) pthread_mutex_lock(&lsp->mt); 11382072Svn83148 11392072Svn83148 lsp->fds_chan.state = CHANNEL_EXIT; 11402072Svn83148 (void) close(lsp->fds_chan.fd); 11412072Svn83148 11422072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 11432072Svn83148 } 11442072Svn83148 11452072Svn83148 11462072Svn83148 static struct ldmsvcs_info * 11472072Svn83148 channel_init(struct ldom_hdl *lhp) 11482072Svn83148 { 11492072Svn83148 static pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER; 11502072Svn83148 static pthread_cond_t cv = PTHREAD_COND_INITIALIZER; 11512072Svn83148 static struct ldmsvcs_info *root = NULL; 11522072Svn83148 static int busy_init = 0; 11532072Svn83148 11542072Svn83148 struct timespec twait; 11552072Svn83148 int expired; 11562072Svn83148 11572072Svn83148 (void) pthread_mutex_lock(&mt); 11582072Svn83148 11592072Svn83148 while (busy_init == 1) 11602072Svn83148 (void) pthread_cond_wait(&cv, &mt); 11612072Svn83148 11622072Svn83148 if (root != NULL || (lhp == NULL && root == NULL)) { 11632072Svn83148 (void) pthread_mutex_unlock(&mt); 11642072Svn83148 return (root); 11652072Svn83148 } 11662072Svn83148 11672072Svn83148 /* 11682072Svn83148 * get to this point if we need to open the channel 11692072Svn83148 */ 11702072Svn83148 busy_init = 1; 11712072Svn83148 (void) pthread_mutex_unlock(&mt); 11722072Svn83148 11732072Svn83148 root = (struct ldmsvcs_info *) 11744358Srb144127 lhp->allocp(sizeof (struct ldmsvcs_info)); 11752072Svn83148 bzero(root, sizeof (struct ldmsvcs_info)); 11762072Svn83148 11772072Svn83148 root->fds_chan.state = CHANNEL_UNINITIALIZED; 11784358Srb144127 root->cv_twait = get_smf_int_val(LDM_INIT_TO_PROP_NM, 11794358Srb144127 0, LDM_TIMEOUT_CEILING, LDM_INIT_WAIT_TIME); 11802072Svn83148 11812072Svn83148 if (pthread_mutex_init(&root->mt, NULL) != 0 || 11822072Svn83148 pthread_cond_init(&root->cv, NULL) != 0) { 11832072Svn83148 lhp->freep(root, sizeof (struct ldmsvcs_info)); 11842072Svn83148 return (NULL); 11852072Svn83148 } 11862072Svn83148 11872072Svn83148 fds_svc_alloc(lhp, root); 11882072Svn83148 fds_svc_reset(root, -1); 11892072Svn83148 11902072Svn83148 (void) poller_init(root); 11912072Svn83148 11922072Svn83148 expired = 0; 11932072Svn83148 twait.tv_sec = time(NULL) + 10; 11942072Svn83148 twait.tv_nsec = 0; 11952072Svn83148 11962072Svn83148 (void) pthread_mutex_lock(&root->mt); 11972072Svn83148 11982072Svn83148 /* 11992072Svn83148 * wait for channel to become uninitialized. this should be quick. 12002072Svn83148 */ 12012072Svn83148 while (root->fds_chan.state == CHANNEL_UNINITIALIZED && expired == 0) 12022072Svn83148 expired = pthread_cond_timedwait(&root->cv, &root->mt, &twait); 12032072Svn83148 12042072Svn83148 if (root->fds_chan.state == CHANNEL_UNUSABLE) 12052072Svn83148 expired = 1; 12062072Svn83148 12072072Svn83148 (void) pthread_mutex_unlock(&root->mt); 12082072Svn83148 12092072Svn83148 (void) pthread_mutex_lock(&mt); 12102072Svn83148 busy_init = 0; 12112072Svn83148 (void) pthread_mutex_unlock(&mt); 12122072Svn83148 (void) pthread_cond_broadcast(&cv); 12132072Svn83148 12142072Svn83148 (void) atexit(channel_fini); 12152072Svn83148 12162072Svn83148 if (expired == 0) 12172072Svn83148 return (root); 12182072Svn83148 else 12192072Svn83148 return (NULL); 12202072Svn83148 } 12212072Svn83148 12222072Svn83148 12232072Svn83148 static int 12242072Svn83148 sendrecv(struct ldom_hdl *lhp, uint64_t req_num, 12252072Svn83148 void *msg, size_t msglen, ds_svc_hdl_t *svc_hdl, char *svcname, 12262072Svn83148 void **resp, size_t *resplen) 12272072Svn83148 { 12282072Svn83148 struct ldmsvcs_info *lsp; 12292072Svn83148 fds_svc_t *svc; 12302072Svn83148 int maxretries, index, i, ier; 12312072Svn83148 12322072Svn83148 lsp = lhp->lsinfo; 12332072Svn83148 i = 0; 12342072Svn83148 maxretries = 1; 12352072Svn83148 12362072Svn83148 do { 12372072Svn83148 /* 12382072Svn83148 * if any of the calls in this loop fail, retry some number 12392072Svn83148 * of times before giving up. 12402072Svn83148 */ 12412072Svn83148 if ((svc = fds_svc_lookup(lsp, svcname)) == NULL) { 12422072Svn83148 (void) pthread_mutex_lock(&lsp->mt); 12432072Svn83148 12442072Svn83148 if (lsp->fds_chan.state != CHANNEL_READY) 12452072Svn83148 ier = ETIMEDOUT; /* channel not ready */ 12462072Svn83148 else 12472072Svn83148 ier = ENOTSUP; /* service not ready */ 12482072Svn83148 12492072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 12502072Svn83148 12512072Svn83148 continue; 12522072Svn83148 } else { 12532072Svn83148 ier = 0; 12542072Svn83148 *svc_hdl = svc->hdl; 12552072Svn83148 } 12562072Svn83148 12572072Svn83148 index = poller_add_pending(lhp, req_num); 12582072Svn83148 12592072Svn83148 if ((ier = fds_send(lsp, msg, msglen)) != 0 || 12602072Svn83148 (ier = poller_recv_data(lhp, req_num, index, resp, 12614358Srb144127 resplen)) != 0) 12622072Svn83148 poller_delete_pending(req_num, index); 12632072Svn83148 12642072Svn83148 } while (i++ < maxretries && ier != 0); 12652072Svn83148 12662072Svn83148 ASSERT(ier == 0 || ier == ETIMEDOUT || ier == ENOTSUP); 12672072Svn83148 12682072Svn83148 return (ier); 12692072Svn83148 } 12702072Svn83148 12712072Svn83148 12722072Svn83148 /* 12732072Svn83148 * input: 12742072Svn83148 * msg_type - requested operation: FMA_CPU_REQ_STATUS or FMA_CPU_REQ_OFFLINE 12752072Svn83148 * cpuid - physical cpu id 12762072Svn83148 * 12772072Svn83148 * normal return values: 12782072Svn83148 * P_OFFLINE - cpu is offline 12792072Svn83148 * P_ONLINE - cpu is online 12802072Svn83148 * 12812072Svn83148 * abnormal return values: 12822072Svn83148 * ETIMEDOUT - LDOM manager is not responding 12832072Svn83148 * ENOTSUP - LDOM service for cpu offlining/status is not available 12842072Svn83148 * ENOMSG - got an unexpected response from the LDOM cpu service 12852072Svn83148 */ 12862072Svn83148 static int 12872072Svn83148 cpu_request(struct ldom_hdl *lhp, uint32_t msg_type, uint32_t cpuid) 12882072Svn83148 { 12892072Svn83148 ds_hdr_t *H; 12902072Svn83148 ds_data_handle_t *D; 12912072Svn83148 fma_cpu_service_req_t *R; 12922072Svn83148 1293*7850SVuong.Nguyen@Sun.COM char *svcname = LDM_DS_NAME_CPU; 12942072Svn83148 fma_cpu_resp_t *respmsg; 12952072Svn83148 void *resp; 12962072Svn83148 size_t resplen, reqmsglen; 12972072Svn83148 int rc; 12982072Svn83148 12992072Svn83148 if (lhp->lsinfo == NULL) 13002072Svn83148 return (ENOMSG); 13012072Svn83148 13022072Svn83148 reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) + 13034358Srb144127 sizeof (fma_cpu_service_req_t); 13042072Svn83148 13052072Svn83148 H = lhp->allocp(reqmsglen); 13062072Svn83148 D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 13072072Svn83148 R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t)); 13082072Svn83148 13092072Svn83148 H->msg_type = DS_DATA; 13102072Svn83148 H->payload_len = sizeof (ds_data_handle_t) + 13114358Srb144127 sizeof (fma_cpu_service_req_t); 13122072Svn83148 13132072Svn83148 R->req_num = fds_svc_req_num(); 13142072Svn83148 R->msg_type = msg_type; 13152072Svn83148 R->cpu_id = cpuid; 13162072Svn83148 13172072Svn83148 if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen, 13184358Srb144127 &D->svc_handle, svcname, &resp, &resplen)) != 0) { 13192072Svn83148 lhp->freep(H, reqmsglen); 13202072Svn83148 return (rc); 13212072Svn83148 } 13222072Svn83148 13232072Svn83148 lhp->freep(H, reqmsglen); 13242072Svn83148 13252072Svn83148 ASSERT(resplen == sizeof (fma_cpu_resp_t)); 13262072Svn83148 respmsg = (fma_cpu_resp_t *)resp; 13272072Svn83148 13282072Svn83148 rc = ENOMSG; 13292072Svn83148 if (respmsg->result == FMA_CPU_RESP_OK) { 13302072Svn83148 if (respmsg->status == FMA_CPU_STAT_ONLINE) 13312072Svn83148 rc = P_ONLINE; 13322072Svn83148 else if (respmsg->status == FMA_CPU_STAT_OFFLINE) 13332072Svn83148 rc = P_OFFLINE; 13342072Svn83148 } else { 13352072Svn83148 if (msg_type == FMA_CPU_REQ_OFFLINE && 13362072Svn83148 respmsg->status == FMA_CPU_STAT_OFFLINE) 13372072Svn83148 rc = P_OFFLINE; 13382072Svn83148 } 13392072Svn83148 13402072Svn83148 lhp->freep(resp, resplen); 13412072Svn83148 13422072Svn83148 return (rc); 13432072Svn83148 } 13442072Svn83148 13452072Svn83148 13462072Svn83148 /* 13472072Svn83148 * input: 13482072Svn83148 * msg_type - requested operation: FMA_MEM_REQ_STATUS or FMA_MEM_REQ_RETIRE 13492072Svn83148 * pa - starting address of memory page 13502072Svn83148 * pgsize - memory page size in bytes 13512072Svn83148 * 13522072Svn83148 * normal return values for msg_type == FMA_MEM_REQ_STATUS: 13532072Svn83148 * 0 - page is retired 13542072Svn83148 * EAGAIN - page is scheduled for retirement 13552072Svn83148 * EIO - page not scheduled for retirement 13562072Svn83148 * EINVAL - error 13572072Svn83148 * 13582072Svn83148 * normal return values for msg_type == FMA_MEM_REQ_RETIRE: 13592072Svn83148 * 0 - success in retiring page 13602072Svn83148 * EIO - page is already retired 13612072Svn83148 * EAGAIN - page is scheduled for retirement 13622072Svn83148 * EINVAL - error 13632072Svn83148 * 13642072Svn83148 * abnormal return values (regardless of msg_type) 13652072Svn83148 * ETIMEDOUT - LDOM manager is not responding 13662072Svn83148 * ENOTSUP - LDOM service for cpu offlining/status is not available 13672072Svn83148 * ENOMSG - got an unexpected response from the LDOM cpu service 13682072Svn83148 */ 13692072Svn83148 static int 13702072Svn83148 mem_request(struct ldom_hdl *lhp, uint32_t msg_type, uint64_t pa, 13712072Svn83148 uint64_t pgsize) 13722072Svn83148 { 13732072Svn83148 ds_hdr_t *H; 13742072Svn83148 ds_data_handle_t *D; 13752072Svn83148 fma_mem_service_req_t *R; 13762072Svn83148 1377*7850SVuong.Nguyen@Sun.COM char *svcname = LDM_DS_NAME_MEM; 13782072Svn83148 fma_mem_resp_t *respmsg; 13792072Svn83148 void *resp; 13802072Svn83148 size_t resplen, reqmsglen; 13812072Svn83148 int rc; 13822072Svn83148 13832072Svn83148 if (lhp->lsinfo == NULL) 13842072Svn83148 return (ENOMSG); 13852072Svn83148 13862072Svn83148 reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) + 13874358Srb144127 sizeof (fma_mem_service_req_t); 13882072Svn83148 13892072Svn83148 H = lhp->allocp(reqmsglen); 13902072Svn83148 bzero(H, reqmsglen); 13912072Svn83148 D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 13922072Svn83148 R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t)); 13932072Svn83148 13942072Svn83148 H->msg_type = DS_DATA; 13952072Svn83148 H->payload_len = sizeof (ds_data_handle_t) + 13964358Srb144127 sizeof (fma_mem_service_req_t); 13972072Svn83148 13982072Svn83148 R->req_num = fds_svc_req_num(); 13992072Svn83148 R->msg_type = msg_type; 14002072Svn83148 R->real_addr = pa; 14012072Svn83148 R->length = pgsize; 14022072Svn83148 14032072Svn83148 if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen, 14044358Srb144127 &D->svc_handle, svcname, &resp, &resplen)) != 0) { 14052072Svn83148 lhp->freep(H, reqmsglen); 14062072Svn83148 return (rc); 14072072Svn83148 } 14082072Svn83148 14092072Svn83148 lhp->freep(H, reqmsglen); 14102072Svn83148 14112072Svn83148 ASSERT(resplen == sizeof (fma_mem_resp_t)); 14122072Svn83148 respmsg = (fma_mem_resp_t *)resp; 14132072Svn83148 14142072Svn83148 rc = ENOMSG; 14152072Svn83148 if (msg_type == FMA_MEM_REQ_STATUS) { 14162072Svn83148 if (respmsg->result == FMA_MEM_RESP_OK) { 14172072Svn83148 if (respmsg->status == FMA_MEM_STAT_RETIRED) 14184655Svn83148 rc = 0; /* page is retired */ 14192072Svn83148 else if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 14204655Svn83148 rc = EIO; /* page is not scheduled */ 14212072Svn83148 } else if (respmsg->result == FMA_MEM_RESP_FAILURE) { 14224655Svn83148 if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 14234655Svn83148 rc = EAGAIN; /* page is scheduled */ 14244655Svn83148 else if (respmsg->status == FMA_MEM_STAT_ILLEGAL) 14252072Svn83148 rc = EINVAL; 14262072Svn83148 } 14272072Svn83148 } else if (msg_type == FMA_MEM_REQ_RETIRE) { 14282072Svn83148 if (respmsg->result == FMA_MEM_RESP_OK) { 14292072Svn83148 if (respmsg->status == FMA_MEM_STAT_RETIRED) 14304655Svn83148 rc = 0; /* is successfully retired */ 14312072Svn83148 } else if (respmsg->result == FMA_MEM_RESP_FAILURE) { 14322072Svn83148 if (respmsg->status == FMA_MEM_STAT_RETIRED) 14334655Svn83148 rc = EIO; /* is already retired */ 14344655Svn83148 else if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 14354655Svn83148 rc = EAGAIN; /* is scheduled to retire */ 14362072Svn83148 else if (respmsg->status == FMA_MEM_STAT_ILLEGAL) 14372072Svn83148 rc = EINVAL; 14382072Svn83148 } 14397532SSean.Ye@Sun.COM } else if (msg_type == FMA_MEM_REQ_RESURRECT) { 14407532SSean.Ye@Sun.COM if (respmsg->result == FMA_MEM_RESP_OK) { 14417532SSean.Ye@Sun.COM if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 14427532SSean.Ye@Sun.COM rc = 0; /* is successfully unretired */ 14437532SSean.Ye@Sun.COM } if (respmsg->result == FMA_MEM_RESP_FAILURE) { 14447532SSean.Ye@Sun.COM if (respmsg->status == FMA_MEM_STAT_RETIRED) 14457532SSean.Ye@Sun.COM rc = EAGAIN; /* page couldn't be locked */ 14467532SSean.Ye@Sun.COM else if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 14477532SSean.Ye@Sun.COM rc = EIO; /* page isn't retired already */ 14487532SSean.Ye@Sun.COM else if (respmsg->status == FMA_MEM_STAT_ILLEGAL) 14497532SSean.Ye@Sun.COM rc = EINVAL; 14507532SSean.Ye@Sun.COM } 14512072Svn83148 } 14522072Svn83148 14532072Svn83148 lhp->freep(resp, resplen); 14542072Svn83148 14552072Svn83148 return (rc); 14562072Svn83148 } 14572072Svn83148 14582072Svn83148 14592072Svn83148 /* 14602072Svn83148 * APIs 14612072Svn83148 */ 14622072Svn83148 int 14632072Svn83148 ldmsvcs_check_channel(void) 14642072Svn83148 { 14652072Svn83148 struct stat buf; 14662072Svn83148 14672072Svn83148 if (stat(FDS_VLDC, &buf) == 0) 14682072Svn83148 return (0); /* vldc exists */ 14692072Svn83148 else if (errno == ENOENT || errno == ENOTDIR) 14702072Svn83148 return (1); /* vldc does not exist */ 14712072Svn83148 else 14722072Svn83148 return (-1); /* miscellaneous error */ 14732072Svn83148 } 14742072Svn83148 14752072Svn83148 14762072Svn83148 /*ARGSUSED*/ 14772072Svn83148 void 14782072Svn83148 ldmsvcs_init(struct ldom_hdl *lhp) 14792072Svn83148 { 14802072Svn83148 if (ldmsvcs_check_channel() != 0) 14812072Svn83148 return; 14822072Svn83148 14832072Svn83148 lhp->lsinfo = channel_init(lhp); 14842072Svn83148 poller_add_client(); 14852072Svn83148 } 14862072Svn83148 14872072Svn83148 14882072Svn83148 /*ARGSUSED*/ 14892072Svn83148 void 14902072Svn83148 ldmsvcs_fini(struct ldom_hdl *lhp) 14912072Svn83148 { 14922072Svn83148 if (ldmsvcs_check_channel() != 0) 14932072Svn83148 return; 14942072Svn83148 14952072Svn83148 poller_remove_client(); 14962072Svn83148 } 14972072Svn83148 14982072Svn83148 14992072Svn83148 /*ARGSUSED*/ 15002072Svn83148 ssize_t 15012072Svn83148 ldmsvcs_get_core_md(struct ldom_hdl *lhp, uint64_t **buf) 15022072Svn83148 { 15032072Svn83148 ds_hdr_t *H; 15042072Svn83148 ds_data_handle_t *D; 15052072Svn83148 fma_req_pri_t *R; 15062072Svn83148 1507*7850SVuong.Nguyen@Sun.COM char *svcname = LDM_DS_NAME_PRI; 15082072Svn83148 void *resp; 15092072Svn83148 size_t resplen, reqmsglen; 15102072Svn83148 ssize_t buflen; 15112072Svn83148 int rc; 15122072Svn83148 15132072Svn83148 if (lhp->lsinfo == NULL) 15142072Svn83148 return (-1); 15152072Svn83148 15162072Svn83148 reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) + 15174358Srb144127 sizeof (fma_req_pri_t); 15182072Svn83148 15192072Svn83148 H = lhp->allocp(reqmsglen); 15202072Svn83148 D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 15212072Svn83148 R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t)); 15222072Svn83148 15232072Svn83148 H->msg_type = DS_DATA; 15242072Svn83148 H->payload_len = sizeof (ds_data_handle_t) + 15254358Srb144127 sizeof (fma_req_pri_t); 15262072Svn83148 15272072Svn83148 R->req_num = fds_svc_req_num(); 15282072Svn83148 15292072Svn83148 if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen, 15304358Srb144127 &D->svc_handle, svcname, &resp, &resplen)) != 0) { 15312072Svn83148 lhp->freep(H, reqmsglen); 15322072Svn83148 errno = rc; 15332072Svn83148 return (-1); 15342072Svn83148 } 15352072Svn83148 15362072Svn83148 lhp->freep(H, reqmsglen); 15372072Svn83148 15382072Svn83148 /* 15392072Svn83148 * resp should contain the req_num immediately followed by the PRI 15402072Svn83148 * (the latter may or may not be present). unfortunately, the 15412072Svn83148 * current compiler flags cause a warning for the following 15422072Svn83148 * definition 15432072Svn83148 * 15442072Svn83148 * typedef struct { 15452072Svn83148 * uint64_t req_num; 15462072Svn83148 * uint8_t pri[]; 15472072Svn83148 * } fma_pri_resp_t; 15482072Svn83148 * 15492072Svn83148 * so we do not use the struct here. 15502072Svn83148 */ 15512072Svn83148 if (resplen <= sizeof (uint64_t)) { 15522072Svn83148 lhp->freep(resp, resplen); 15532072Svn83148 if (resplen == sizeof (uint64_t)) 15542072Svn83148 return (0); 15552072Svn83148 else 15562072Svn83148 return (-1); 15572072Svn83148 } 15582072Svn83148 15592072Svn83148 buflen = resplen - sizeof (uint64_t); 15602072Svn83148 *buf = lhp->allocp(buflen); 15612072Svn83148 15622072Svn83148 bcopy((void *)((ptrdiff_t)resp + sizeof (uint64_t)), *buf, buflen); 15632072Svn83148 lhp->freep(resp, resplen); 15642072Svn83148 15652072Svn83148 return (buflen); 15662072Svn83148 } 15672072Svn83148 15682072Svn83148 15692072Svn83148 /* 15702072Svn83148 * see cpu_request() for a description of return values 15712072Svn83148 */ 15722072Svn83148 int 15732072Svn83148 ldmsvcs_cpu_req_status(struct ldom_hdl *lhp, uint32_t cpuid) 15742072Svn83148 { 15752072Svn83148 return (cpu_request(lhp, FMA_CPU_REQ_STATUS, cpuid)); 15762072Svn83148 } 15772072Svn83148 15782072Svn83148 15792072Svn83148 int 15802072Svn83148 ldmsvcs_cpu_req_offline(struct ldom_hdl *lhp, uint32_t cpuid) 15812072Svn83148 { 15822072Svn83148 return (cpu_request(lhp, FMA_CPU_REQ_OFFLINE, cpuid)); 15832072Svn83148 } 15842072Svn83148 15856111Scy152378 int 15866111Scy152378 ldmsvcs_cpu_req_online(struct ldom_hdl *lhp, uint32_t cpuid) 15876111Scy152378 { 15886111Scy152378 return (cpu_request(lhp, FMA_CPU_REQ_ONLINE, cpuid)); 15896111Scy152378 } 15902072Svn83148 15912072Svn83148 /* 15922072Svn83148 * see mem_request() for a description of return values 15932072Svn83148 */ 15942072Svn83148 int 15952072Svn83148 ldmsvcs_mem_req_status(struct ldom_hdl *lhp, uint64_t pa) 15962072Svn83148 { 15972072Svn83148 return (mem_request(lhp, FMA_MEM_REQ_STATUS, pa, getpagesize())); 15982072Svn83148 } 15992072Svn83148 16002072Svn83148 int 16012072Svn83148 ldmsvcs_mem_req_retire(struct ldom_hdl *lhp, uint64_t pa) 16022072Svn83148 { 16032072Svn83148 return (mem_request(lhp, FMA_MEM_REQ_RETIRE, pa, getpagesize())); 16042072Svn83148 } 16052072Svn83148 16066111Scy152378 int 16076111Scy152378 ldmsvcs_mem_req_unretire(struct ldom_hdl *lhp, uint64_t pa) 16086111Scy152378 { 16096111Scy152378 return (mem_request(lhp, FMA_MEM_REQ_RESURRECT, pa, getpagesize())); 16106111Scy152378 } 16116111Scy152378 1612*7850SVuong.Nguyen@Sun.COM int 1613*7850SVuong.Nguyen@Sun.COM ldmsvcs_io_req_id(struct ldom_hdl *lhp, uint64_t addr, uint_t type, 1614*7850SVuong.Nguyen@Sun.COM uint64_t *virt_addr, char *name, int name_len, uint64_t *did) 1615*7850SVuong.Nguyen@Sun.COM { 1616*7850SVuong.Nguyen@Sun.COM 1617*7850SVuong.Nguyen@Sun.COM ds_hdr_t *H; 1618*7850SVuong.Nguyen@Sun.COM ds_data_handle_t *D; 1619*7850SVuong.Nguyen@Sun.COM fma_io_req_t *R; 1620*7850SVuong.Nguyen@Sun.COM 1621*7850SVuong.Nguyen@Sun.COM char *svcname = LDM_DS_NAME_IOD; 1622*7850SVuong.Nguyen@Sun.COM void *resp; 1623*7850SVuong.Nguyen@Sun.COM fma_io_resp_t *iop; 1624*7850SVuong.Nguyen@Sun.COM size_t resplen, reqmsglen; 1625*7850SVuong.Nguyen@Sun.COM int offset; 1626*7850SVuong.Nguyen@Sun.COM int rc; 1627*7850SVuong.Nguyen@Sun.COM 1628*7850SVuong.Nguyen@Sun.COM if (lhp->lsinfo == NULL) 1629*7850SVuong.Nguyen@Sun.COM return (-1); 1630*7850SVuong.Nguyen@Sun.COM 1631*7850SVuong.Nguyen@Sun.COM reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) + 1632*7850SVuong.Nguyen@Sun.COM sizeof (fma_io_req_t); 1633*7850SVuong.Nguyen@Sun.COM 1634*7850SVuong.Nguyen@Sun.COM H = lhp->allocp(reqmsglen); 1635*7850SVuong.Nguyen@Sun.COM D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 1636*7850SVuong.Nguyen@Sun.COM R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t)); 1637*7850SVuong.Nguyen@Sun.COM 1638*7850SVuong.Nguyen@Sun.COM H->msg_type = DS_DATA; 1639*7850SVuong.Nguyen@Sun.COM H->payload_len = sizeof (ds_data_handle_t) + sizeof (fma_io_req_t); 1640*7850SVuong.Nguyen@Sun.COM 1641*7850SVuong.Nguyen@Sun.COM R->req_num = fds_svc_req_num(); 1642*7850SVuong.Nguyen@Sun.COM R->msg_type = type; 1643*7850SVuong.Nguyen@Sun.COM R->rsrc_address = addr; 1644*7850SVuong.Nguyen@Sun.COM 1645*7850SVuong.Nguyen@Sun.COM rc = ENOMSG; 1646*7850SVuong.Nguyen@Sun.COM if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen, 1647*7850SVuong.Nguyen@Sun.COM &D->svc_handle, svcname, &resp, &resplen)) != 0) { 1648*7850SVuong.Nguyen@Sun.COM lhp->freep(H, reqmsglen); 1649*7850SVuong.Nguyen@Sun.COM return (rc); 1650*7850SVuong.Nguyen@Sun.COM } 1651*7850SVuong.Nguyen@Sun.COM lhp->freep(H, reqmsglen); 1652*7850SVuong.Nguyen@Sun.COM 1653*7850SVuong.Nguyen@Sun.COM /* 1654*7850SVuong.Nguyen@Sun.COM * resp should contain the req_num, status, virtual addr, domain id 1655*7850SVuong.Nguyen@Sun.COM * and the domain name. The domain name may or may not be present. 1656*7850SVuong.Nguyen@Sun.COM */ 1657*7850SVuong.Nguyen@Sun.COM offset = sizeof (fma_io_resp_t); 1658*7850SVuong.Nguyen@Sun.COM if (resplen < offset) { 1659*7850SVuong.Nguyen@Sun.COM lhp->freep(resp, resplen); 1660*7850SVuong.Nguyen@Sun.COM return (-1); 1661*7850SVuong.Nguyen@Sun.COM } 1662*7850SVuong.Nguyen@Sun.COM 1663*7850SVuong.Nguyen@Sun.COM iop = (fma_io_resp_t *)resp; 1664*7850SVuong.Nguyen@Sun.COM switch (iop->result) { 1665*7850SVuong.Nguyen@Sun.COM case FMA_IO_RESP_OK: 1666*7850SVuong.Nguyen@Sun.COM /* success */ 1667*7850SVuong.Nguyen@Sun.COM rc = 0; 1668*7850SVuong.Nguyen@Sun.COM *virt_addr = iop->virt_rsrc_address; 1669*7850SVuong.Nguyen@Sun.COM *did = iop->domain_id; 1670*7850SVuong.Nguyen@Sun.COM if (name == NULL || name_len <= 0) 1671*7850SVuong.Nguyen@Sun.COM break; 1672*7850SVuong.Nguyen@Sun.COM *name = '\0'; 1673*7850SVuong.Nguyen@Sun.COM if (resplen > offset) { 1674*7850SVuong.Nguyen@Sun.COM (void) strncpy(name, (char *)((ptrdiff_t)resp + offset), 1675*7850SVuong.Nguyen@Sun.COM name_len); 1676*7850SVuong.Nguyen@Sun.COM } 1677*7850SVuong.Nguyen@Sun.COM break; 1678*7850SVuong.Nguyen@Sun.COM default: 1679*7850SVuong.Nguyen@Sun.COM rc = -1; 1680*7850SVuong.Nguyen@Sun.COM break; 1681*7850SVuong.Nguyen@Sun.COM } 1682*7850SVuong.Nguyen@Sun.COM 1683*7850SVuong.Nguyen@Sun.COM lhp->freep(resp, resplen); 1684*7850SVuong.Nguyen@Sun.COM return (rc); 1685*7850SVuong.Nguyen@Sun.COM } 1686*7850SVuong.Nguyen@Sun.COM 16872072Svn83148 /* end file */ 1688