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 /* 22*8634SVuong.Nguyen@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 232072Svn83148 * Use is subject to license terms. 242072Svn83148 */ 252072Svn83148 262072Svn83148 #include <stdlib.h> 272072Svn83148 #include <stdio.h> 287850SVuong.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> 42*8634SVuong.Nguyen@Sun.COM #include <signal.h> 434358Srb144127 #include <values.h> 444358Srb144127 #include <libscf.h> 452072Svn83148 467850SVuong.Nguyen@Sun.COM #include <ctype.h> 477850SVuong.Nguyen@Sun.COM 482072Svn83148 #include "ldmsvcs_utils.h" 49*8634SVuong.Nguyen@Sun.COM #include "ldom_alloc.h" 502072Svn83148 512072Svn83148 #define ASSERT(cnd) \ 522072Svn83148 ((void) ((cnd) || ((void) fprintf(stderr, \ 532072Svn83148 "assertion failure in %s:%d: %s\n", \ 542072Svn83148 __FILE__, __LINE__, #cnd), 0))) 552072Svn83148 562072Svn83148 #define FDS_VLDC \ 572072Svn83148 "/devices/virtual-devices@100/channel-devices@200/" \ 582072Svn83148 "/virtual-channel-client@1:ldmfma" 592072Svn83148 604358Srb144127 /* allow timeouts in sec that are nearly forever but small enough for an int */ 614358Srb144127 #define LDM_TIMEOUT_CEILING (MAXINT / 2) 622072Svn83148 632072Svn83148 #define MIN(x, y) ((x) < (y) ? (x) : (y)) 642072Svn83148 652072Svn83148 /* 662072Svn83148 * functions in this file are for version 1.0 of FMA domain services 672072Svn83148 */ 682072Svn83148 static ds_ver_t ds_vers[] = { 692072Svn83148 { 1, 0 } 702072Svn83148 }; 712072Svn83148 722072Svn83148 #define DS_NUM_VER (sizeof (ds_vers) / sizeof (ds_ver_t)) 732072Svn83148 742072Svn83148 /* 752072Svn83148 * information for each channel 762072Svn83148 */ 772072Svn83148 struct ldmsvcs_info { 782072Svn83148 pthread_mutex_t mt; 792072Svn83148 pthread_cond_t cv; 802072Svn83148 fds_channel_t fds_chan; 812072Svn83148 fds_reg_svcs_t fmas_svcs; 822072Svn83148 int cv_twait; 832072Svn83148 }; 842072Svn83148 852072Svn83148 /* 862072Svn83148 * struct listdata_s and struct poller_s are used to maintain the state of 872072Svn83148 * the poller thread. this thread is used to manage incoming messages and 882072Svn83148 * pass those messages onto the correct requesting thread. see the "poller 892072Svn83148 * functions" section for more details. 902072Svn83148 */ 912072Svn83148 struct listdata_s { 922072Svn83148 enum { 932072Svn83148 UNUSED, 942072Svn83148 PENDING, 952072Svn83148 ARRIVED 962072Svn83148 } status; 972072Svn83148 uint64_t req_num; 982072Svn83148 int fd; 992072Svn83148 size_t datalen; 1002072Svn83148 }; 1012072Svn83148 1022072Svn83148 static struct poller_s { 1032072Svn83148 pthread_mutex_t mt; 1042072Svn83148 pthread_cond_t cv; 1052072Svn83148 pthread_t polling_tid; 1062072Svn83148 int doreset; 1072072Svn83148 int doexit; 1082072Svn83148 int nclients; 1092072Svn83148 struct listdata_s **list; 1102072Svn83148 int list_len; 1112072Svn83148 int pending_count; 1122072Svn83148 } pollbase = { 1132072Svn83148 PTHREAD_MUTEX_INITIALIZER, 1142072Svn83148 PTHREAD_COND_INITIALIZER, 1152072Svn83148 0, 1162072Svn83148 1, 1172072Svn83148 0, 1182072Svn83148 0, 1192072Svn83148 NULL, 1202072Svn83148 0, 1212072Svn83148 0 1222072Svn83148 }; 1232072Svn83148 1242072Svn83148 1252072Svn83148 static struct ldmsvcs_info *channel_init(struct ldom_hdl *lhp); 1262072Svn83148 static int channel_openreset(struct ldmsvcs_info *lsp); 1272072Svn83148 static int read_msg(struct ldmsvcs_info *lsp); 1282072Svn83148 1294358Srb144127 static int 1304358Srb144127 get_smf_int_val(char *prop_nm, int min, int max, int default_val) 1314358Srb144127 { 1324358Srb144127 scf_simple_prop_t *prop; /* SMF property */ 1334358Srb144127 int64_t *valp; /* prop value ptr */ 1344358Srb144127 int64_t val; /* prop value to return */ 1354358Srb144127 1364358Srb144127 val = default_val; 1374358Srb144127 if ((prop = scf_simple_prop_get(NULL, LDM_SVC_NM, LDM_PROP_GROUP_NM, 1384358Srb144127 prop_nm)) != NULL) { 1394358Srb144127 if ((valp = scf_simple_prop_next_integer(prop)) != NULL) { 1404358Srb144127 val = *valp; 1414358Srb144127 if (val < min) 1424358Srb144127 val = min; 1434358Srb144127 else if (val > max) 1444358Srb144127 val = max; 1454358Srb144127 } 1464358Srb144127 scf_simple_prop_free(prop); 1474358Srb144127 } 1484358Srb144127 return ((int)val); 1494358Srb144127 } 1504358Srb144127 1512072Svn83148 static void 1522072Svn83148 channel_close(struct ldmsvcs_info *lsp) 1532072Svn83148 { 1542072Svn83148 (void) pthread_mutex_lock(&lsp->mt); 1552072Svn83148 1563327Svn83148 if (lsp->fds_chan.state == CHANNEL_OPEN || 1574358Srb144127 lsp->fds_chan.state == CHANNEL_READY) { 1583327Svn83148 (void) close(lsp->fds_chan.fd); 1594358Srb144127 lsp->cv_twait = get_smf_int_val(LDM_INIT_TO_PROP_NM, 1604358Srb144127 0, LDM_TIMEOUT_CEILING, LDM_INIT_WAIT_TIME); 1613327Svn83148 lsp->fds_chan.state = CHANNEL_CLOSED; 1623327Svn83148 } 1632072Svn83148 1642072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 1652072Svn83148 } 1662072Svn83148 1672072Svn83148 /* 1682072Svn83148 * read size bytes of data from a streaming fd into buf 1692072Svn83148 */ 1702072Svn83148 static int 1712072Svn83148 read_stream(int fd, void *buf, size_t size) 1722072Svn83148 { 1732072Svn83148 pollfd_t pollfd; 1742072Svn83148 ssize_t rv; 1752072Svn83148 size_t data_left; 1762072Svn83148 ptrdiff_t currentp; 1772072Svn83148 1782072Svn83148 pollfd.events = POLLIN; 1792072Svn83148 pollfd.revents = 0; 1802072Svn83148 pollfd.fd = fd; 1812072Svn83148 1822072Svn83148 currentp = (ptrdiff_t)buf; 1832072Svn83148 data_left = size; 1842072Svn83148 1852072Svn83148 /* 1862072Svn83148 * data may come in bits and pieces 1872072Svn83148 */ 1882072Svn83148 do { 1892072Svn83148 if ((rv = read(fd, (void *)currentp, data_left)) < 0) { 1902072Svn83148 if (errno == EAGAIN && poll(&pollfd, 1, -1) > 0) 1912072Svn83148 continue; /* retry */ 1922072Svn83148 else 1932072Svn83148 return (1); 1942072Svn83148 } 1952072Svn83148 1962072Svn83148 data_left -= rv; 1972072Svn83148 currentp += rv; 1982072Svn83148 } while (data_left > 0); 1992072Svn83148 2002072Svn83148 return (0); 2012072Svn83148 } 2022072Svn83148 2032072Svn83148 2042072Svn83148 /* 2052072Svn83148 * poller functions 2062072Svn83148 * 2072072Svn83148 * at init time, a thread is created for the purpose of monitoring incoming 2082072Svn83148 * messages and doing one of the following: 2092072Svn83148 * 2102072Svn83148 * 1. doing the initial handshake and version negotiation 2112072Svn83148 * 2122072Svn83148 * 2. handing incoming data off to the requesting thread (which is an fmd 2132072Svn83148 * module or scheme thread) 2142072Svn83148 */ 2152072Svn83148 static int 2162072Svn83148 poller_handle_data(int fd, size_t payloadsize) 2172072Svn83148 { 2182072Svn83148 uint64_t *req_num; 2192072Svn83148 void *pr; 2202072Svn83148 size_t prlen; 2212072Svn83148 int i; 2222072Svn83148 2232072Svn83148 prlen = sizeof (ds_data_handle_t) + sizeof (uint64_t); 2242072Svn83148 2252072Svn83148 if (payloadsize < prlen) 2262072Svn83148 return (1); 2272072Svn83148 2282072Svn83148 pr = alloca(prlen); 2292072Svn83148 2302072Svn83148 if (read_stream(fd, pr, prlen) != 0) 2312072Svn83148 return (1); 2322072Svn83148 2332072Svn83148 req_num = (uint64_t *)((ptrdiff_t)pr + sizeof (ds_data_handle_t)); 2342072Svn83148 2352072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 2362072Svn83148 2372072Svn83148 for (i = 0; i < pollbase.list_len; i++) { 2382072Svn83148 if (pollbase.list[i]->req_num == *req_num) { 2392072Svn83148 ASSERT(pollbase.list[i]->status == PENDING); 2402072Svn83148 2412072Svn83148 pollbase.list[i]->status = ARRIVED; 2422072Svn83148 pollbase.list[i]->fd = fd; 2432072Svn83148 pollbase.list[i]->datalen = payloadsize - prlen; 2442072Svn83148 2452072Svn83148 pollbase.pending_count--; 2462072Svn83148 (void) pthread_cond_broadcast(&pollbase.cv); 2472072Svn83148 break; 2482072Svn83148 } 2492072Svn83148 } 2502072Svn83148 2512072Svn83148 /* 2522072Svn83148 * now wait for receiving thread to read in the data 2532072Svn83148 */ 2542072Svn83148 if (i < pollbase.list_len) { 2552072Svn83148 while (pollbase.list[i]->status == ARRIVED) 2562072Svn83148 (void) pthread_cond_wait(&pollbase.cv, &pollbase.mt); 2572072Svn83148 } 2582072Svn83148 2592072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 2602072Svn83148 2612072Svn83148 return (0); 2622072Svn83148 } 2632072Svn83148 2642072Svn83148 2652072Svn83148 /* 2662072Svn83148 * note that this function is meant to handle only DS_DATA messages 2672072Svn83148 */ 2682072Svn83148 static int 2692072Svn83148 poller_recv_data(struct ldom_hdl *lhp, uint64_t req_num, int index, 2702072Svn83148 void **resp, size_t *resplen) 2712072Svn83148 { 2722072Svn83148 struct timespec twait; 2732072Svn83148 int ier; 2742072Svn83148 2752072Svn83148 ier = 0; 2762072Svn83148 twait.tv_sec = time(NULL) + lhp->lsinfo->cv_twait; 2772072Svn83148 twait.tv_nsec = 0; 2782072Svn83148 2792072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 2802072Svn83148 2812072Svn83148 ASSERT(pollbase.list[index]->req_num == req_num); 2822072Svn83148 2832072Svn83148 while (pollbase.list[index]->status == PENDING && 2842072Svn83148 pollbase.doreset == 0 && ier == 0) 2852072Svn83148 ier = pthread_cond_timedwait(&pollbase.cv, &pollbase.mt, 2864358Srb144127 &twait); 2872072Svn83148 2882072Svn83148 if (ier == 0) { 2892072Svn83148 if (pollbase.doreset == 0) { 2902072Svn83148 ASSERT(pollbase.list[index]->status == ARRIVED); 2912072Svn83148 2922072Svn83148 /* 2932072Svn83148 * need to add req_num to beginning of resp 2942072Svn83148 */ 2952072Svn83148 *resplen = pollbase.list[index]->datalen + 2964358Srb144127 sizeof (uint64_t); 2972072Svn83148 *resp = lhp->allocp(*resplen); 2982072Svn83148 *((uint64_t *)*resp) = req_num; 2992072Svn83148 3002072Svn83148 if (read_stream(pollbase.list[index]->fd, 3014358Srb144127 (void *)((ptrdiff_t)*resp + sizeof (uint64_t)), 3024358Srb144127 *resplen - sizeof (uint64_t)) != 0) 3032072Svn83148 ier = ETIMEDOUT; 3042072Svn83148 3052072Svn83148 pollbase.list[index]->status = UNUSED; 3062072Svn83148 pollbase.list[index]->req_num = 0; 3072072Svn83148 (void) pthread_cond_broadcast(&pollbase.cv); 3082072Svn83148 } else { 3092072Svn83148 if (--(pollbase.pending_count) == 0) 3102072Svn83148 (void) pthread_cond_broadcast(&pollbase.cv); 3112072Svn83148 } 3122072Svn83148 } 3132072Svn83148 3142072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 3152072Svn83148 3162072Svn83148 ASSERT(ier == 0 || ier == ETIMEDOUT); 3172072Svn83148 3182072Svn83148 return (ier); 3192072Svn83148 } 3202072Svn83148 3212072Svn83148 3222072Svn83148 static void 3232072Svn83148 poller_add_client(void) 3242072Svn83148 { 3252072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 3262072Svn83148 pollbase.nclients++; 3272072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 3282072Svn83148 } 3292072Svn83148 3302072Svn83148 3312072Svn83148 static void 3322072Svn83148 poller_remove_client(void) 3332072Svn83148 { 3342072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 3352072Svn83148 pollbase.nclients--; 3362072Svn83148 ASSERT(pollbase.nclients >= 0); 3372072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 3382072Svn83148 } 3392072Svn83148 3402072Svn83148 3412072Svn83148 static int 342*8634SVuong.Nguyen@Sun.COM poller_add_pending(uint64_t req_num) 3432072Svn83148 { 3442072Svn83148 int newlen, index, i, j; 3452072Svn83148 3462072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 3472072Svn83148 pollbase.pending_count++; 3482072Svn83148 3492072Svn83148 for (j = 0, index = -1; j < 2 && index == -1; j++) { 3502072Svn83148 for (i = 0; i < pollbase.list_len; i++) { 3512072Svn83148 if (pollbase.list[i]->status == UNUSED) { 3522072Svn83148 pollbase.list[i]->status = PENDING; 3532072Svn83148 pollbase.list[i]->req_num = req_num; 3542072Svn83148 pollbase.list[i]->datalen = 0; 3552072Svn83148 index = i; 3562072Svn83148 break; 3572072Svn83148 } 3582072Svn83148 } 3592072Svn83148 3602072Svn83148 if (index == -1) { 3612072Svn83148 struct listdata_s **newlist, **oldlist; 3622072Svn83148 3632072Svn83148 /* 3642072Svn83148 * get to this point if list is not long enough. 3652072Svn83148 * check for a runaway list. since requests are 3662072Svn83148 * synchronous (clients send a request and need to 3672072Svn83148 * wait for the result before returning) the size 3682072Svn83148 * of the list cannot be much more than the number 3692072Svn83148 * of clients. 3702072Svn83148 */ 3712072Svn83148 ASSERT(pollbase.list_len < pollbase.nclients + 1); 3722072Svn83148 3732072Svn83148 newlen = pollbase.list_len + 5; 374*8634SVuong.Nguyen@Sun.COM newlist = ldom_alloc(newlen * 375*8634SVuong.Nguyen@Sun.COM sizeof (struct listdata_s *)); 3762072Svn83148 3772072Svn83148 for (i = 0; i < pollbase.list_len; i++) 3782072Svn83148 newlist[i] = pollbase.list[i]; 3792072Svn83148 3802072Svn83148 oldlist = pollbase.list; 3812072Svn83148 pollbase.list = newlist; 382*8634SVuong.Nguyen@Sun.COM ldom_free(oldlist, pollbase.list_len * 383*8634SVuong.Nguyen@Sun.COM sizeof (struct listdata_s *)); 3842072Svn83148 3852072Svn83148 for (i = pollbase.list_len; i < newlen; i++) { 3862072Svn83148 pollbase.list[i] = 387*8634SVuong.Nguyen@Sun.COM ldom_alloc(sizeof (struct listdata_s)); 3882072Svn83148 pollbase.list[i]->status = UNUSED; 3892072Svn83148 } 3902072Svn83148 3912072Svn83148 pollbase.list_len = newlen; 3922072Svn83148 } 3932072Svn83148 } 3942072Svn83148 3952072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 3962072Svn83148 ASSERT(index != -1); 3972072Svn83148 3982072Svn83148 return (index); 3992072Svn83148 } 4002072Svn83148 4012072Svn83148 4022072Svn83148 static void 4032072Svn83148 poller_delete_pending(uint64_t req_num, int index) 4042072Svn83148 { 4052072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 4062072Svn83148 4072072Svn83148 ASSERT(pollbase.list[index]->req_num == req_num); 4082072Svn83148 pollbase.list[index]->status = UNUSED; 4092072Svn83148 4102072Svn83148 if (--(pollbase.pending_count) == 0 && pollbase.doreset == 1) 4112072Svn83148 (void) pthread_cond_broadcast(&pollbase.cv); 4122072Svn83148 4132072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 4142072Svn83148 } 4152072Svn83148 4162072Svn83148 4172072Svn83148 static void 418*8634SVuong.Nguyen@Sun.COM poller_shutdown(boolean_t wait) 4192072Svn83148 { 4202072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 4212072Svn83148 4222072Svn83148 pollbase.doexit = 1; 4232072Svn83148 4242072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 425*8634SVuong.Nguyen@Sun.COM 426*8634SVuong.Nguyen@Sun.COM if (wait == B_TRUE) { 427*8634SVuong.Nguyen@Sun.COM /* stop the poller thread and wait for it to end */ 428*8634SVuong.Nguyen@Sun.COM (void) pthread_kill(pollbase.polling_tid, SIGTERM); 429*8634SVuong.Nguyen@Sun.COM (void) pthread_join(pollbase.polling_tid, NULL); 430*8634SVuong.Nguyen@Sun.COM } 4312072Svn83148 } 4322072Svn83148 4332072Svn83148 4342072Svn83148 /* 4352072Svn83148 * perform the polling of incoming messages. manage any resets (usually 4362072Svn83148 * due to one end of the connection being closed) as well as exit 4372072Svn83148 * conditions. 4382072Svn83148 */ 4392072Svn83148 static void * 4402072Svn83148 poller_loop(void *arg) 4412072Svn83148 { 4422072Svn83148 struct ldmsvcs_info *lsp; 4432072Svn83148 pollfd_t pollfd; 4442072Svn83148 int ier; 4452072Svn83148 4462072Svn83148 lsp = (struct ldmsvcs_info *)arg; 4472072Svn83148 4482072Svn83148 for (;;) { 4492072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 4502072Svn83148 4512072Svn83148 if (pollbase.doexit) { 4522072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 4532072Svn83148 break; 4542072Svn83148 } 4552072Svn83148 4562072Svn83148 if (pollbase.doreset) { 4572072Svn83148 int i; 4582072Svn83148 4592072Svn83148 while (pollbase.pending_count > 0) 4602072Svn83148 (void) pthread_cond_wait(&pollbase.cv, 4614358Srb144127 &pollbase.mt); 4622072Svn83148 4632072Svn83148 ASSERT(pollbase.pending_count == 0); 4642072Svn83148 for (i = 0; i < pollbase.list_len; i++) 4652072Svn83148 pollbase.list[i]->status = UNUSED; 4662072Svn83148 4672072Svn83148 pollbase.doreset = 0; 4682072Svn83148 } 4692072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 4702072Svn83148 4712072Svn83148 if ((ier = channel_openreset(lsp)) == 1) { 4722072Svn83148 continue; 4732072Svn83148 } else if (ier == 2) { 4742072Svn83148 /* 4752072Svn83148 * start exit preparations 4762072Svn83148 */ 477*8634SVuong.Nguyen@Sun.COM poller_shutdown(B_FALSE); 4782072Svn83148 continue; 4792072Svn83148 } 4802072Svn83148 4812072Svn83148 pollfd.events = POLLIN; 4822072Svn83148 pollfd.revents = 0; 4832072Svn83148 pollfd.fd = lsp->fds_chan.fd; 4842072Svn83148 4852072Svn83148 if (poll(&pollfd, 1, -1) <= 0 || read_msg(lsp) != 0) { 4862072Svn83148 /* 4872072Svn83148 * read error and/or fd got closed 4882072Svn83148 */ 4892072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 4902072Svn83148 pollbase.doreset = 1; 4912072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 4922072Svn83148 4932072Svn83148 channel_close(lsp); 4942072Svn83148 } 4952072Svn83148 } 4962072Svn83148 4972072Svn83148 return (NULL); 4982072Svn83148 } 4992072Svn83148 5002072Svn83148 5012072Svn83148 /* 5022072Svn83148 * create the polling thread 5032072Svn83148 */ 5042072Svn83148 static int 5052072Svn83148 poller_init(struct ldmsvcs_info *lsp) 5062072Svn83148 { 5072072Svn83148 int rc = 0; 5082072Svn83148 5092072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 5102072Svn83148 5112072Svn83148 if (pollbase.polling_tid == 0) { 512*8634SVuong.Nguyen@Sun.COM pthread_attr_t *attr = NULL; 5132072Svn83148 5142072Svn83148 /* 515*8634SVuong.Nguyen@Sun.COM * create a joinable polling thread for receiving messages 5162072Svn83148 */ 517*8634SVuong.Nguyen@Sun.COM if (pthread_create(&pollbase.polling_tid, attr, 5184358Srb144127 poller_loop, lsp) != 0) 5192072Svn83148 rc = 1; 5202072Svn83148 } 5212072Svn83148 5222072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 5232072Svn83148 5242072Svn83148 return (rc); 5252072Svn83148 } 5262072Svn83148 527*8634SVuong.Nguyen@Sun.COM /* 528*8634SVuong.Nguyen@Sun.COM * Cleanup the polling thread 529*8634SVuong.Nguyen@Sun.COM */ 530*8634SVuong.Nguyen@Sun.COM static void 531*8634SVuong.Nguyen@Sun.COM poller_fini(void) 532*8634SVuong.Nguyen@Sun.COM { 533*8634SVuong.Nguyen@Sun.COM int i; 534*8634SVuong.Nguyen@Sun.COM 535*8634SVuong.Nguyen@Sun.COM /* stop the poller thread */ 536*8634SVuong.Nguyen@Sun.COM poller_shutdown(B_TRUE); 537*8634SVuong.Nguyen@Sun.COM 538*8634SVuong.Nguyen@Sun.COM (void) pthread_mutex_lock(&pollbase.mt); 539*8634SVuong.Nguyen@Sun.COM 540*8634SVuong.Nguyen@Sun.COM /* Free up the list of outstanding requests */ 541*8634SVuong.Nguyen@Sun.COM if (pollbase.list != NULL) { 542*8634SVuong.Nguyen@Sun.COM for (i = 0; i < pollbase.list_len; i++) { 543*8634SVuong.Nguyen@Sun.COM if (pollbase.list[i]) { 544*8634SVuong.Nguyen@Sun.COM ldom_free(pollbase.list[i], 545*8634SVuong.Nguyen@Sun.COM sizeof (struct listdata_s)); 546*8634SVuong.Nguyen@Sun.COM } 547*8634SVuong.Nguyen@Sun.COM } 548*8634SVuong.Nguyen@Sun.COM ldom_free(pollbase.list, pollbase.list_len * 549*8634SVuong.Nguyen@Sun.COM sizeof (struct listdata_s *)); 550*8634SVuong.Nguyen@Sun.COM pollbase.list = NULL; 551*8634SVuong.Nguyen@Sun.COM pollbase.list_len = 0; 552*8634SVuong.Nguyen@Sun.COM } 553*8634SVuong.Nguyen@Sun.COM 554*8634SVuong.Nguyen@Sun.COM (void) pthread_mutex_unlock(&pollbase.mt); 555*8634SVuong.Nguyen@Sun.COM } 5562072Svn83148 5572072Svn83148 /* 5582072Svn83148 * utilities for message handlers 5592072Svn83148 */ 5602072Svn83148 static int 5612072Svn83148 fds_send(struct ldmsvcs_info *lsp, void *msg, size_t msglen) 5622072Svn83148 { 5632072Svn83148 static pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER; 5642072Svn83148 5652072Svn83148 (void) pthread_mutex_lock(&mt); 5662072Svn83148 5672072Svn83148 if (write(lsp->fds_chan.fd, msg, msglen) != msglen) { 5682072Svn83148 channel_close(lsp); 5692072Svn83148 (void) pthread_mutex_unlock(&mt); 5702072Svn83148 return (ETIMEDOUT); 5712072Svn83148 } 5722072Svn83148 5732072Svn83148 (void) pthread_mutex_unlock(&mt); 5742072Svn83148 return (0); 5752072Svn83148 } 5762072Svn83148 5772072Svn83148 5782072Svn83148 /* 5792072Svn83148 * Find the max and min version supported 5802072Svn83148 */ 5812072Svn83148 static void 5822072Svn83148 fds_min_max_versions(uint16_t *min_major, uint16_t *max_major) 5832072Svn83148 { 5842072Svn83148 int i; 5852072Svn83148 5862072Svn83148 *min_major = ds_vers[0].major; 5872072Svn83148 *max_major = *min_major; 5882072Svn83148 5892072Svn83148 for (i = 1; i < DS_NUM_VER; i++) { 5902072Svn83148 if (ds_vers[i].major < *min_major) 5912072Svn83148 *min_major = ds_vers[i].major; 5922072Svn83148 5932072Svn83148 if (ds_vers[i].major > *max_major) 5942072Svn83148 *max_major = ds_vers[i].major; 5952072Svn83148 } 5962072Svn83148 } 5972072Svn83148 5982072Svn83148 /* 5992072Svn83148 * check whether the major and minor numbers requested by remote ds client 6002072Svn83148 * can be satisfied. if the requested major is supported, true is 6012072Svn83148 * returned, and the agreed minor is returned in new_minor. if the 6022072Svn83148 * requested major is not supported, the routine returns false, and the 6032072Svn83148 * closest major is returned in *new_major, upon which the ds client should 6042072Svn83148 * renegotiate. the closest major is the just lower that the requested 6052072Svn83148 * major number. 6062072Svn83148 */ 6072072Svn83148 static boolean_t 6082072Svn83148 fds_negotiate_version(uint16_t req_major, uint16_t *new_majorp, 6092072Svn83148 uint16_t *new_minorp) 6102072Svn83148 { 6112072Svn83148 int i = 0; 6122072Svn83148 uint16_t major, lower_major; 6132072Svn83148 uint16_t min_major, max_major; 6142072Svn83148 boolean_t found_match = B_FALSE; 6152072Svn83148 6162072Svn83148 fds_min_max_versions(&min_major, &max_major); 6172072Svn83148 6182072Svn83148 /* 6192072Svn83148 * if the minimum version supported is greater than the version 6202072Svn83148 * requested, return the lowest version supported 6212072Svn83148 */ 6222072Svn83148 if (min_major > req_major) { 6232072Svn83148 *new_majorp = min_major; 6242072Svn83148 return (B_FALSE); 6252072Svn83148 } 6262072Svn83148 6272072Svn83148 /* 6282072Svn83148 * if the largest version supported is lower than the version 6292072Svn83148 * requested, return the largest version supported 6302072Svn83148 */ 6312072Svn83148 if (max_major < req_major) { 6322072Svn83148 *new_majorp = max_major; 6332072Svn83148 return (B_FALSE); 6342072Svn83148 } 6352072Svn83148 6362072Svn83148 /* 6372072Svn83148 * now we know that the requested version lies between the min and 6382072Svn83148 * max versions supported. check if the requested major can be 6392072Svn83148 * found in supported versions. 6402072Svn83148 */ 6412072Svn83148 lower_major = min_major; 6422072Svn83148 for (i = 0; i < DS_NUM_VER; i++) { 6432072Svn83148 major = ds_vers[i].major; 6442072Svn83148 if (major == req_major) { 6452072Svn83148 found_match = B_TRUE; 6462072Svn83148 *new_minorp = ds_vers[i].minor; 6472072Svn83148 *new_majorp = major; 6482072Svn83148 break; 6492072Svn83148 } else if ((major < req_major) && (major > lower_major)) 6502072Svn83148 lower_major = major; 6512072Svn83148 } 6522072Svn83148 6532072Svn83148 /* 6542072Svn83148 * If no match is found, return the closest available number 6552072Svn83148 */ 6562072Svn83148 if (!found_match) 6572072Svn83148 *new_majorp = lower_major; 6582072Svn83148 6592072Svn83148 return (found_match); 6602072Svn83148 } 6612072Svn83148 6622072Svn83148 6632072Svn83148 /* 6642072Svn83148 * return 0 if service is added; 1 if service is a duplicate 6652072Svn83148 */ 6662072Svn83148 static int 6672072Svn83148 fds_svc_add(struct ldmsvcs_info *lsp, ds_reg_req_t *req, int minor) 6682072Svn83148 { 6692072Svn83148 fds_svc_t *svc; 6702072Svn83148 int i, rc; 6712072Svn83148 6722072Svn83148 svc = NULL; 6732072Svn83148 for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) { 6742072Svn83148 if (strcmp(lsp->fmas_svcs.tbl[i]->name, req->svc_id) == 0) { 6752072Svn83148 svc = lsp->fmas_svcs.tbl[i]; 6762072Svn83148 break; 6772072Svn83148 } 6782072Svn83148 } 6792072Svn83148 6802072Svn83148 if (svc == NULL) 6812072Svn83148 return (0); /* we don't need this service */ 6822072Svn83148 6832072Svn83148 (void) pthread_mutex_lock(&lsp->fmas_svcs.mt); 6842072Svn83148 6852072Svn83148 /* 6862072Svn83148 * duplicate registration is OK --- we retain the previous entry 6872072Svn83148 * (which has not been unregistered anyway) 6882072Svn83148 */ 6892072Svn83148 if (svc->state == DS_SVC_ACTIVE) { 6902072Svn83148 rc = 1; 6912072Svn83148 } else { 6922072Svn83148 svc->state = DS_SVC_ACTIVE; 6932072Svn83148 svc->hdl = req->svc_handle; 6942072Svn83148 svc->ver.major = req->major_vers; 6952072Svn83148 svc->ver.minor = minor; 6962072Svn83148 6972072Svn83148 rc = 0; 6982072Svn83148 (void) pthread_cond_broadcast(&lsp->fmas_svcs.cv); 6992072Svn83148 } 7002072Svn83148 7012072Svn83148 (void) pthread_mutex_unlock(&lsp->fmas_svcs.mt); 7022072Svn83148 7032072Svn83148 return (rc); 7042072Svn83148 } 7052072Svn83148 7062072Svn83148 7072072Svn83148 static void 7082072Svn83148 fds_svc_reset(struct ldmsvcs_info *lsp, int index) 7092072Svn83148 { 7102072Svn83148 int i, start, end; 7112072Svn83148 7122072Svn83148 if (index >= 0) { 7132072Svn83148 start = index; 7142072Svn83148 end = index + 1; 7152072Svn83148 } else { 7162072Svn83148 start = 0; 7172072Svn83148 end = lsp->fmas_svcs.nsvcs; 7182072Svn83148 } 7192072Svn83148 7202072Svn83148 (void) pthread_mutex_lock(&lsp->fmas_svcs.mt); 7212072Svn83148 7222072Svn83148 for (i = start; i < end; i++) { 7232072Svn83148 lsp->fmas_svcs.tbl[i]->hdl = 0; 7242072Svn83148 lsp->fmas_svcs.tbl[i]->state = DS_SVC_INVAL; 7252072Svn83148 lsp->fmas_svcs.tbl[i]->ver.major = 7264358Srb144127 ds_vers[DS_NUM_VER - 1].major; 7272072Svn83148 lsp->fmas_svcs.tbl[i]->ver.minor = 7284358Srb144127 ds_vers[DS_NUM_VER - 1].minor; 7292072Svn83148 } 7302072Svn83148 7312072Svn83148 (void) pthread_mutex_unlock(&lsp->fmas_svcs.mt); 7322072Svn83148 } 7332072Svn83148 7342072Svn83148 7352072Svn83148 static int 7362072Svn83148 fds_svc_remove(struct ldmsvcs_info *lsp, ds_svc_hdl_t svc_handle) 7372072Svn83148 { 7382072Svn83148 int i; 7392072Svn83148 7402072Svn83148 for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) { 7412072Svn83148 if (lsp->fmas_svcs.tbl[i]->hdl == svc_handle) { 7422072Svn83148 fds_svc_reset(lsp, i); 7432072Svn83148 return (0); 7442072Svn83148 } 7452072Svn83148 } 7462072Svn83148 7472072Svn83148 return (1); 7482072Svn83148 } 7492072Svn83148 7502072Svn83148 7512072Svn83148 /* 7522072Svn83148 * message handlers 7532072Svn83148 */ 7542072Svn83148 /*ARGSUSED*/ 7552072Svn83148 static void 7562072Svn83148 ds_handle_msg_noop(struct ldmsvcs_info *lsp, void *buf, size_t len) 7572072Svn83148 { 7582072Svn83148 } 7592072Svn83148 7602072Svn83148 static void 7612072Svn83148 ds_handle_init_req(struct ldmsvcs_info *lsp, void *buf, size_t len) 7622072Svn83148 { 7632072Svn83148 ds_init_req_t *req; 7642072Svn83148 uint16_t new_major, new_minor; 7652072Svn83148 size_t msglen; 7662072Svn83148 7672072Svn83148 req = (ds_init_req_t *)buf; 7682072Svn83148 7692072Svn83148 /* sanity check the incoming message */ 7702072Svn83148 if (len != sizeof (ds_init_req_t)) { 7712072Svn83148 channel_close(lsp); 7722072Svn83148 return; 7732072Svn83148 } 7742072Svn83148 7752072Svn83148 /* 7762072Svn83148 * Check version info. ACK only if the major numbers exactly 7772072Svn83148 * match. The service entity can retry with a new minor 7782072Svn83148 * based on the response sent as part of the NACK. 7792072Svn83148 */ 7802072Svn83148 if (fds_negotiate_version(req->major_vers, &new_major, &new_minor)) { 7812072Svn83148 ds_hdr_t *H; 7822072Svn83148 ds_init_ack_t *R; 7832072Svn83148 7842072Svn83148 msglen = sizeof (ds_hdr_t) + sizeof (ds_init_ack_t); 7852072Svn83148 H = alloca(msglen); 7862072Svn83148 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 7872072Svn83148 7882072Svn83148 H->msg_type = DS_INIT_ACK; 7892072Svn83148 H->payload_len = sizeof (ds_init_ack_t); 7902072Svn83148 R->minor_vers = MIN(new_minor, req->minor_vers); 7912072Svn83148 7922072Svn83148 if (fds_send(lsp, H, msglen) != 0) 7932072Svn83148 return; 7942072Svn83148 7952072Svn83148 (void) pthread_mutex_lock(&lsp->mt); 7962072Svn83148 ASSERT(lsp->fds_chan.state == CHANNEL_OPEN); 7972072Svn83148 lsp->fds_chan.state = CHANNEL_READY; 7983327Svn83148 7993327Svn83148 /* 8003327Svn83148 * Now the channel is ready after the handshake completes. 8013327Svn83148 * Reset the timeout to a smaller value for receiving messages 8023327Svn83148 * from the domain services. 8033327Svn83148 */ 8044358Srb144127 lsp->cv_twait = get_smf_int_val(LDM_RUNNING_TO_PROP_NM, 8054358Srb144127 0, LDM_TIMEOUT_CEILING, LDM_RUNNING_WAIT_TIME); 8063327Svn83148 8072072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 8082072Svn83148 } else { 8092072Svn83148 ds_hdr_t *H; 8102072Svn83148 ds_init_nack_t *R; 8112072Svn83148 8122072Svn83148 msglen = sizeof (ds_hdr_t) + sizeof (ds_init_nack_t); 8132072Svn83148 H = alloca(msglen); 8142072Svn83148 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 8152072Svn83148 8162072Svn83148 H->msg_type = DS_INIT_NACK; 8172072Svn83148 H->payload_len = sizeof (ds_init_nack_t); 8182072Svn83148 R->major_vers = new_major; 8192072Svn83148 8202072Svn83148 (void) fds_send(lsp, H, msglen); 8212072Svn83148 /* 8222072Svn83148 * do not update state; remote end may attempt to initiate 8232072Svn83148 * connection with a different version 8242072Svn83148 */ 8252072Svn83148 } 8262072Svn83148 } 8272072Svn83148 8282072Svn83148 8292072Svn83148 /*ARGSUSED*/ 8302072Svn83148 static void 8312072Svn83148 ds_handle_reg_req(struct ldmsvcs_info *lsp, void *buf, size_t len) 8322072Svn83148 { 8332072Svn83148 ds_reg_req_t *req; 8342072Svn83148 char *msg; 8352072Svn83148 uint16_t new_major, new_minor; 8362072Svn83148 size_t msglen; 8372072Svn83148 int dup_svcreg = 0; 8382072Svn83148 8392072Svn83148 req = (ds_reg_req_t *)buf; 8402072Svn83148 msg = (char *)req->svc_id; 8412072Svn83148 8422072Svn83148 /* 8432072Svn83148 * Service must be NULL terminated 8442072Svn83148 */ 8452072Svn83148 if (req->svc_id == NULL || strlen(req->svc_id) == 0 || 8462072Svn83148 msg[strlen(req->svc_id)] != '\0') { 8472072Svn83148 channel_close(lsp); 8482072Svn83148 return; 8492072Svn83148 } 8502072Svn83148 8512072Svn83148 if (fds_negotiate_version(req->major_vers, &new_major, &new_minor) && 8522072Svn83148 (dup_svcreg = fds_svc_add(lsp, req, 8534358Srb144127 MIN(new_minor, req->minor_vers))) == 0) { 8542072Svn83148 8552072Svn83148 /* 8562072Svn83148 * Check version info. ACK only if the major numbers 8572072Svn83148 * exactly match. The service entity can retry with a new 8582072Svn83148 * minor based on the response sent as part of the NACK. 8592072Svn83148 */ 8602072Svn83148 ds_hdr_t *H; 8612072Svn83148 ds_reg_ack_t *R; 8622072Svn83148 8632072Svn83148 msglen = sizeof (ds_hdr_t) + sizeof (ds_reg_ack_t); 8642072Svn83148 H = alloca(msglen); 8652072Svn83148 bzero(H, msglen); 8662072Svn83148 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 8672072Svn83148 8682072Svn83148 H->msg_type = DS_REG_ACK; 8692072Svn83148 H->payload_len = sizeof (ds_reg_ack_t); 8702072Svn83148 R->svc_handle = req->svc_handle; 8712072Svn83148 R->minor_vers = MIN(new_minor, req->minor_vers); 8722072Svn83148 8732072Svn83148 (void) fds_send(lsp, H, msglen); 8742072Svn83148 } else { 8752072Svn83148 ds_hdr_t *H; 8762072Svn83148 ds_reg_nack_t *R; 8772072Svn83148 8782072Svn83148 msglen = sizeof (ds_hdr_t) + sizeof (ds_reg_nack_t); 8792072Svn83148 H = alloca(msglen); 8802072Svn83148 bzero(H, msglen); 8812072Svn83148 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 8822072Svn83148 8832072Svn83148 H->msg_type = DS_REG_NACK; 8842072Svn83148 H->payload_len = sizeof (ds_reg_nack_t); 8852072Svn83148 R->svc_handle = req->svc_handle; 8862072Svn83148 R->major_vers = new_major; 8872072Svn83148 8882072Svn83148 if (dup_svcreg) 8892072Svn83148 R->result = DS_REG_DUP; 8902072Svn83148 else 8912072Svn83148 R->result = DS_REG_VER_NACK; 8922072Svn83148 8932072Svn83148 (void) fds_send(lsp, H, msglen); 8942072Svn83148 } 8952072Svn83148 } 8962072Svn83148 8972072Svn83148 8982072Svn83148 /*ARGSUSED*/ 8992072Svn83148 static void 9002072Svn83148 ds_handle_unreg(struct ldmsvcs_info *lsp, void *buf, size_t len) 9012072Svn83148 { 9022072Svn83148 ds_unreg_req_t *req; 9032072Svn83148 size_t msglen; 9042072Svn83148 9052072Svn83148 req = (ds_unreg_req_t *)buf; 9062072Svn83148 9072072Svn83148 if (fds_svc_remove(lsp, req->svc_handle) == 0) { 9082072Svn83148 ds_hdr_t *H; 9092072Svn83148 ds_unreg_ack_t *R; 9102072Svn83148 9112072Svn83148 msglen = sizeof (ds_hdr_t) + sizeof (ds_unreg_ack_t); 9122072Svn83148 H = alloca(msglen); 9132072Svn83148 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 9142072Svn83148 9152072Svn83148 H->msg_type = DS_REG_ACK; 9162072Svn83148 H->payload_len = sizeof (ds_unreg_ack_t); 9172072Svn83148 R->svc_handle = req->svc_handle; 9182072Svn83148 9192072Svn83148 (void) fds_send(lsp, H, msglen); 9202072Svn83148 } else { 9212072Svn83148 ds_hdr_t *H; 9222072Svn83148 ds_unreg_nack_t *R; 9232072Svn83148 9242072Svn83148 msglen = sizeof (ds_hdr_t) + sizeof (ds_unreg_nack_t); 9252072Svn83148 H = alloca(msglen); 9262072Svn83148 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 9272072Svn83148 9282072Svn83148 H->msg_type = DS_REG_NACK; 9292072Svn83148 H->payload_len = sizeof (ds_unreg_nack_t); 9302072Svn83148 R->svc_handle = req->svc_handle; 9312072Svn83148 9322072Svn83148 (void) fds_send(lsp, H, msglen); 9332072Svn83148 } 9342072Svn83148 } 9352072Svn83148 9362072Svn83148 9372072Svn83148 /* 9382072Svn83148 * Message handler lookup table (v1.0 only for now) Future 9392072Svn83148 * versions can add their own lookup table. 9402072Svn83148 */ 9412072Svn83148 typedef void (*ds_msg_handler_t)(struct ldmsvcs_info *lsp, 9422072Svn83148 void *buf, size_t len); 9432072Svn83148 9442072Svn83148 static const ds_msg_handler_t ds_msg_handlers[] = { 9452072Svn83148 ds_handle_init_req, /* DS_INIT_REQ */ 9462072Svn83148 ds_handle_msg_noop, /* DS_INIT_ACK */ 9472072Svn83148 ds_handle_msg_noop, /* DS_INIT_NACK */ 9482072Svn83148 ds_handle_reg_req, /* DS_REG_REQ */ 9492072Svn83148 ds_handle_msg_noop, /* DS_REG_ACK */ 9502072Svn83148 ds_handle_msg_noop, /* DS_REG_NACK */ 9512072Svn83148 ds_handle_unreg, /* DS_UNREG */ 9522072Svn83148 ds_handle_msg_noop, /* DS_UNREG_ACK */ 9532072Svn83148 ds_handle_msg_noop, /* DS_UNREG_NACK */ 9542072Svn83148 ds_handle_msg_noop, /* DS_DATA */ 9552072Svn83148 ds_handle_msg_noop /* DS_NACK */ 9562072Svn83148 }; 9572072Svn83148 9582072Svn83148 9592072Svn83148 /* 9602072Svn83148 * message and service internal functions 9612072Svn83148 */ 9622072Svn83148 static void 963*8634SVuong.Nguyen@Sun.COM fds_svc_alloc(struct ldmsvcs_info *lsp) 9642072Svn83148 { 9652072Svn83148 int i; 9667850SVuong.Nguyen@Sun.COM static char *name[] = { LDM_DS_NAME_CPU, LDM_DS_NAME_MEM, 9677850SVuong.Nguyen@Sun.COM LDM_DS_NAME_PRI, LDM_DS_NAME_IOD, NULL }; 9682072Svn83148 9692072Svn83148 (void) pthread_mutex_init(&lsp->fmas_svcs.mt, NULL); 9702072Svn83148 (void) pthread_cond_init(&lsp->fmas_svcs.cv, NULL); 9712072Svn83148 9722072Svn83148 for (lsp->fmas_svcs.nsvcs = 0; name[lsp->fmas_svcs.nsvcs] != NULL; 9732072Svn83148 lsp->fmas_svcs.nsvcs++) 9742072Svn83148 ; 9752072Svn83148 976*8634SVuong.Nguyen@Sun.COM lsp->fmas_svcs.tbl = (fds_svc_t **)ldom_alloc(sizeof (fds_svc_t *) * 9774358Srb144127 lsp->fmas_svcs.nsvcs); 9782072Svn83148 9792072Svn83148 for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) { 9802072Svn83148 lsp->fmas_svcs.tbl[i] = 981*8634SVuong.Nguyen@Sun.COM (fds_svc_t *)ldom_alloc(sizeof (fds_svc_t)); 9822072Svn83148 bzero(lsp->fmas_svcs.tbl[i], sizeof (fds_svc_t)); 9832072Svn83148 lsp->fmas_svcs.tbl[i]->name = name[i]; 9842072Svn83148 } 9852072Svn83148 } 9862072Svn83148 9872072Svn83148 9882072Svn83148 static fds_svc_t * 9892072Svn83148 fds_svc_lookup(struct ldmsvcs_info *lsp, char *name) 9902072Svn83148 { 9912072Svn83148 struct timespec twait; 9922072Svn83148 fds_svc_t *svc; 9932072Svn83148 int i, ier; 9942072Svn83148 9952072Svn83148 if (pthread_mutex_lock(&lsp->fmas_svcs.mt) == EINVAL) 9962072Svn83148 return (NULL); /* uninitialized or destroyed mutex */ 9972072Svn83148 9982072Svn83148 svc = NULL; 9992072Svn83148 for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) { 10002072Svn83148 if (strcmp(lsp->fmas_svcs.tbl[i]->name, name) == 0) { 10012072Svn83148 svc = lsp->fmas_svcs.tbl[i]; 10022072Svn83148 break; 10032072Svn83148 } 10042072Svn83148 } 10052072Svn83148 10062072Svn83148 ASSERT(svc != NULL); 10072072Svn83148 10087850SVuong.Nguyen@Sun.COM if (svc->state == DS_SVC_INACTIVE) { 10097850SVuong.Nguyen@Sun.COM /* service is not registered */ 10107850SVuong.Nguyen@Sun.COM ier = ETIMEDOUT; 10117850SVuong.Nguyen@Sun.COM } else { 10127850SVuong.Nguyen@Sun.COM ier = 0; 10137850SVuong.Nguyen@Sun.COM twait.tv_sec = time(NULL) + lsp->cv_twait; 10147850SVuong.Nguyen@Sun.COM twait.tv_nsec = 0; 10152072Svn83148 10167850SVuong.Nguyen@Sun.COM while (svc->state != DS_SVC_ACTIVE && ier == 0 && 10177850SVuong.Nguyen@Sun.COM lsp->fds_chan.state != CHANNEL_UNUSABLE) 10187850SVuong.Nguyen@Sun.COM ier = pthread_cond_timedwait(&lsp->fmas_svcs.cv, 10197850SVuong.Nguyen@Sun.COM &lsp->fmas_svcs.mt, &twait); 10207850SVuong.Nguyen@Sun.COM 10217850SVuong.Nguyen@Sun.COM /* 10227850SVuong.Nguyen@Sun.COM * By now, the ds service should have registered already. 10237850SVuong.Nguyen@Sun.COM * If it does not, ldmd probably does not support this service. 10247850SVuong.Nguyen@Sun.COM * Then mark the service state as inactive. 10257850SVuong.Nguyen@Sun.COM */ 10267850SVuong.Nguyen@Sun.COM if (ier == ETIMEDOUT) { 10277850SVuong.Nguyen@Sun.COM svc->state = DS_SVC_INACTIVE; 10287850SVuong.Nguyen@Sun.COM } 10297850SVuong.Nguyen@Sun.COM } 10302072Svn83148 10312072Svn83148 (void) pthread_mutex_unlock(&lsp->fmas_svcs.mt); 10322072Svn83148 10332072Svn83148 if (ier == 0) 10342072Svn83148 return (svc); 10352072Svn83148 else 10362072Svn83148 return (NULL); 10372072Svn83148 } 10382072Svn83148 10392072Svn83148 10402072Svn83148 static uint64_t 10412072Svn83148 fds_svc_req_num(void) 10422072Svn83148 { 10432072Svn83148 static uint64_t req_num = 1; 10442072Svn83148 10452072Svn83148 return (req_num++); 10462072Svn83148 } 10472072Svn83148 10482072Svn83148 10492072Svn83148 /* 10502072Svn83148 * return 0 if successful, 1 if otherwise 10512072Svn83148 */ 10522072Svn83148 static int 10532072Svn83148 read_msg(struct ldmsvcs_info *lsp) 10542072Svn83148 { 10552072Svn83148 ds_hdr_t header; 10562072Svn83148 void *msg_buf; 10572072Svn83148 10582072Svn83148 /* 10592072Svn83148 * read the header 10602072Svn83148 */ 10612072Svn83148 if (read_stream(lsp->fds_chan.fd, &header, sizeof (ds_hdr_t)) != 0) 10622072Svn83148 return (1); 10632072Svn83148 10642072Svn83148 if (header.msg_type >= 10652072Svn83148 sizeof (ds_msg_handlers) / sizeof (ds_msg_handler_t)) 10664358Srb144127 return (1); 10672072Svn83148 10682072Svn83148 /* 10692072Svn83148 * handle data as a special case 10702072Svn83148 */ 10712072Svn83148 if (header.msg_type == 9) 10722072Svn83148 return (poller_handle_data(lsp->fds_chan.fd, 10734358Srb144127 header.payload_len)); 10742072Svn83148 10752072Svn83148 /* 10762072Svn83148 * all other types of messages should be small 10772072Svn83148 */ 10782072Svn83148 ASSERT(header.payload_len < 1024); 10792072Svn83148 msg_buf = alloca(header.payload_len); 10802072Svn83148 10812072Svn83148 /* 10822072Svn83148 * read the payload 10832072Svn83148 */ 10842072Svn83148 if (read_stream(lsp->fds_chan.fd, msg_buf, header.payload_len) != 0) 10852072Svn83148 return (1); 10862072Svn83148 10872072Svn83148 (*ds_msg_handlers[header.msg_type])(lsp, msg_buf, header.payload_len); 10882072Svn83148 10892072Svn83148 return (0); 10902072Svn83148 } 10912072Svn83148 10922072Svn83148 10932072Svn83148 /* 10942072Svn83148 * return values: 10952072Svn83148 * 0 - success 10962072Svn83148 * 1 - problem with opening the channel 10972072Svn83148 * 2 - channed not opened; request to exit has been detected 10982072Svn83148 */ 10992072Svn83148 static int 11002072Svn83148 channel_openreset(struct ldmsvcs_info *lsp) 11012072Svn83148 { 11022072Svn83148 int ier; 11032072Svn83148 11042072Svn83148 ier = pthread_mutex_lock(&lsp->mt); 11052072Svn83148 11062072Svn83148 if (ier == EINVAL || lsp->fds_chan.state == CHANNEL_EXIT || 11072072Svn83148 lsp->fds_chan.state == CHANNEL_UNUSABLE) { 11082072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 11092072Svn83148 return (2); 11102072Svn83148 } 11112072Svn83148 11122072Svn83148 if (lsp->fds_chan.state == CHANNEL_UNINITIALIZED || 11132072Svn83148 lsp->fds_chan.state == CHANNEL_CLOSED) { 11142072Svn83148 (void) pthread_cond_broadcast(&lsp->cv); 11152072Svn83148 11162072Svn83148 if ((lsp->fds_chan.fd = open(FDS_VLDC, O_RDWR)) < 0) { 11172072Svn83148 lsp->fds_chan.state = CHANNEL_UNUSABLE; 11184358Srb144127 lsp->cv_twait = get_smf_int_val(LDM_RUNNING_TO_PROP_NM, 11194358Srb144127 0, LDM_TIMEOUT_CEILING, LDM_RUNNING_WAIT_TIME); 11202072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 11212072Svn83148 (void) pthread_cond_broadcast(&lsp->fmas_svcs.cv); 11222072Svn83148 11232072Svn83148 return (2); 11242072Svn83148 } else { 11252072Svn83148 vldc_opt_op_t op; 11262072Svn83148 11272072Svn83148 op.op_sel = VLDC_OP_SET; 11282072Svn83148 op.opt_sel = VLDC_OPT_MODE; 11296408Sha137994 op.opt_val = LDC_MODE_RELIABLE; 11302072Svn83148 11312072Svn83148 if (ioctl(lsp->fds_chan.fd, VLDC_IOCTL_OPT_OP, 11324358Srb144127 &op) != 0) { 11332072Svn83148 (void) close(lsp->fds_chan.fd); 11342072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 11352072Svn83148 return (1); 11362072Svn83148 } 11372072Svn83148 } 11382072Svn83148 lsp->fds_chan.state = CHANNEL_OPEN; 11392072Svn83148 } 11402072Svn83148 11412072Svn83148 if (lsp->fds_chan.state == CHANNEL_OPEN) { 11422072Svn83148 /* 11432072Svn83148 * reset various channel parameters 11442072Svn83148 */ 11452072Svn83148 lsp->fds_chan.ver.major = 0; 11462072Svn83148 lsp->fds_chan.ver.minor = 0; 11472072Svn83148 fds_svc_reset(lsp, -1); 11482072Svn83148 } 11492072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 11502072Svn83148 11512072Svn83148 return (0); 11522072Svn83148 } 11532072Svn83148 11542072Svn83148 11552072Svn83148 static void 11562072Svn83148 channel_fini(void) 11572072Svn83148 { 1158*8634SVuong.Nguyen@Sun.COM int i; 11592072Svn83148 struct ldmsvcs_info *lsp; 11602072Svn83148 11612072Svn83148 /* 11622072Svn83148 * End the poller thread 11632072Svn83148 */ 1164*8634SVuong.Nguyen@Sun.COM poller_fini(); 11652072Svn83148 11662072Svn83148 if ((lsp = channel_init(NULL)) == NULL) 11672072Svn83148 return; 11682072Svn83148 11692072Svn83148 (void) pthread_mutex_lock(&lsp->mt); 11702072Svn83148 11712072Svn83148 lsp->fds_chan.state = CHANNEL_EXIT; 11722072Svn83148 (void) close(lsp->fds_chan.fd); 11732072Svn83148 11742072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 1175*8634SVuong.Nguyen@Sun.COM 1176*8634SVuong.Nguyen@Sun.COM /* Free the ldom service structure */ 1177*8634SVuong.Nguyen@Sun.COM for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) { 1178*8634SVuong.Nguyen@Sun.COM ldom_free(lsp->fmas_svcs.tbl[i], sizeof (fds_svc_t)); 1179*8634SVuong.Nguyen@Sun.COM } 1180*8634SVuong.Nguyen@Sun.COM ldom_free(lsp->fmas_svcs.tbl, 1181*8634SVuong.Nguyen@Sun.COM lsp->fmas_svcs.nsvcs * sizeof (fds_svc_t *)); 1182*8634SVuong.Nguyen@Sun.COM ldom_free(lsp, sizeof (struct ldmsvcs_info)); 11832072Svn83148 } 11842072Svn83148 11852072Svn83148 11862072Svn83148 static struct ldmsvcs_info * 11872072Svn83148 channel_init(struct ldom_hdl *lhp) 11882072Svn83148 { 11892072Svn83148 static pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER; 11902072Svn83148 static pthread_cond_t cv = PTHREAD_COND_INITIALIZER; 11912072Svn83148 static struct ldmsvcs_info *root = NULL; 11922072Svn83148 static int busy_init = 0; 11932072Svn83148 11942072Svn83148 struct timespec twait; 11952072Svn83148 int expired; 11962072Svn83148 11972072Svn83148 (void) pthread_mutex_lock(&mt); 11982072Svn83148 11992072Svn83148 while (busy_init == 1) 12002072Svn83148 (void) pthread_cond_wait(&cv, &mt); 12012072Svn83148 12022072Svn83148 if (root != NULL || (lhp == NULL && root == NULL)) { 12032072Svn83148 (void) pthread_mutex_unlock(&mt); 12042072Svn83148 return (root); 12052072Svn83148 } 12062072Svn83148 12072072Svn83148 /* 12082072Svn83148 * get to this point if we need to open the channel 12092072Svn83148 */ 12102072Svn83148 busy_init = 1; 12112072Svn83148 (void) pthread_mutex_unlock(&mt); 12122072Svn83148 12132072Svn83148 root = (struct ldmsvcs_info *) 1214*8634SVuong.Nguyen@Sun.COM ldom_alloc(sizeof (struct ldmsvcs_info)); 12152072Svn83148 bzero(root, sizeof (struct ldmsvcs_info)); 12162072Svn83148 12172072Svn83148 root->fds_chan.state = CHANNEL_UNINITIALIZED; 12184358Srb144127 root->cv_twait = get_smf_int_val(LDM_INIT_TO_PROP_NM, 12194358Srb144127 0, LDM_TIMEOUT_CEILING, LDM_INIT_WAIT_TIME); 12202072Svn83148 12212072Svn83148 if (pthread_mutex_init(&root->mt, NULL) != 0 || 12222072Svn83148 pthread_cond_init(&root->cv, NULL) != 0) { 1223*8634SVuong.Nguyen@Sun.COM ldom_free(root, sizeof (struct ldmsvcs_info)); 12242072Svn83148 return (NULL); 12252072Svn83148 } 12262072Svn83148 1227*8634SVuong.Nguyen@Sun.COM fds_svc_alloc(root); 12282072Svn83148 fds_svc_reset(root, -1); 12292072Svn83148 12302072Svn83148 (void) poller_init(root); 12312072Svn83148 12322072Svn83148 expired = 0; 12332072Svn83148 twait.tv_sec = time(NULL) + 10; 12342072Svn83148 twait.tv_nsec = 0; 12352072Svn83148 12362072Svn83148 (void) pthread_mutex_lock(&root->mt); 12372072Svn83148 12382072Svn83148 /* 12392072Svn83148 * wait for channel to become uninitialized. this should be quick. 12402072Svn83148 */ 12412072Svn83148 while (root->fds_chan.state == CHANNEL_UNINITIALIZED && expired == 0) 12422072Svn83148 expired = pthread_cond_timedwait(&root->cv, &root->mt, &twait); 12432072Svn83148 12442072Svn83148 if (root->fds_chan.state == CHANNEL_UNUSABLE) 12452072Svn83148 expired = 1; 12462072Svn83148 12472072Svn83148 (void) pthread_mutex_unlock(&root->mt); 12482072Svn83148 12492072Svn83148 (void) pthread_mutex_lock(&mt); 12502072Svn83148 busy_init = 0; 12512072Svn83148 (void) pthread_mutex_unlock(&mt); 12522072Svn83148 (void) pthread_cond_broadcast(&cv); 12532072Svn83148 12542072Svn83148 (void) atexit(channel_fini); 12552072Svn83148 12562072Svn83148 if (expired == 0) 12572072Svn83148 return (root); 12582072Svn83148 else 12592072Svn83148 return (NULL); 12602072Svn83148 } 12612072Svn83148 12622072Svn83148 12632072Svn83148 static int 12642072Svn83148 sendrecv(struct ldom_hdl *lhp, uint64_t req_num, 12652072Svn83148 void *msg, size_t msglen, ds_svc_hdl_t *svc_hdl, char *svcname, 12662072Svn83148 void **resp, size_t *resplen) 12672072Svn83148 { 12682072Svn83148 struct ldmsvcs_info *lsp; 12692072Svn83148 fds_svc_t *svc; 12702072Svn83148 int maxretries, index, i, ier; 12712072Svn83148 12722072Svn83148 lsp = lhp->lsinfo; 12732072Svn83148 i = 0; 12742072Svn83148 maxretries = 1; 12752072Svn83148 12762072Svn83148 do { 12772072Svn83148 /* 12782072Svn83148 * if any of the calls in this loop fail, retry some number 12792072Svn83148 * of times before giving up. 12802072Svn83148 */ 12812072Svn83148 if ((svc = fds_svc_lookup(lsp, svcname)) == NULL) { 12822072Svn83148 (void) pthread_mutex_lock(&lsp->mt); 12832072Svn83148 12842072Svn83148 if (lsp->fds_chan.state != CHANNEL_READY) 12852072Svn83148 ier = ETIMEDOUT; /* channel not ready */ 12862072Svn83148 else 12872072Svn83148 ier = ENOTSUP; /* service not ready */ 12882072Svn83148 12892072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 12902072Svn83148 12912072Svn83148 continue; 12922072Svn83148 } else { 12932072Svn83148 ier = 0; 12942072Svn83148 *svc_hdl = svc->hdl; 12952072Svn83148 } 12962072Svn83148 1297*8634SVuong.Nguyen@Sun.COM index = poller_add_pending(req_num); 12982072Svn83148 12992072Svn83148 if ((ier = fds_send(lsp, msg, msglen)) != 0 || 13002072Svn83148 (ier = poller_recv_data(lhp, req_num, index, resp, 13014358Srb144127 resplen)) != 0) 13022072Svn83148 poller_delete_pending(req_num, index); 13032072Svn83148 13042072Svn83148 } while (i++ < maxretries && ier != 0); 13052072Svn83148 13062072Svn83148 ASSERT(ier == 0 || ier == ETIMEDOUT || ier == ENOTSUP); 13072072Svn83148 13082072Svn83148 return (ier); 13092072Svn83148 } 13102072Svn83148 13112072Svn83148 13122072Svn83148 /* 13132072Svn83148 * input: 13142072Svn83148 * msg_type - requested operation: FMA_CPU_REQ_STATUS or FMA_CPU_REQ_OFFLINE 13152072Svn83148 * cpuid - physical cpu id 13162072Svn83148 * 13172072Svn83148 * normal return values: 13182072Svn83148 * P_OFFLINE - cpu is offline 13192072Svn83148 * P_ONLINE - cpu is online 13202072Svn83148 * 13212072Svn83148 * abnormal return values: 13222072Svn83148 * ETIMEDOUT - LDOM manager is not responding 13232072Svn83148 * ENOTSUP - LDOM service for cpu offlining/status is not available 13242072Svn83148 * ENOMSG - got an unexpected response from the LDOM cpu service 13252072Svn83148 */ 13262072Svn83148 static int 13272072Svn83148 cpu_request(struct ldom_hdl *lhp, uint32_t msg_type, uint32_t cpuid) 13282072Svn83148 { 13292072Svn83148 ds_hdr_t *H; 13302072Svn83148 ds_data_handle_t *D; 13312072Svn83148 fma_cpu_service_req_t *R; 13322072Svn83148 13337850SVuong.Nguyen@Sun.COM char *svcname = LDM_DS_NAME_CPU; 13342072Svn83148 fma_cpu_resp_t *respmsg; 13352072Svn83148 void *resp; 13362072Svn83148 size_t resplen, reqmsglen; 13372072Svn83148 int rc; 13382072Svn83148 13392072Svn83148 if (lhp->lsinfo == NULL) 13402072Svn83148 return (ENOMSG); 13412072Svn83148 13422072Svn83148 reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) + 13434358Srb144127 sizeof (fma_cpu_service_req_t); 13442072Svn83148 13452072Svn83148 H = lhp->allocp(reqmsglen); 13462072Svn83148 D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 13472072Svn83148 R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t)); 13482072Svn83148 13492072Svn83148 H->msg_type = DS_DATA; 13502072Svn83148 H->payload_len = sizeof (ds_data_handle_t) + 13514358Srb144127 sizeof (fma_cpu_service_req_t); 13522072Svn83148 13532072Svn83148 R->req_num = fds_svc_req_num(); 13542072Svn83148 R->msg_type = msg_type; 13552072Svn83148 R->cpu_id = cpuid; 13562072Svn83148 13572072Svn83148 if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen, 13584358Srb144127 &D->svc_handle, svcname, &resp, &resplen)) != 0) { 13592072Svn83148 lhp->freep(H, reqmsglen); 13602072Svn83148 return (rc); 13612072Svn83148 } 13622072Svn83148 13632072Svn83148 lhp->freep(H, reqmsglen); 13642072Svn83148 13652072Svn83148 ASSERT(resplen == sizeof (fma_cpu_resp_t)); 13662072Svn83148 respmsg = (fma_cpu_resp_t *)resp; 13672072Svn83148 13682072Svn83148 rc = ENOMSG; 13692072Svn83148 if (respmsg->result == FMA_CPU_RESP_OK) { 13702072Svn83148 if (respmsg->status == FMA_CPU_STAT_ONLINE) 13712072Svn83148 rc = P_ONLINE; 13722072Svn83148 else if (respmsg->status == FMA_CPU_STAT_OFFLINE) 13732072Svn83148 rc = P_OFFLINE; 13742072Svn83148 } else { 13752072Svn83148 if (msg_type == FMA_CPU_REQ_OFFLINE && 13762072Svn83148 respmsg->status == FMA_CPU_STAT_OFFLINE) 13772072Svn83148 rc = P_OFFLINE; 13782072Svn83148 } 13792072Svn83148 13802072Svn83148 lhp->freep(resp, resplen); 13812072Svn83148 13822072Svn83148 return (rc); 13832072Svn83148 } 13842072Svn83148 13852072Svn83148 13862072Svn83148 /* 13872072Svn83148 * input: 13882072Svn83148 * msg_type - requested operation: FMA_MEM_REQ_STATUS or FMA_MEM_REQ_RETIRE 13892072Svn83148 * pa - starting address of memory page 13902072Svn83148 * pgsize - memory page size in bytes 13912072Svn83148 * 13922072Svn83148 * normal return values for msg_type == FMA_MEM_REQ_STATUS: 13932072Svn83148 * 0 - page is retired 13942072Svn83148 * EAGAIN - page is scheduled for retirement 13952072Svn83148 * EIO - page not scheduled for retirement 13962072Svn83148 * EINVAL - error 13972072Svn83148 * 13982072Svn83148 * normal return values for msg_type == FMA_MEM_REQ_RETIRE: 13992072Svn83148 * 0 - success in retiring page 14002072Svn83148 * EIO - page is already retired 14012072Svn83148 * EAGAIN - page is scheduled for retirement 14022072Svn83148 * EINVAL - error 14032072Svn83148 * 14042072Svn83148 * abnormal return values (regardless of msg_type) 14052072Svn83148 * ETIMEDOUT - LDOM manager is not responding 14062072Svn83148 * ENOTSUP - LDOM service for cpu offlining/status is not available 14072072Svn83148 * ENOMSG - got an unexpected response from the LDOM cpu service 14082072Svn83148 */ 14092072Svn83148 static int 14102072Svn83148 mem_request(struct ldom_hdl *lhp, uint32_t msg_type, uint64_t pa, 14112072Svn83148 uint64_t pgsize) 14122072Svn83148 { 14132072Svn83148 ds_hdr_t *H; 14142072Svn83148 ds_data_handle_t *D; 14152072Svn83148 fma_mem_service_req_t *R; 14162072Svn83148 14177850SVuong.Nguyen@Sun.COM char *svcname = LDM_DS_NAME_MEM; 14182072Svn83148 fma_mem_resp_t *respmsg; 14192072Svn83148 void *resp; 14202072Svn83148 size_t resplen, reqmsglen; 14212072Svn83148 int rc; 14222072Svn83148 14232072Svn83148 if (lhp->lsinfo == NULL) 14242072Svn83148 return (ENOMSG); 14252072Svn83148 14262072Svn83148 reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) + 14274358Srb144127 sizeof (fma_mem_service_req_t); 14282072Svn83148 14292072Svn83148 H = lhp->allocp(reqmsglen); 14302072Svn83148 bzero(H, reqmsglen); 14312072Svn83148 D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 14322072Svn83148 R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t)); 14332072Svn83148 14342072Svn83148 H->msg_type = DS_DATA; 14352072Svn83148 H->payload_len = sizeof (ds_data_handle_t) + 14364358Srb144127 sizeof (fma_mem_service_req_t); 14372072Svn83148 14382072Svn83148 R->req_num = fds_svc_req_num(); 14392072Svn83148 R->msg_type = msg_type; 14402072Svn83148 R->real_addr = pa; 14412072Svn83148 R->length = pgsize; 14422072Svn83148 14432072Svn83148 if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen, 14444358Srb144127 &D->svc_handle, svcname, &resp, &resplen)) != 0) { 14452072Svn83148 lhp->freep(H, reqmsglen); 14462072Svn83148 return (rc); 14472072Svn83148 } 14482072Svn83148 14492072Svn83148 lhp->freep(H, reqmsglen); 14502072Svn83148 14512072Svn83148 ASSERT(resplen == sizeof (fma_mem_resp_t)); 14522072Svn83148 respmsg = (fma_mem_resp_t *)resp; 14532072Svn83148 14542072Svn83148 rc = ENOMSG; 14552072Svn83148 if (msg_type == FMA_MEM_REQ_STATUS) { 14562072Svn83148 if (respmsg->result == FMA_MEM_RESP_OK) { 14572072Svn83148 if (respmsg->status == FMA_MEM_STAT_RETIRED) 14584655Svn83148 rc = 0; /* page is retired */ 14592072Svn83148 else if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 14604655Svn83148 rc = EIO; /* page is not scheduled */ 14612072Svn83148 } else if (respmsg->result == FMA_MEM_RESP_FAILURE) { 14624655Svn83148 if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 14634655Svn83148 rc = EAGAIN; /* page is scheduled */ 14644655Svn83148 else if (respmsg->status == FMA_MEM_STAT_ILLEGAL) 14652072Svn83148 rc = EINVAL; 14662072Svn83148 } 14672072Svn83148 } else if (msg_type == FMA_MEM_REQ_RETIRE) { 14682072Svn83148 if (respmsg->result == FMA_MEM_RESP_OK) { 14692072Svn83148 if (respmsg->status == FMA_MEM_STAT_RETIRED) 14704655Svn83148 rc = 0; /* is successfully retired */ 14712072Svn83148 } else if (respmsg->result == FMA_MEM_RESP_FAILURE) { 14722072Svn83148 if (respmsg->status == FMA_MEM_STAT_RETIRED) 14734655Svn83148 rc = EIO; /* is already retired */ 14744655Svn83148 else if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 14754655Svn83148 rc = EAGAIN; /* is scheduled to retire */ 14762072Svn83148 else if (respmsg->status == FMA_MEM_STAT_ILLEGAL) 14772072Svn83148 rc = EINVAL; 14782072Svn83148 } 14797532SSean.Ye@Sun.COM } else if (msg_type == FMA_MEM_REQ_RESURRECT) { 14807532SSean.Ye@Sun.COM if (respmsg->result == FMA_MEM_RESP_OK) { 14817532SSean.Ye@Sun.COM if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 14827532SSean.Ye@Sun.COM rc = 0; /* is successfully unretired */ 14837532SSean.Ye@Sun.COM } if (respmsg->result == FMA_MEM_RESP_FAILURE) { 14847532SSean.Ye@Sun.COM if (respmsg->status == FMA_MEM_STAT_RETIRED) 14857532SSean.Ye@Sun.COM rc = EAGAIN; /* page couldn't be locked */ 14867532SSean.Ye@Sun.COM else if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 14877532SSean.Ye@Sun.COM rc = EIO; /* page isn't retired already */ 14887532SSean.Ye@Sun.COM else if (respmsg->status == FMA_MEM_STAT_ILLEGAL) 14897532SSean.Ye@Sun.COM rc = EINVAL; 14907532SSean.Ye@Sun.COM } 14912072Svn83148 } 14922072Svn83148 14932072Svn83148 lhp->freep(resp, resplen); 14942072Svn83148 14952072Svn83148 return (rc); 14962072Svn83148 } 14972072Svn83148 14982072Svn83148 14992072Svn83148 /* 15002072Svn83148 * APIs 15012072Svn83148 */ 15022072Svn83148 int 15032072Svn83148 ldmsvcs_check_channel(void) 15042072Svn83148 { 15052072Svn83148 struct stat buf; 15062072Svn83148 15072072Svn83148 if (stat(FDS_VLDC, &buf) == 0) 15082072Svn83148 return (0); /* vldc exists */ 15092072Svn83148 else if (errno == ENOENT || errno == ENOTDIR) 15102072Svn83148 return (1); /* vldc does not exist */ 15112072Svn83148 else 15122072Svn83148 return (-1); /* miscellaneous error */ 15132072Svn83148 } 15142072Svn83148 15152072Svn83148 15162072Svn83148 /*ARGSUSED*/ 15172072Svn83148 void 15182072Svn83148 ldmsvcs_init(struct ldom_hdl *lhp) 15192072Svn83148 { 15202072Svn83148 if (ldmsvcs_check_channel() != 0) 15212072Svn83148 return; 15222072Svn83148 15232072Svn83148 lhp->lsinfo = channel_init(lhp); 15242072Svn83148 poller_add_client(); 15252072Svn83148 } 15262072Svn83148 15272072Svn83148 15282072Svn83148 /*ARGSUSED*/ 15292072Svn83148 void 15302072Svn83148 ldmsvcs_fini(struct ldom_hdl *lhp) 15312072Svn83148 { 15322072Svn83148 if (ldmsvcs_check_channel() != 0) 15332072Svn83148 return; 15342072Svn83148 15352072Svn83148 poller_remove_client(); 15362072Svn83148 } 15372072Svn83148 15382072Svn83148 15392072Svn83148 /*ARGSUSED*/ 15402072Svn83148 ssize_t 15412072Svn83148 ldmsvcs_get_core_md(struct ldom_hdl *lhp, uint64_t **buf) 15422072Svn83148 { 15432072Svn83148 ds_hdr_t *H; 15442072Svn83148 ds_data_handle_t *D; 15452072Svn83148 fma_req_pri_t *R; 15462072Svn83148 15477850SVuong.Nguyen@Sun.COM char *svcname = LDM_DS_NAME_PRI; 15482072Svn83148 void *resp; 15492072Svn83148 size_t resplen, reqmsglen; 15502072Svn83148 ssize_t buflen; 15512072Svn83148 int rc; 15522072Svn83148 15532072Svn83148 if (lhp->lsinfo == NULL) 15542072Svn83148 return (-1); 15552072Svn83148 15562072Svn83148 reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) + 15574358Srb144127 sizeof (fma_req_pri_t); 15582072Svn83148 15592072Svn83148 H = lhp->allocp(reqmsglen); 15602072Svn83148 D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 15612072Svn83148 R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t)); 15622072Svn83148 15632072Svn83148 H->msg_type = DS_DATA; 15642072Svn83148 H->payload_len = sizeof (ds_data_handle_t) + 15654358Srb144127 sizeof (fma_req_pri_t); 15662072Svn83148 15672072Svn83148 R->req_num = fds_svc_req_num(); 15682072Svn83148 15692072Svn83148 if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen, 15704358Srb144127 &D->svc_handle, svcname, &resp, &resplen)) != 0) { 15712072Svn83148 lhp->freep(H, reqmsglen); 15722072Svn83148 errno = rc; 15732072Svn83148 return (-1); 15742072Svn83148 } 15752072Svn83148 15762072Svn83148 lhp->freep(H, reqmsglen); 15772072Svn83148 15782072Svn83148 /* 15792072Svn83148 * resp should contain the req_num immediately followed by the PRI 15802072Svn83148 * (the latter may or may not be present). unfortunately, the 15812072Svn83148 * current compiler flags cause a warning for the following 15822072Svn83148 * definition 15832072Svn83148 * 15842072Svn83148 * typedef struct { 15852072Svn83148 * uint64_t req_num; 15862072Svn83148 * uint8_t pri[]; 15872072Svn83148 * } fma_pri_resp_t; 15882072Svn83148 * 15892072Svn83148 * so we do not use the struct here. 15902072Svn83148 */ 15912072Svn83148 if (resplen <= sizeof (uint64_t)) { 15922072Svn83148 lhp->freep(resp, resplen); 15932072Svn83148 if (resplen == sizeof (uint64_t)) 15942072Svn83148 return (0); 15952072Svn83148 else 15962072Svn83148 return (-1); 15972072Svn83148 } 15982072Svn83148 15992072Svn83148 buflen = resplen - sizeof (uint64_t); 16002072Svn83148 *buf = lhp->allocp(buflen); 16012072Svn83148 16022072Svn83148 bcopy((void *)((ptrdiff_t)resp + sizeof (uint64_t)), *buf, buflen); 16032072Svn83148 lhp->freep(resp, resplen); 16042072Svn83148 16052072Svn83148 return (buflen); 16062072Svn83148 } 16072072Svn83148 16082072Svn83148 16092072Svn83148 /* 16102072Svn83148 * see cpu_request() for a description of return values 16112072Svn83148 */ 16122072Svn83148 int 16132072Svn83148 ldmsvcs_cpu_req_status(struct ldom_hdl *lhp, uint32_t cpuid) 16142072Svn83148 { 16152072Svn83148 return (cpu_request(lhp, FMA_CPU_REQ_STATUS, cpuid)); 16162072Svn83148 } 16172072Svn83148 16182072Svn83148 16192072Svn83148 int 16202072Svn83148 ldmsvcs_cpu_req_offline(struct ldom_hdl *lhp, uint32_t cpuid) 16212072Svn83148 { 16222072Svn83148 return (cpu_request(lhp, FMA_CPU_REQ_OFFLINE, cpuid)); 16232072Svn83148 } 16242072Svn83148 16256111Scy152378 int 16266111Scy152378 ldmsvcs_cpu_req_online(struct ldom_hdl *lhp, uint32_t cpuid) 16276111Scy152378 { 16286111Scy152378 return (cpu_request(lhp, FMA_CPU_REQ_ONLINE, cpuid)); 16296111Scy152378 } 16302072Svn83148 16312072Svn83148 /* 16322072Svn83148 * see mem_request() for a description of return values 16332072Svn83148 */ 16342072Svn83148 int 16352072Svn83148 ldmsvcs_mem_req_status(struct ldom_hdl *lhp, uint64_t pa) 16362072Svn83148 { 16372072Svn83148 return (mem_request(lhp, FMA_MEM_REQ_STATUS, pa, getpagesize())); 16382072Svn83148 } 16392072Svn83148 16402072Svn83148 int 16412072Svn83148 ldmsvcs_mem_req_retire(struct ldom_hdl *lhp, uint64_t pa) 16422072Svn83148 { 16432072Svn83148 return (mem_request(lhp, FMA_MEM_REQ_RETIRE, pa, getpagesize())); 16442072Svn83148 } 16452072Svn83148 16466111Scy152378 int 16476111Scy152378 ldmsvcs_mem_req_unretire(struct ldom_hdl *lhp, uint64_t pa) 16486111Scy152378 { 16496111Scy152378 return (mem_request(lhp, FMA_MEM_REQ_RESURRECT, pa, getpagesize())); 16506111Scy152378 } 16516111Scy152378 16527850SVuong.Nguyen@Sun.COM int 16537850SVuong.Nguyen@Sun.COM ldmsvcs_io_req_id(struct ldom_hdl *lhp, uint64_t addr, uint_t type, 16547850SVuong.Nguyen@Sun.COM uint64_t *virt_addr, char *name, int name_len, uint64_t *did) 16557850SVuong.Nguyen@Sun.COM { 16567850SVuong.Nguyen@Sun.COM 16577850SVuong.Nguyen@Sun.COM ds_hdr_t *H; 16587850SVuong.Nguyen@Sun.COM ds_data_handle_t *D; 16597850SVuong.Nguyen@Sun.COM fma_io_req_t *R; 16607850SVuong.Nguyen@Sun.COM 16617850SVuong.Nguyen@Sun.COM char *svcname = LDM_DS_NAME_IOD; 16627850SVuong.Nguyen@Sun.COM void *resp; 16637850SVuong.Nguyen@Sun.COM fma_io_resp_t *iop; 16647850SVuong.Nguyen@Sun.COM size_t resplen, reqmsglen; 16657850SVuong.Nguyen@Sun.COM int offset; 16667850SVuong.Nguyen@Sun.COM int rc; 16677850SVuong.Nguyen@Sun.COM 16687850SVuong.Nguyen@Sun.COM if (lhp->lsinfo == NULL) 16697850SVuong.Nguyen@Sun.COM return (-1); 16707850SVuong.Nguyen@Sun.COM 16717850SVuong.Nguyen@Sun.COM reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) + 16727850SVuong.Nguyen@Sun.COM sizeof (fma_io_req_t); 16737850SVuong.Nguyen@Sun.COM 16747850SVuong.Nguyen@Sun.COM H = lhp->allocp(reqmsglen); 16757850SVuong.Nguyen@Sun.COM D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 16767850SVuong.Nguyen@Sun.COM R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t)); 16777850SVuong.Nguyen@Sun.COM 16787850SVuong.Nguyen@Sun.COM H->msg_type = DS_DATA; 16797850SVuong.Nguyen@Sun.COM H->payload_len = sizeof (ds_data_handle_t) + sizeof (fma_io_req_t); 16807850SVuong.Nguyen@Sun.COM 16817850SVuong.Nguyen@Sun.COM R->req_num = fds_svc_req_num(); 16827850SVuong.Nguyen@Sun.COM R->msg_type = type; 16837850SVuong.Nguyen@Sun.COM R->rsrc_address = addr; 16847850SVuong.Nguyen@Sun.COM 16857850SVuong.Nguyen@Sun.COM rc = ENOMSG; 16867850SVuong.Nguyen@Sun.COM if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen, 16877850SVuong.Nguyen@Sun.COM &D->svc_handle, svcname, &resp, &resplen)) != 0) { 16887850SVuong.Nguyen@Sun.COM lhp->freep(H, reqmsglen); 16897850SVuong.Nguyen@Sun.COM return (rc); 16907850SVuong.Nguyen@Sun.COM } 16917850SVuong.Nguyen@Sun.COM lhp->freep(H, reqmsglen); 16927850SVuong.Nguyen@Sun.COM 16937850SVuong.Nguyen@Sun.COM /* 16947850SVuong.Nguyen@Sun.COM * resp should contain the req_num, status, virtual addr, domain id 16957850SVuong.Nguyen@Sun.COM * and the domain name. The domain name may or may not be present. 16967850SVuong.Nguyen@Sun.COM */ 16977850SVuong.Nguyen@Sun.COM offset = sizeof (fma_io_resp_t); 16987850SVuong.Nguyen@Sun.COM if (resplen < offset) { 16997850SVuong.Nguyen@Sun.COM lhp->freep(resp, resplen); 17007850SVuong.Nguyen@Sun.COM return (-1); 17017850SVuong.Nguyen@Sun.COM } 17027850SVuong.Nguyen@Sun.COM 17037850SVuong.Nguyen@Sun.COM iop = (fma_io_resp_t *)resp; 17047850SVuong.Nguyen@Sun.COM switch (iop->result) { 17057850SVuong.Nguyen@Sun.COM case FMA_IO_RESP_OK: 17067850SVuong.Nguyen@Sun.COM /* success */ 17077850SVuong.Nguyen@Sun.COM rc = 0; 17087850SVuong.Nguyen@Sun.COM *virt_addr = iop->virt_rsrc_address; 17097850SVuong.Nguyen@Sun.COM *did = iop->domain_id; 17107850SVuong.Nguyen@Sun.COM if (name == NULL || name_len <= 0) 17117850SVuong.Nguyen@Sun.COM break; 17127850SVuong.Nguyen@Sun.COM *name = '\0'; 17137850SVuong.Nguyen@Sun.COM if (resplen > offset) { 17147850SVuong.Nguyen@Sun.COM (void) strncpy(name, (char *)((ptrdiff_t)resp + offset), 17157850SVuong.Nguyen@Sun.COM name_len); 17167850SVuong.Nguyen@Sun.COM } 17177850SVuong.Nguyen@Sun.COM break; 17187850SVuong.Nguyen@Sun.COM default: 17197850SVuong.Nguyen@Sun.COM rc = -1; 17207850SVuong.Nguyen@Sun.COM break; 17217850SVuong.Nguyen@Sun.COM } 17227850SVuong.Nguyen@Sun.COM 17237850SVuong.Nguyen@Sun.COM lhp->freep(resp, resplen); 17247850SVuong.Nguyen@Sun.COM return (rc); 17257850SVuong.Nguyen@Sun.COM } 17267850SVuong.Nguyen@Sun.COM 17272072Svn83148 /* end file */ 1728