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*11831SVuong.Nguyen@Sun.COM * Copyright 2010 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> 428634SVuong.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" 498634SVuong.Nguyen@Sun.COM #include "ldom_alloc.h" 50*11831SVuong.Nguyen@Sun.COM #include "ldom_utils.h" 512072Svn83148 522072Svn83148 #define ASSERT(cnd) \ 532072Svn83148 ((void) ((cnd) || ((void) fprintf(stderr, \ 542072Svn83148 "assertion failure in %s:%d: %s\n", \ 552072Svn83148 __FILE__, __LINE__, #cnd), 0))) 562072Svn83148 572072Svn83148 #define FDS_VLDC \ 582072Svn83148 "/devices/virtual-devices@100/channel-devices@200/" \ 592072Svn83148 "/virtual-channel-client@1:ldmfma" 602072Svn83148 614358Srb144127 /* allow timeouts in sec that are nearly forever but small enough for an int */ 624358Srb144127 #define LDM_TIMEOUT_CEILING (MAXINT / 2) 632072Svn83148 642072Svn83148 #define MIN(x, y) ((x) < (y) ? (x) : (y)) 652072Svn83148 662072Svn83148 /* 672072Svn83148 * functions in this file are for version 1.0 of FMA domain services 682072Svn83148 */ 692072Svn83148 static ds_ver_t ds_vers[] = { 702072Svn83148 { 1, 0 } 712072Svn83148 }; 722072Svn83148 732072Svn83148 #define DS_NUM_VER (sizeof (ds_vers) / sizeof (ds_ver_t)) 742072Svn83148 752072Svn83148 /* 762072Svn83148 * information for each channel 772072Svn83148 */ 782072Svn83148 struct ldmsvcs_info { 792072Svn83148 pthread_mutex_t mt; 802072Svn83148 pthread_cond_t cv; 812072Svn83148 fds_channel_t fds_chan; 822072Svn83148 fds_reg_svcs_t fmas_svcs; 832072Svn83148 int cv_twait; 842072Svn83148 }; 852072Svn83148 862072Svn83148 /* 872072Svn83148 * struct listdata_s and struct poller_s are used to maintain the state of 882072Svn83148 * the poller thread. this thread is used to manage incoming messages and 892072Svn83148 * pass those messages onto the correct requesting thread. see the "poller 902072Svn83148 * functions" section for more details. 912072Svn83148 */ 922072Svn83148 struct listdata_s { 932072Svn83148 enum { 942072Svn83148 UNUSED, 952072Svn83148 PENDING, 962072Svn83148 ARRIVED 972072Svn83148 } status; 982072Svn83148 uint64_t req_num; 992072Svn83148 int fd; 1002072Svn83148 size_t datalen; 1012072Svn83148 }; 1022072Svn83148 1032072Svn83148 static struct poller_s { 1042072Svn83148 pthread_mutex_t mt; 1052072Svn83148 pthread_cond_t cv; 1062072Svn83148 pthread_t polling_tid; 107*11831SVuong.Nguyen@Sun.COM int polling_thr_sig; 1082072Svn83148 int doreset; 1092072Svn83148 int doexit; 1102072Svn83148 int nclients; 1112072Svn83148 struct listdata_s **list; 1122072Svn83148 int list_len; 1132072Svn83148 int pending_count; 1142072Svn83148 } pollbase = { 1152072Svn83148 PTHREAD_MUTEX_INITIALIZER, 1162072Svn83148 PTHREAD_COND_INITIALIZER, 1172072Svn83148 0, 118*11831SVuong.Nguyen@Sun.COM SIGTERM, 1192072Svn83148 1, 1202072Svn83148 0, 1212072Svn83148 0, 1222072Svn83148 NULL, 1232072Svn83148 0, 1242072Svn83148 0 1252072Svn83148 }; 1262072Svn83148 1272072Svn83148 1282072Svn83148 static struct ldmsvcs_info *channel_init(struct ldom_hdl *lhp); 1292072Svn83148 static int channel_openreset(struct ldmsvcs_info *lsp); 1302072Svn83148 static int read_msg(struct ldmsvcs_info *lsp); 1312072Svn83148 1324358Srb144127 static int 1334358Srb144127 get_smf_int_val(char *prop_nm, int min, int max, int default_val) 1344358Srb144127 { 1354358Srb144127 scf_simple_prop_t *prop; /* SMF property */ 1364358Srb144127 int64_t *valp; /* prop value ptr */ 1374358Srb144127 int64_t val; /* prop value to return */ 1384358Srb144127 1394358Srb144127 val = default_val; 1404358Srb144127 if ((prop = scf_simple_prop_get(NULL, LDM_SVC_NM, LDM_PROP_GROUP_NM, 1414358Srb144127 prop_nm)) != NULL) { 1424358Srb144127 if ((valp = scf_simple_prop_next_integer(prop)) != NULL) { 1434358Srb144127 val = *valp; 1444358Srb144127 if (val < min) 1454358Srb144127 val = min; 1464358Srb144127 else if (val > max) 1474358Srb144127 val = max; 1484358Srb144127 } 1494358Srb144127 scf_simple_prop_free(prop); 1504358Srb144127 } 1514358Srb144127 return ((int)val); 1524358Srb144127 } 1534358Srb144127 1542072Svn83148 static void 1552072Svn83148 channel_close(struct ldmsvcs_info *lsp) 1562072Svn83148 { 1572072Svn83148 (void) pthread_mutex_lock(&lsp->mt); 1582072Svn83148 1593327Svn83148 if (lsp->fds_chan.state == CHANNEL_OPEN || 1604358Srb144127 lsp->fds_chan.state == CHANNEL_READY) { 1613327Svn83148 (void) close(lsp->fds_chan.fd); 1624358Srb144127 lsp->cv_twait = get_smf_int_val(LDM_INIT_TO_PROP_NM, 1634358Srb144127 0, LDM_TIMEOUT_CEILING, LDM_INIT_WAIT_TIME); 1643327Svn83148 lsp->fds_chan.state = CHANNEL_CLOSED; 1653327Svn83148 } 1662072Svn83148 1672072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 1682072Svn83148 } 1692072Svn83148 1702072Svn83148 /* 1712072Svn83148 * read size bytes of data from a streaming fd into buf 1722072Svn83148 */ 1732072Svn83148 static int 1742072Svn83148 read_stream(int fd, void *buf, size_t size) 1752072Svn83148 { 1762072Svn83148 pollfd_t pollfd; 1772072Svn83148 ssize_t rv; 1782072Svn83148 size_t data_left; 1792072Svn83148 ptrdiff_t currentp; 1802072Svn83148 1812072Svn83148 pollfd.events = POLLIN; 1822072Svn83148 pollfd.revents = 0; 1832072Svn83148 pollfd.fd = fd; 1842072Svn83148 1852072Svn83148 currentp = (ptrdiff_t)buf; 1862072Svn83148 data_left = size; 1872072Svn83148 1882072Svn83148 /* 1892072Svn83148 * data may come in bits and pieces 1902072Svn83148 */ 1912072Svn83148 do { 1922072Svn83148 if ((rv = read(fd, (void *)currentp, data_left)) < 0) { 1932072Svn83148 if (errno == EAGAIN && poll(&pollfd, 1, -1) > 0) 1942072Svn83148 continue; /* retry */ 1952072Svn83148 else 1962072Svn83148 return (1); 1972072Svn83148 } 1982072Svn83148 1992072Svn83148 data_left -= rv; 2002072Svn83148 currentp += rv; 2012072Svn83148 } while (data_left > 0); 2022072Svn83148 2032072Svn83148 return (0); 2042072Svn83148 } 2052072Svn83148 2062072Svn83148 2072072Svn83148 /* 2082072Svn83148 * poller functions 2092072Svn83148 * 2102072Svn83148 * at init time, a thread is created for the purpose of monitoring incoming 2112072Svn83148 * messages and doing one of the following: 2122072Svn83148 * 2132072Svn83148 * 1. doing the initial handshake and version negotiation 2142072Svn83148 * 2152072Svn83148 * 2. handing incoming data off to the requesting thread (which is an fmd 2162072Svn83148 * module or scheme thread) 2172072Svn83148 */ 2182072Svn83148 static int 2192072Svn83148 poller_handle_data(int fd, size_t payloadsize) 2202072Svn83148 { 2212072Svn83148 uint64_t *req_num; 2222072Svn83148 void *pr; 2232072Svn83148 size_t prlen; 2242072Svn83148 int i; 2252072Svn83148 2262072Svn83148 prlen = sizeof (ds_data_handle_t) + sizeof (uint64_t); 2272072Svn83148 2282072Svn83148 if (payloadsize < prlen) 2292072Svn83148 return (1); 2302072Svn83148 2312072Svn83148 pr = alloca(prlen); 2322072Svn83148 2332072Svn83148 if (read_stream(fd, pr, prlen) != 0) 2342072Svn83148 return (1); 2352072Svn83148 2362072Svn83148 req_num = (uint64_t *)((ptrdiff_t)pr + sizeof (ds_data_handle_t)); 2372072Svn83148 2382072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 2392072Svn83148 2402072Svn83148 for (i = 0; i < pollbase.list_len; i++) { 2412072Svn83148 if (pollbase.list[i]->req_num == *req_num) { 2422072Svn83148 ASSERT(pollbase.list[i]->status == PENDING); 2432072Svn83148 2442072Svn83148 pollbase.list[i]->status = ARRIVED; 2452072Svn83148 pollbase.list[i]->fd = fd; 2462072Svn83148 pollbase.list[i]->datalen = payloadsize - prlen; 2472072Svn83148 2482072Svn83148 pollbase.pending_count--; 2492072Svn83148 (void) pthread_cond_broadcast(&pollbase.cv); 2502072Svn83148 break; 2512072Svn83148 } 2522072Svn83148 } 2532072Svn83148 2542072Svn83148 /* 2552072Svn83148 * now wait for receiving thread to read in the data 2562072Svn83148 */ 2572072Svn83148 if (i < pollbase.list_len) { 2582072Svn83148 while (pollbase.list[i]->status == ARRIVED) 2592072Svn83148 (void) pthread_cond_wait(&pollbase.cv, &pollbase.mt); 2602072Svn83148 } 2612072Svn83148 2622072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 2632072Svn83148 2642072Svn83148 return (0); 2652072Svn83148 } 2662072Svn83148 2672072Svn83148 2682072Svn83148 /* 2692072Svn83148 * note that this function is meant to handle only DS_DATA messages 2702072Svn83148 */ 2712072Svn83148 static int 2722072Svn83148 poller_recv_data(struct ldom_hdl *lhp, uint64_t req_num, int index, 2732072Svn83148 void **resp, size_t *resplen) 2742072Svn83148 { 2752072Svn83148 struct timespec twait; 2762072Svn83148 int ier; 2772072Svn83148 2782072Svn83148 ier = 0; 2792072Svn83148 twait.tv_sec = time(NULL) + lhp->lsinfo->cv_twait; 2802072Svn83148 twait.tv_nsec = 0; 2812072Svn83148 2822072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 2832072Svn83148 2842072Svn83148 ASSERT(pollbase.list[index]->req_num == req_num); 2852072Svn83148 2862072Svn83148 while (pollbase.list[index]->status == PENDING && 2872072Svn83148 pollbase.doreset == 0 && ier == 0) 2882072Svn83148 ier = pthread_cond_timedwait(&pollbase.cv, &pollbase.mt, 2894358Srb144127 &twait); 2902072Svn83148 2912072Svn83148 if (ier == 0) { 2922072Svn83148 if (pollbase.doreset == 0) { 2932072Svn83148 ASSERT(pollbase.list[index]->status == ARRIVED); 2942072Svn83148 2952072Svn83148 /* 2962072Svn83148 * need to add req_num to beginning of resp 2972072Svn83148 */ 2982072Svn83148 *resplen = pollbase.list[index]->datalen + 2994358Srb144127 sizeof (uint64_t); 3002072Svn83148 *resp = lhp->allocp(*resplen); 3012072Svn83148 *((uint64_t *)*resp) = req_num; 3022072Svn83148 3032072Svn83148 if (read_stream(pollbase.list[index]->fd, 3044358Srb144127 (void *)((ptrdiff_t)*resp + sizeof (uint64_t)), 3054358Srb144127 *resplen - sizeof (uint64_t)) != 0) 3062072Svn83148 ier = ETIMEDOUT; 3072072Svn83148 3082072Svn83148 pollbase.list[index]->status = UNUSED; 3092072Svn83148 pollbase.list[index]->req_num = 0; 3102072Svn83148 (void) pthread_cond_broadcast(&pollbase.cv); 3112072Svn83148 } else { 3122072Svn83148 if (--(pollbase.pending_count) == 0) 3132072Svn83148 (void) pthread_cond_broadcast(&pollbase.cv); 3142072Svn83148 } 3152072Svn83148 } 3162072Svn83148 3172072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 3182072Svn83148 3192072Svn83148 ASSERT(ier == 0 || ier == ETIMEDOUT); 3202072Svn83148 3212072Svn83148 return (ier); 3222072Svn83148 } 3232072Svn83148 3242072Svn83148 3252072Svn83148 static void 3262072Svn83148 poller_add_client(void) 3272072Svn83148 { 3282072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 3292072Svn83148 pollbase.nclients++; 3302072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 3312072Svn83148 } 3322072Svn83148 3332072Svn83148 3342072Svn83148 static void 3352072Svn83148 poller_remove_client(void) 3362072Svn83148 { 3372072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 3382072Svn83148 pollbase.nclients--; 3392072Svn83148 ASSERT(pollbase.nclients >= 0); 3402072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 3412072Svn83148 } 3422072Svn83148 3432072Svn83148 3442072Svn83148 static int 3458634SVuong.Nguyen@Sun.COM poller_add_pending(uint64_t req_num) 3462072Svn83148 { 3472072Svn83148 int newlen, index, i, j; 3482072Svn83148 3492072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 3502072Svn83148 pollbase.pending_count++; 3512072Svn83148 3522072Svn83148 for (j = 0, index = -1; j < 2 && index == -1; j++) { 3532072Svn83148 for (i = 0; i < pollbase.list_len; i++) { 3542072Svn83148 if (pollbase.list[i]->status == UNUSED) { 3552072Svn83148 pollbase.list[i]->status = PENDING; 3562072Svn83148 pollbase.list[i]->req_num = req_num; 3572072Svn83148 pollbase.list[i]->datalen = 0; 3582072Svn83148 index = i; 3592072Svn83148 break; 3602072Svn83148 } 3612072Svn83148 } 3622072Svn83148 3632072Svn83148 if (index == -1) { 3642072Svn83148 struct listdata_s **newlist, **oldlist; 3652072Svn83148 3662072Svn83148 /* 3672072Svn83148 * get to this point if list is not long enough. 3682072Svn83148 * check for a runaway list. since requests are 3692072Svn83148 * synchronous (clients send a request and need to 3702072Svn83148 * wait for the result before returning) the size 3712072Svn83148 * of the list cannot be much more than the number 3722072Svn83148 * of clients. 3732072Svn83148 */ 3742072Svn83148 ASSERT(pollbase.list_len < pollbase.nclients + 1); 3752072Svn83148 3762072Svn83148 newlen = pollbase.list_len + 5; 3778634SVuong.Nguyen@Sun.COM newlist = ldom_alloc(newlen * 3788634SVuong.Nguyen@Sun.COM sizeof (struct listdata_s *)); 3792072Svn83148 3802072Svn83148 for (i = 0; i < pollbase.list_len; i++) 3812072Svn83148 newlist[i] = pollbase.list[i]; 3822072Svn83148 3832072Svn83148 oldlist = pollbase.list; 3842072Svn83148 pollbase.list = newlist; 3858634SVuong.Nguyen@Sun.COM ldom_free(oldlist, pollbase.list_len * 3868634SVuong.Nguyen@Sun.COM sizeof (struct listdata_s *)); 3872072Svn83148 3882072Svn83148 for (i = pollbase.list_len; i < newlen; i++) { 3892072Svn83148 pollbase.list[i] = 3908634SVuong.Nguyen@Sun.COM ldom_alloc(sizeof (struct listdata_s)); 3912072Svn83148 pollbase.list[i]->status = UNUSED; 3922072Svn83148 } 3932072Svn83148 3942072Svn83148 pollbase.list_len = newlen; 3952072Svn83148 } 3962072Svn83148 } 3972072Svn83148 3982072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 3992072Svn83148 ASSERT(index != -1); 4002072Svn83148 4012072Svn83148 return (index); 4022072Svn83148 } 4032072Svn83148 4042072Svn83148 4052072Svn83148 static void 4062072Svn83148 poller_delete_pending(uint64_t req_num, int index) 4072072Svn83148 { 4082072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 4092072Svn83148 4102072Svn83148 ASSERT(pollbase.list[index]->req_num == req_num); 4112072Svn83148 pollbase.list[index]->status = UNUSED; 4122072Svn83148 4132072Svn83148 if (--(pollbase.pending_count) == 0 && pollbase.doreset == 1) 4142072Svn83148 (void) pthread_cond_broadcast(&pollbase.cv); 4152072Svn83148 4162072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 4172072Svn83148 } 4182072Svn83148 4192072Svn83148 4202072Svn83148 static void 4218634SVuong.Nguyen@Sun.COM poller_shutdown(boolean_t wait) 4222072Svn83148 { 4232072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 4242072Svn83148 4252072Svn83148 pollbase.doexit = 1; 4262072Svn83148 4272072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 4288634SVuong.Nguyen@Sun.COM 4298634SVuong.Nguyen@Sun.COM if (wait == B_TRUE) { 4308634SVuong.Nguyen@Sun.COM /* stop the poller thread and wait for it to end */ 431*11831SVuong.Nguyen@Sun.COM (void) pthread_kill(pollbase.polling_tid, 432*11831SVuong.Nguyen@Sun.COM pollbase.polling_thr_sig); 4338634SVuong.Nguyen@Sun.COM (void) pthread_join(pollbase.polling_tid, NULL); 4348634SVuong.Nguyen@Sun.COM } 4352072Svn83148 } 4362072Svn83148 4372072Svn83148 4382072Svn83148 /* 4392072Svn83148 * perform the polling of incoming messages. manage any resets (usually 4402072Svn83148 * due to one end of the connection being closed) as well as exit 4412072Svn83148 * conditions. 4422072Svn83148 */ 4432072Svn83148 static void * 4442072Svn83148 poller_loop(void *arg) 4452072Svn83148 { 4462072Svn83148 struct ldmsvcs_info *lsp; 4472072Svn83148 pollfd_t pollfd; 4482072Svn83148 int ier; 4492072Svn83148 4502072Svn83148 lsp = (struct ldmsvcs_info *)arg; 4512072Svn83148 4522072Svn83148 for (;;) { 4532072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 4542072Svn83148 4552072Svn83148 if (pollbase.doexit) { 4562072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 4572072Svn83148 break; 4582072Svn83148 } 4592072Svn83148 4602072Svn83148 if (pollbase.doreset) { 4612072Svn83148 int i; 4622072Svn83148 4632072Svn83148 while (pollbase.pending_count > 0) 4642072Svn83148 (void) pthread_cond_wait(&pollbase.cv, 4654358Srb144127 &pollbase.mt); 4662072Svn83148 4672072Svn83148 ASSERT(pollbase.pending_count == 0); 4682072Svn83148 for (i = 0; i < pollbase.list_len; i++) 4692072Svn83148 pollbase.list[i]->status = UNUSED; 4702072Svn83148 4712072Svn83148 pollbase.doreset = 0; 4722072Svn83148 } 4732072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 4742072Svn83148 4752072Svn83148 if ((ier = channel_openreset(lsp)) == 1) { 4762072Svn83148 continue; 4772072Svn83148 } else if (ier == 2) { 4782072Svn83148 /* 4792072Svn83148 * start exit preparations 4802072Svn83148 */ 4818634SVuong.Nguyen@Sun.COM poller_shutdown(B_FALSE); 4822072Svn83148 continue; 4832072Svn83148 } 4842072Svn83148 4852072Svn83148 pollfd.events = POLLIN; 4862072Svn83148 pollfd.revents = 0; 4872072Svn83148 pollfd.fd = lsp->fds_chan.fd; 4882072Svn83148 4892072Svn83148 if (poll(&pollfd, 1, -1) <= 0 || read_msg(lsp) != 0) { 4902072Svn83148 /* 4912072Svn83148 * read error and/or fd got closed 4922072Svn83148 */ 4932072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 4942072Svn83148 pollbase.doreset = 1; 4952072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 4962072Svn83148 4972072Svn83148 channel_close(lsp); 4982072Svn83148 } 4992072Svn83148 } 5002072Svn83148 5012072Svn83148 return (NULL); 5022072Svn83148 } 5032072Svn83148 5042072Svn83148 5052072Svn83148 /* 5062072Svn83148 * create the polling thread 5072072Svn83148 */ 5082072Svn83148 static int 5092072Svn83148 poller_init(struct ldmsvcs_info *lsp) 5102072Svn83148 { 5112072Svn83148 int rc = 0; 5122072Svn83148 5132072Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 5142072Svn83148 5152072Svn83148 if (pollbase.polling_tid == 0) { 5168634SVuong.Nguyen@Sun.COM pthread_attr_t *attr = NULL; 5172072Svn83148 5182072Svn83148 /* 5198634SVuong.Nguyen@Sun.COM * create a joinable polling thread for receiving messages 520*11831SVuong.Nguyen@Sun.COM * The polling_thr_sig stores the signal number that is not 521*11831SVuong.Nguyen@Sun.COM * currently masked. it is used to stop the poller thread. 5222072Svn83148 */ 523*11831SVuong.Nguyen@Sun.COM pollbase.polling_thr_sig = ldom_find_thr_sig(); 5248634SVuong.Nguyen@Sun.COM if (pthread_create(&pollbase.polling_tid, attr, 5254358Srb144127 poller_loop, lsp) != 0) 5262072Svn83148 rc = 1; 5272072Svn83148 } 5282072Svn83148 5292072Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 5302072Svn83148 5312072Svn83148 return (rc); 5322072Svn83148 } 5332072Svn83148 5348634SVuong.Nguyen@Sun.COM /* 5358634SVuong.Nguyen@Sun.COM * Cleanup the polling thread 5368634SVuong.Nguyen@Sun.COM */ 5378634SVuong.Nguyen@Sun.COM static void 5388634SVuong.Nguyen@Sun.COM poller_fini(void) 5398634SVuong.Nguyen@Sun.COM { 5408634SVuong.Nguyen@Sun.COM int i; 5418634SVuong.Nguyen@Sun.COM 5428634SVuong.Nguyen@Sun.COM /* stop the poller thread */ 5438634SVuong.Nguyen@Sun.COM poller_shutdown(B_TRUE); 5448634SVuong.Nguyen@Sun.COM 5458634SVuong.Nguyen@Sun.COM (void) pthread_mutex_lock(&pollbase.mt); 5468634SVuong.Nguyen@Sun.COM 5478634SVuong.Nguyen@Sun.COM /* Free up the list of outstanding requests */ 5488634SVuong.Nguyen@Sun.COM if (pollbase.list != NULL) { 5498634SVuong.Nguyen@Sun.COM for (i = 0; i < pollbase.list_len; i++) { 5508634SVuong.Nguyen@Sun.COM if (pollbase.list[i]) { 5518634SVuong.Nguyen@Sun.COM ldom_free(pollbase.list[i], 5528634SVuong.Nguyen@Sun.COM sizeof (struct listdata_s)); 5538634SVuong.Nguyen@Sun.COM } 5548634SVuong.Nguyen@Sun.COM } 5558634SVuong.Nguyen@Sun.COM ldom_free(pollbase.list, pollbase.list_len * 5568634SVuong.Nguyen@Sun.COM sizeof (struct listdata_s *)); 5578634SVuong.Nguyen@Sun.COM pollbase.list = NULL; 5588634SVuong.Nguyen@Sun.COM pollbase.list_len = 0; 5598634SVuong.Nguyen@Sun.COM } 5608634SVuong.Nguyen@Sun.COM 5618634SVuong.Nguyen@Sun.COM (void) pthread_mutex_unlock(&pollbase.mt); 5628634SVuong.Nguyen@Sun.COM } 5632072Svn83148 5642072Svn83148 /* 5652072Svn83148 * utilities for message handlers 5662072Svn83148 */ 5672072Svn83148 static int 5682072Svn83148 fds_send(struct ldmsvcs_info *lsp, void *msg, size_t msglen) 5692072Svn83148 { 5702072Svn83148 static pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER; 5712072Svn83148 5722072Svn83148 (void) pthread_mutex_lock(&mt); 5732072Svn83148 5742072Svn83148 if (write(lsp->fds_chan.fd, msg, msglen) != msglen) { 5752072Svn83148 channel_close(lsp); 5762072Svn83148 (void) pthread_mutex_unlock(&mt); 5772072Svn83148 return (ETIMEDOUT); 5782072Svn83148 } 5792072Svn83148 5802072Svn83148 (void) pthread_mutex_unlock(&mt); 5812072Svn83148 return (0); 5822072Svn83148 } 5832072Svn83148 5842072Svn83148 5852072Svn83148 /* 5862072Svn83148 * Find the max and min version supported 5872072Svn83148 */ 5882072Svn83148 static void 5892072Svn83148 fds_min_max_versions(uint16_t *min_major, uint16_t *max_major) 5902072Svn83148 { 5912072Svn83148 int i; 5922072Svn83148 5932072Svn83148 *min_major = ds_vers[0].major; 5942072Svn83148 *max_major = *min_major; 5952072Svn83148 5962072Svn83148 for (i = 1; i < DS_NUM_VER; i++) { 5972072Svn83148 if (ds_vers[i].major < *min_major) 5982072Svn83148 *min_major = ds_vers[i].major; 5992072Svn83148 6002072Svn83148 if (ds_vers[i].major > *max_major) 6012072Svn83148 *max_major = ds_vers[i].major; 6022072Svn83148 } 6032072Svn83148 } 6042072Svn83148 6052072Svn83148 /* 6062072Svn83148 * check whether the major and minor numbers requested by remote ds client 6072072Svn83148 * can be satisfied. if the requested major is supported, true is 6082072Svn83148 * returned, and the agreed minor is returned in new_minor. if the 6092072Svn83148 * requested major is not supported, the routine returns false, and the 6102072Svn83148 * closest major is returned in *new_major, upon which the ds client should 6112072Svn83148 * renegotiate. the closest major is the just lower that the requested 6122072Svn83148 * major number. 6132072Svn83148 */ 6142072Svn83148 static boolean_t 6152072Svn83148 fds_negotiate_version(uint16_t req_major, uint16_t *new_majorp, 6162072Svn83148 uint16_t *new_minorp) 6172072Svn83148 { 6182072Svn83148 int i = 0; 6192072Svn83148 uint16_t major, lower_major; 6202072Svn83148 uint16_t min_major, max_major; 6212072Svn83148 boolean_t found_match = B_FALSE; 6222072Svn83148 6232072Svn83148 fds_min_max_versions(&min_major, &max_major); 6242072Svn83148 6252072Svn83148 /* 6262072Svn83148 * if the minimum version supported is greater than the version 6272072Svn83148 * requested, return the lowest version supported 6282072Svn83148 */ 6292072Svn83148 if (min_major > req_major) { 6302072Svn83148 *new_majorp = min_major; 6312072Svn83148 return (B_FALSE); 6322072Svn83148 } 6332072Svn83148 6342072Svn83148 /* 6352072Svn83148 * if the largest version supported is lower than the version 6362072Svn83148 * requested, return the largest version supported 6372072Svn83148 */ 6382072Svn83148 if (max_major < req_major) { 6392072Svn83148 *new_majorp = max_major; 6402072Svn83148 return (B_FALSE); 6412072Svn83148 } 6422072Svn83148 6432072Svn83148 /* 6442072Svn83148 * now we know that the requested version lies between the min and 6452072Svn83148 * max versions supported. check if the requested major can be 6462072Svn83148 * found in supported versions. 6472072Svn83148 */ 6482072Svn83148 lower_major = min_major; 6492072Svn83148 for (i = 0; i < DS_NUM_VER; i++) { 6502072Svn83148 major = ds_vers[i].major; 6512072Svn83148 if (major == req_major) { 6522072Svn83148 found_match = B_TRUE; 6532072Svn83148 *new_minorp = ds_vers[i].minor; 6542072Svn83148 *new_majorp = major; 6552072Svn83148 break; 6562072Svn83148 } else if ((major < req_major) && (major > lower_major)) 6572072Svn83148 lower_major = major; 6582072Svn83148 } 6592072Svn83148 6602072Svn83148 /* 6612072Svn83148 * If no match is found, return the closest available number 6622072Svn83148 */ 6632072Svn83148 if (!found_match) 6642072Svn83148 *new_majorp = lower_major; 6652072Svn83148 6662072Svn83148 return (found_match); 6672072Svn83148 } 6682072Svn83148 6692072Svn83148 6702072Svn83148 /* 6712072Svn83148 * return 0 if service is added; 1 if service is a duplicate 6722072Svn83148 */ 6732072Svn83148 static int 6742072Svn83148 fds_svc_add(struct ldmsvcs_info *lsp, ds_reg_req_t *req, int minor) 6752072Svn83148 { 6762072Svn83148 fds_svc_t *svc; 6772072Svn83148 int i, rc; 6782072Svn83148 6792072Svn83148 svc = NULL; 6802072Svn83148 for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) { 6812072Svn83148 if (strcmp(lsp->fmas_svcs.tbl[i]->name, req->svc_id) == 0) { 6822072Svn83148 svc = lsp->fmas_svcs.tbl[i]; 6832072Svn83148 break; 6842072Svn83148 } 6852072Svn83148 } 6862072Svn83148 6872072Svn83148 if (svc == NULL) 6882072Svn83148 return (0); /* we don't need this service */ 6892072Svn83148 6902072Svn83148 (void) pthread_mutex_lock(&lsp->fmas_svcs.mt); 6912072Svn83148 6922072Svn83148 /* 6932072Svn83148 * duplicate registration is OK --- we retain the previous entry 6942072Svn83148 * (which has not been unregistered anyway) 6952072Svn83148 */ 6962072Svn83148 if (svc->state == DS_SVC_ACTIVE) { 6972072Svn83148 rc = 1; 6982072Svn83148 } else { 6992072Svn83148 svc->state = DS_SVC_ACTIVE; 7002072Svn83148 svc->hdl = req->svc_handle; 7012072Svn83148 svc->ver.major = req->major_vers; 7022072Svn83148 svc->ver.minor = minor; 7032072Svn83148 7042072Svn83148 rc = 0; 7052072Svn83148 (void) pthread_cond_broadcast(&lsp->fmas_svcs.cv); 7062072Svn83148 } 7072072Svn83148 7082072Svn83148 (void) pthread_mutex_unlock(&lsp->fmas_svcs.mt); 7092072Svn83148 7102072Svn83148 return (rc); 7112072Svn83148 } 7122072Svn83148 7132072Svn83148 7142072Svn83148 static void 7152072Svn83148 fds_svc_reset(struct ldmsvcs_info *lsp, int index) 7162072Svn83148 { 7172072Svn83148 int i, start, end; 7182072Svn83148 7192072Svn83148 if (index >= 0) { 7202072Svn83148 start = index; 7212072Svn83148 end = index + 1; 7222072Svn83148 } else { 7232072Svn83148 start = 0; 7242072Svn83148 end = lsp->fmas_svcs.nsvcs; 7252072Svn83148 } 7262072Svn83148 7272072Svn83148 (void) pthread_mutex_lock(&lsp->fmas_svcs.mt); 7282072Svn83148 7292072Svn83148 for (i = start; i < end; i++) { 7302072Svn83148 lsp->fmas_svcs.tbl[i]->hdl = 0; 7312072Svn83148 lsp->fmas_svcs.tbl[i]->state = DS_SVC_INVAL; 7322072Svn83148 lsp->fmas_svcs.tbl[i]->ver.major = 7334358Srb144127 ds_vers[DS_NUM_VER - 1].major; 7342072Svn83148 lsp->fmas_svcs.tbl[i]->ver.minor = 7354358Srb144127 ds_vers[DS_NUM_VER - 1].minor; 7362072Svn83148 } 7372072Svn83148 7382072Svn83148 (void) pthread_mutex_unlock(&lsp->fmas_svcs.mt); 7392072Svn83148 } 7402072Svn83148 7412072Svn83148 7422072Svn83148 static int 7432072Svn83148 fds_svc_remove(struct ldmsvcs_info *lsp, ds_svc_hdl_t svc_handle) 7442072Svn83148 { 7452072Svn83148 int i; 7462072Svn83148 7472072Svn83148 for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) { 7482072Svn83148 if (lsp->fmas_svcs.tbl[i]->hdl == svc_handle) { 7492072Svn83148 fds_svc_reset(lsp, i); 7502072Svn83148 return (0); 7512072Svn83148 } 7522072Svn83148 } 7532072Svn83148 7542072Svn83148 return (1); 7552072Svn83148 } 7562072Svn83148 7572072Svn83148 7582072Svn83148 /* 7592072Svn83148 * message handlers 7602072Svn83148 */ 7612072Svn83148 /*ARGSUSED*/ 7622072Svn83148 static void 7632072Svn83148 ds_handle_msg_noop(struct ldmsvcs_info *lsp, void *buf, size_t len) 7642072Svn83148 { 7652072Svn83148 } 7662072Svn83148 7672072Svn83148 static void 7682072Svn83148 ds_handle_init_req(struct ldmsvcs_info *lsp, void *buf, size_t len) 7692072Svn83148 { 7702072Svn83148 ds_init_req_t *req; 7712072Svn83148 uint16_t new_major, new_minor; 7722072Svn83148 size_t msglen; 7732072Svn83148 7742072Svn83148 req = (ds_init_req_t *)buf; 7752072Svn83148 7762072Svn83148 /* sanity check the incoming message */ 7772072Svn83148 if (len != sizeof (ds_init_req_t)) { 7782072Svn83148 channel_close(lsp); 7792072Svn83148 return; 7802072Svn83148 } 7812072Svn83148 7822072Svn83148 /* 7832072Svn83148 * Check version info. ACK only if the major numbers exactly 7842072Svn83148 * match. The service entity can retry with a new minor 7852072Svn83148 * based on the response sent as part of the NACK. 7862072Svn83148 */ 7872072Svn83148 if (fds_negotiate_version(req->major_vers, &new_major, &new_minor)) { 7882072Svn83148 ds_hdr_t *H; 7892072Svn83148 ds_init_ack_t *R; 7902072Svn83148 7912072Svn83148 msglen = sizeof (ds_hdr_t) + sizeof (ds_init_ack_t); 7922072Svn83148 H = alloca(msglen); 7932072Svn83148 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 7942072Svn83148 7952072Svn83148 H->msg_type = DS_INIT_ACK; 7962072Svn83148 H->payload_len = sizeof (ds_init_ack_t); 7972072Svn83148 R->minor_vers = MIN(new_minor, req->minor_vers); 7982072Svn83148 7992072Svn83148 if (fds_send(lsp, H, msglen) != 0) 8002072Svn83148 return; 8012072Svn83148 8022072Svn83148 (void) pthread_mutex_lock(&lsp->mt); 8032072Svn83148 ASSERT(lsp->fds_chan.state == CHANNEL_OPEN); 8042072Svn83148 lsp->fds_chan.state = CHANNEL_READY; 8053327Svn83148 8063327Svn83148 /* 8073327Svn83148 * Now the channel is ready after the handshake completes. 8083327Svn83148 * Reset the timeout to a smaller value for receiving messages 8093327Svn83148 * from the domain services. 8103327Svn83148 */ 8114358Srb144127 lsp->cv_twait = get_smf_int_val(LDM_RUNNING_TO_PROP_NM, 8124358Srb144127 0, LDM_TIMEOUT_CEILING, LDM_RUNNING_WAIT_TIME); 8133327Svn83148 8142072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 8152072Svn83148 } else { 8162072Svn83148 ds_hdr_t *H; 8172072Svn83148 ds_init_nack_t *R; 8182072Svn83148 8192072Svn83148 msglen = sizeof (ds_hdr_t) + sizeof (ds_init_nack_t); 8202072Svn83148 H = alloca(msglen); 8212072Svn83148 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 8222072Svn83148 8232072Svn83148 H->msg_type = DS_INIT_NACK; 8242072Svn83148 H->payload_len = sizeof (ds_init_nack_t); 8252072Svn83148 R->major_vers = new_major; 8262072Svn83148 8272072Svn83148 (void) fds_send(lsp, H, msglen); 8282072Svn83148 /* 8292072Svn83148 * do not update state; remote end may attempt to initiate 8302072Svn83148 * connection with a different version 8312072Svn83148 */ 8322072Svn83148 } 8332072Svn83148 } 8342072Svn83148 8352072Svn83148 8362072Svn83148 /*ARGSUSED*/ 8372072Svn83148 static void 8382072Svn83148 ds_handle_reg_req(struct ldmsvcs_info *lsp, void *buf, size_t len) 8392072Svn83148 { 8402072Svn83148 ds_reg_req_t *req; 8412072Svn83148 char *msg; 8422072Svn83148 uint16_t new_major, new_minor; 8432072Svn83148 size_t msglen; 8442072Svn83148 int dup_svcreg = 0; 8452072Svn83148 8462072Svn83148 req = (ds_reg_req_t *)buf; 8472072Svn83148 msg = (char *)req->svc_id; 8482072Svn83148 8492072Svn83148 /* 8502072Svn83148 * Service must be NULL terminated 8512072Svn83148 */ 8522072Svn83148 if (req->svc_id == NULL || strlen(req->svc_id) == 0 || 8532072Svn83148 msg[strlen(req->svc_id)] != '\0') { 8542072Svn83148 channel_close(lsp); 8552072Svn83148 return; 8562072Svn83148 } 8572072Svn83148 8582072Svn83148 if (fds_negotiate_version(req->major_vers, &new_major, &new_minor) && 8592072Svn83148 (dup_svcreg = fds_svc_add(lsp, req, 8604358Srb144127 MIN(new_minor, req->minor_vers))) == 0) { 8612072Svn83148 8622072Svn83148 /* 8632072Svn83148 * Check version info. ACK only if the major numbers 8642072Svn83148 * exactly match. The service entity can retry with a new 8652072Svn83148 * minor based on the response sent as part of the NACK. 8662072Svn83148 */ 8672072Svn83148 ds_hdr_t *H; 8682072Svn83148 ds_reg_ack_t *R; 8692072Svn83148 8702072Svn83148 msglen = sizeof (ds_hdr_t) + sizeof (ds_reg_ack_t); 8712072Svn83148 H = alloca(msglen); 8722072Svn83148 bzero(H, msglen); 8732072Svn83148 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 8742072Svn83148 8752072Svn83148 H->msg_type = DS_REG_ACK; 8762072Svn83148 H->payload_len = sizeof (ds_reg_ack_t); 8772072Svn83148 R->svc_handle = req->svc_handle; 8782072Svn83148 R->minor_vers = MIN(new_minor, req->minor_vers); 8792072Svn83148 8802072Svn83148 (void) fds_send(lsp, H, msglen); 8812072Svn83148 } else { 8822072Svn83148 ds_hdr_t *H; 8832072Svn83148 ds_reg_nack_t *R; 8842072Svn83148 8852072Svn83148 msglen = sizeof (ds_hdr_t) + sizeof (ds_reg_nack_t); 8862072Svn83148 H = alloca(msglen); 8872072Svn83148 bzero(H, msglen); 8882072Svn83148 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 8892072Svn83148 8902072Svn83148 H->msg_type = DS_REG_NACK; 8912072Svn83148 H->payload_len = sizeof (ds_reg_nack_t); 8922072Svn83148 R->svc_handle = req->svc_handle; 8932072Svn83148 R->major_vers = new_major; 8942072Svn83148 8952072Svn83148 if (dup_svcreg) 8962072Svn83148 R->result = DS_REG_DUP; 8972072Svn83148 else 8982072Svn83148 R->result = DS_REG_VER_NACK; 8992072Svn83148 9002072Svn83148 (void) fds_send(lsp, H, msglen); 9012072Svn83148 } 9022072Svn83148 } 9032072Svn83148 9042072Svn83148 9052072Svn83148 /*ARGSUSED*/ 9062072Svn83148 static void 9072072Svn83148 ds_handle_unreg(struct ldmsvcs_info *lsp, void *buf, size_t len) 9082072Svn83148 { 9092072Svn83148 ds_unreg_req_t *req; 9102072Svn83148 size_t msglen; 9112072Svn83148 9122072Svn83148 req = (ds_unreg_req_t *)buf; 9132072Svn83148 9142072Svn83148 if (fds_svc_remove(lsp, req->svc_handle) == 0) { 9152072Svn83148 ds_hdr_t *H; 9162072Svn83148 ds_unreg_ack_t *R; 9172072Svn83148 9182072Svn83148 msglen = sizeof (ds_hdr_t) + sizeof (ds_unreg_ack_t); 9192072Svn83148 H = alloca(msglen); 9202072Svn83148 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 9212072Svn83148 9222072Svn83148 H->msg_type = DS_REG_ACK; 9232072Svn83148 H->payload_len = sizeof (ds_unreg_ack_t); 9242072Svn83148 R->svc_handle = req->svc_handle; 9252072Svn83148 9262072Svn83148 (void) fds_send(lsp, H, msglen); 9272072Svn83148 } else { 9282072Svn83148 ds_hdr_t *H; 9292072Svn83148 ds_unreg_nack_t *R; 9302072Svn83148 9312072Svn83148 msglen = sizeof (ds_hdr_t) + sizeof (ds_unreg_nack_t); 9322072Svn83148 H = alloca(msglen); 9332072Svn83148 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 9342072Svn83148 9352072Svn83148 H->msg_type = DS_REG_NACK; 9362072Svn83148 H->payload_len = sizeof (ds_unreg_nack_t); 9372072Svn83148 R->svc_handle = req->svc_handle; 9382072Svn83148 9392072Svn83148 (void) fds_send(lsp, H, msglen); 9402072Svn83148 } 9412072Svn83148 } 9422072Svn83148 9432072Svn83148 9442072Svn83148 /* 9452072Svn83148 * Message handler lookup table (v1.0 only for now) Future 9462072Svn83148 * versions can add their own lookup table. 9472072Svn83148 */ 9482072Svn83148 typedef void (*ds_msg_handler_t)(struct ldmsvcs_info *lsp, 9492072Svn83148 void *buf, size_t len); 9502072Svn83148 9512072Svn83148 static const ds_msg_handler_t ds_msg_handlers[] = { 9522072Svn83148 ds_handle_init_req, /* DS_INIT_REQ */ 9532072Svn83148 ds_handle_msg_noop, /* DS_INIT_ACK */ 9542072Svn83148 ds_handle_msg_noop, /* DS_INIT_NACK */ 9552072Svn83148 ds_handle_reg_req, /* DS_REG_REQ */ 9562072Svn83148 ds_handle_msg_noop, /* DS_REG_ACK */ 9572072Svn83148 ds_handle_msg_noop, /* DS_REG_NACK */ 9582072Svn83148 ds_handle_unreg, /* DS_UNREG */ 9592072Svn83148 ds_handle_msg_noop, /* DS_UNREG_ACK */ 9602072Svn83148 ds_handle_msg_noop, /* DS_UNREG_NACK */ 9612072Svn83148 ds_handle_msg_noop, /* DS_DATA */ 9622072Svn83148 ds_handle_msg_noop /* DS_NACK */ 9632072Svn83148 }; 9642072Svn83148 9652072Svn83148 9662072Svn83148 /* 9672072Svn83148 * message and service internal functions 9682072Svn83148 */ 9692072Svn83148 static void 9708634SVuong.Nguyen@Sun.COM fds_svc_alloc(struct ldmsvcs_info *lsp) 9712072Svn83148 { 9722072Svn83148 int i; 9737850SVuong.Nguyen@Sun.COM static char *name[] = { LDM_DS_NAME_CPU, LDM_DS_NAME_MEM, 9747850SVuong.Nguyen@Sun.COM LDM_DS_NAME_PRI, LDM_DS_NAME_IOD, NULL }; 9752072Svn83148 9762072Svn83148 (void) pthread_mutex_init(&lsp->fmas_svcs.mt, NULL); 9772072Svn83148 (void) pthread_cond_init(&lsp->fmas_svcs.cv, NULL); 9782072Svn83148 9792072Svn83148 for (lsp->fmas_svcs.nsvcs = 0; name[lsp->fmas_svcs.nsvcs] != NULL; 9802072Svn83148 lsp->fmas_svcs.nsvcs++) 9812072Svn83148 ; 9822072Svn83148 9838634SVuong.Nguyen@Sun.COM lsp->fmas_svcs.tbl = (fds_svc_t **)ldom_alloc(sizeof (fds_svc_t *) * 9844358Srb144127 lsp->fmas_svcs.nsvcs); 9852072Svn83148 9862072Svn83148 for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) { 9872072Svn83148 lsp->fmas_svcs.tbl[i] = 9888634SVuong.Nguyen@Sun.COM (fds_svc_t *)ldom_alloc(sizeof (fds_svc_t)); 9892072Svn83148 bzero(lsp->fmas_svcs.tbl[i], sizeof (fds_svc_t)); 9902072Svn83148 lsp->fmas_svcs.tbl[i]->name = name[i]; 9912072Svn83148 } 9922072Svn83148 } 9932072Svn83148 9942072Svn83148 9952072Svn83148 static fds_svc_t * 9962072Svn83148 fds_svc_lookup(struct ldmsvcs_info *lsp, char *name) 9972072Svn83148 { 9982072Svn83148 struct timespec twait; 9992072Svn83148 fds_svc_t *svc; 10002072Svn83148 int i, ier; 10012072Svn83148 10022072Svn83148 if (pthread_mutex_lock(&lsp->fmas_svcs.mt) == EINVAL) 10032072Svn83148 return (NULL); /* uninitialized or destroyed mutex */ 10042072Svn83148 10052072Svn83148 svc = NULL; 10062072Svn83148 for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) { 10072072Svn83148 if (strcmp(lsp->fmas_svcs.tbl[i]->name, name) == 0) { 10082072Svn83148 svc = lsp->fmas_svcs.tbl[i]; 10092072Svn83148 break; 10102072Svn83148 } 10112072Svn83148 } 10122072Svn83148 10132072Svn83148 ASSERT(svc != NULL); 10142072Svn83148 10157850SVuong.Nguyen@Sun.COM if (svc->state == DS_SVC_INACTIVE) { 10167850SVuong.Nguyen@Sun.COM /* service is not registered */ 10177850SVuong.Nguyen@Sun.COM ier = ETIMEDOUT; 10187850SVuong.Nguyen@Sun.COM } else { 10197850SVuong.Nguyen@Sun.COM ier = 0; 10207850SVuong.Nguyen@Sun.COM twait.tv_sec = time(NULL) + lsp->cv_twait; 10217850SVuong.Nguyen@Sun.COM twait.tv_nsec = 0; 10222072Svn83148 10237850SVuong.Nguyen@Sun.COM while (svc->state != DS_SVC_ACTIVE && ier == 0 && 10247850SVuong.Nguyen@Sun.COM lsp->fds_chan.state != CHANNEL_UNUSABLE) 10257850SVuong.Nguyen@Sun.COM ier = pthread_cond_timedwait(&lsp->fmas_svcs.cv, 10267850SVuong.Nguyen@Sun.COM &lsp->fmas_svcs.mt, &twait); 10277850SVuong.Nguyen@Sun.COM 10287850SVuong.Nguyen@Sun.COM /* 10297850SVuong.Nguyen@Sun.COM * By now, the ds service should have registered already. 10307850SVuong.Nguyen@Sun.COM * If it does not, ldmd probably does not support this service. 10317850SVuong.Nguyen@Sun.COM * Then mark the service state as inactive. 10327850SVuong.Nguyen@Sun.COM */ 10337850SVuong.Nguyen@Sun.COM if (ier == ETIMEDOUT) { 10347850SVuong.Nguyen@Sun.COM svc->state = DS_SVC_INACTIVE; 10357850SVuong.Nguyen@Sun.COM } 10367850SVuong.Nguyen@Sun.COM } 10372072Svn83148 10382072Svn83148 (void) pthread_mutex_unlock(&lsp->fmas_svcs.mt); 10392072Svn83148 10402072Svn83148 if (ier == 0) 10412072Svn83148 return (svc); 10422072Svn83148 else 10432072Svn83148 return (NULL); 10442072Svn83148 } 10452072Svn83148 10462072Svn83148 10472072Svn83148 static uint64_t 10482072Svn83148 fds_svc_req_num(void) 10492072Svn83148 { 10502072Svn83148 static uint64_t req_num = 1; 10512072Svn83148 10522072Svn83148 return (req_num++); 10532072Svn83148 } 10542072Svn83148 10552072Svn83148 10562072Svn83148 /* 10572072Svn83148 * return 0 if successful, 1 if otherwise 10582072Svn83148 */ 10592072Svn83148 static int 10602072Svn83148 read_msg(struct ldmsvcs_info *lsp) 10612072Svn83148 { 10622072Svn83148 ds_hdr_t header; 10632072Svn83148 void *msg_buf; 10642072Svn83148 10652072Svn83148 /* 10662072Svn83148 * read the header 10672072Svn83148 */ 10682072Svn83148 if (read_stream(lsp->fds_chan.fd, &header, sizeof (ds_hdr_t)) != 0) 10692072Svn83148 return (1); 10702072Svn83148 10712072Svn83148 if (header.msg_type >= 10722072Svn83148 sizeof (ds_msg_handlers) / sizeof (ds_msg_handler_t)) 10734358Srb144127 return (1); 10742072Svn83148 10752072Svn83148 /* 10762072Svn83148 * handle data as a special case 10772072Svn83148 */ 10782072Svn83148 if (header.msg_type == 9) 10792072Svn83148 return (poller_handle_data(lsp->fds_chan.fd, 10804358Srb144127 header.payload_len)); 10812072Svn83148 10822072Svn83148 /* 10832072Svn83148 * all other types of messages should be small 10842072Svn83148 */ 10852072Svn83148 ASSERT(header.payload_len < 1024); 10862072Svn83148 msg_buf = alloca(header.payload_len); 10872072Svn83148 10882072Svn83148 /* 10892072Svn83148 * read the payload 10902072Svn83148 */ 10912072Svn83148 if (read_stream(lsp->fds_chan.fd, msg_buf, header.payload_len) != 0) 10922072Svn83148 return (1); 10932072Svn83148 10942072Svn83148 (*ds_msg_handlers[header.msg_type])(lsp, msg_buf, header.payload_len); 10952072Svn83148 10962072Svn83148 return (0); 10972072Svn83148 } 10982072Svn83148 10992072Svn83148 11002072Svn83148 /* 11012072Svn83148 * return values: 11022072Svn83148 * 0 - success 11032072Svn83148 * 1 - problem with opening the channel 11042072Svn83148 * 2 - channed not opened; request to exit has been detected 11052072Svn83148 */ 11062072Svn83148 static int 11072072Svn83148 channel_openreset(struct ldmsvcs_info *lsp) 11082072Svn83148 { 11092072Svn83148 int ier; 11102072Svn83148 11112072Svn83148 ier = pthread_mutex_lock(&lsp->mt); 11122072Svn83148 11132072Svn83148 if (ier == EINVAL || lsp->fds_chan.state == CHANNEL_EXIT || 11142072Svn83148 lsp->fds_chan.state == CHANNEL_UNUSABLE) { 11152072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 11162072Svn83148 return (2); 11172072Svn83148 } 11182072Svn83148 11192072Svn83148 if (lsp->fds_chan.state == CHANNEL_UNINITIALIZED || 11202072Svn83148 lsp->fds_chan.state == CHANNEL_CLOSED) { 11212072Svn83148 (void) pthread_cond_broadcast(&lsp->cv); 11222072Svn83148 11232072Svn83148 if ((lsp->fds_chan.fd = open(FDS_VLDC, O_RDWR)) < 0) { 11242072Svn83148 lsp->fds_chan.state = CHANNEL_UNUSABLE; 11254358Srb144127 lsp->cv_twait = get_smf_int_val(LDM_RUNNING_TO_PROP_NM, 11264358Srb144127 0, LDM_TIMEOUT_CEILING, LDM_RUNNING_WAIT_TIME); 11272072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 11282072Svn83148 (void) pthread_cond_broadcast(&lsp->fmas_svcs.cv); 11292072Svn83148 11302072Svn83148 return (2); 11312072Svn83148 } else { 11322072Svn83148 vldc_opt_op_t op; 11332072Svn83148 11342072Svn83148 op.op_sel = VLDC_OP_SET; 11352072Svn83148 op.opt_sel = VLDC_OPT_MODE; 11366408Sha137994 op.opt_val = LDC_MODE_RELIABLE; 11372072Svn83148 11382072Svn83148 if (ioctl(lsp->fds_chan.fd, VLDC_IOCTL_OPT_OP, 11394358Srb144127 &op) != 0) { 11402072Svn83148 (void) close(lsp->fds_chan.fd); 11412072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 11422072Svn83148 return (1); 11432072Svn83148 } 11442072Svn83148 } 11452072Svn83148 lsp->fds_chan.state = CHANNEL_OPEN; 11462072Svn83148 } 11472072Svn83148 11482072Svn83148 if (lsp->fds_chan.state == CHANNEL_OPEN) { 11492072Svn83148 /* 11502072Svn83148 * reset various channel parameters 11512072Svn83148 */ 11522072Svn83148 lsp->fds_chan.ver.major = 0; 11532072Svn83148 lsp->fds_chan.ver.minor = 0; 11542072Svn83148 fds_svc_reset(lsp, -1); 11552072Svn83148 } 11562072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 11572072Svn83148 11582072Svn83148 return (0); 11592072Svn83148 } 11602072Svn83148 11612072Svn83148 11622072Svn83148 static void 11632072Svn83148 channel_fini(void) 11642072Svn83148 { 11658634SVuong.Nguyen@Sun.COM int i; 11662072Svn83148 struct ldmsvcs_info *lsp; 11672072Svn83148 11682072Svn83148 /* 11692072Svn83148 * End the poller thread 11702072Svn83148 */ 11718634SVuong.Nguyen@Sun.COM poller_fini(); 11722072Svn83148 11732072Svn83148 if ((lsp = channel_init(NULL)) == NULL) 11742072Svn83148 return; 11752072Svn83148 11762072Svn83148 (void) pthread_mutex_lock(&lsp->mt); 11772072Svn83148 11782072Svn83148 lsp->fds_chan.state = CHANNEL_EXIT; 11792072Svn83148 (void) close(lsp->fds_chan.fd); 11802072Svn83148 11812072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 11828634SVuong.Nguyen@Sun.COM 11838634SVuong.Nguyen@Sun.COM /* Free the ldom service structure */ 11848634SVuong.Nguyen@Sun.COM for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) { 11858634SVuong.Nguyen@Sun.COM ldom_free(lsp->fmas_svcs.tbl[i], sizeof (fds_svc_t)); 11868634SVuong.Nguyen@Sun.COM } 11878634SVuong.Nguyen@Sun.COM ldom_free(lsp->fmas_svcs.tbl, 11888634SVuong.Nguyen@Sun.COM lsp->fmas_svcs.nsvcs * sizeof (fds_svc_t *)); 11898634SVuong.Nguyen@Sun.COM ldom_free(lsp, sizeof (struct ldmsvcs_info)); 11902072Svn83148 } 11912072Svn83148 11922072Svn83148 11932072Svn83148 static struct ldmsvcs_info * 11942072Svn83148 channel_init(struct ldom_hdl *lhp) 11952072Svn83148 { 11962072Svn83148 static pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER; 11972072Svn83148 static pthread_cond_t cv = PTHREAD_COND_INITIALIZER; 11982072Svn83148 static struct ldmsvcs_info *root = NULL; 11992072Svn83148 static int busy_init = 0; 12002072Svn83148 12012072Svn83148 struct timespec twait; 12022072Svn83148 int expired; 12032072Svn83148 12042072Svn83148 (void) pthread_mutex_lock(&mt); 12052072Svn83148 12062072Svn83148 while (busy_init == 1) 12072072Svn83148 (void) pthread_cond_wait(&cv, &mt); 12082072Svn83148 12092072Svn83148 if (root != NULL || (lhp == NULL && root == NULL)) { 12102072Svn83148 (void) pthread_mutex_unlock(&mt); 12112072Svn83148 return (root); 12122072Svn83148 } 12132072Svn83148 12142072Svn83148 /* 12152072Svn83148 * get to this point if we need to open the channel 12162072Svn83148 */ 12172072Svn83148 busy_init = 1; 12182072Svn83148 (void) pthread_mutex_unlock(&mt); 12192072Svn83148 12202072Svn83148 root = (struct ldmsvcs_info *) 12218634SVuong.Nguyen@Sun.COM ldom_alloc(sizeof (struct ldmsvcs_info)); 12222072Svn83148 bzero(root, sizeof (struct ldmsvcs_info)); 12232072Svn83148 12242072Svn83148 root->fds_chan.state = CHANNEL_UNINITIALIZED; 12254358Srb144127 root->cv_twait = get_smf_int_val(LDM_INIT_TO_PROP_NM, 12264358Srb144127 0, LDM_TIMEOUT_CEILING, LDM_INIT_WAIT_TIME); 12272072Svn83148 12282072Svn83148 if (pthread_mutex_init(&root->mt, NULL) != 0 || 12292072Svn83148 pthread_cond_init(&root->cv, NULL) != 0) { 12308634SVuong.Nguyen@Sun.COM ldom_free(root, sizeof (struct ldmsvcs_info)); 12312072Svn83148 return (NULL); 12322072Svn83148 } 12332072Svn83148 12348634SVuong.Nguyen@Sun.COM fds_svc_alloc(root); 12352072Svn83148 fds_svc_reset(root, -1); 12362072Svn83148 12372072Svn83148 (void) poller_init(root); 12382072Svn83148 12392072Svn83148 expired = 0; 12402072Svn83148 twait.tv_sec = time(NULL) + 10; 12412072Svn83148 twait.tv_nsec = 0; 12422072Svn83148 12432072Svn83148 (void) pthread_mutex_lock(&root->mt); 12442072Svn83148 12452072Svn83148 /* 12462072Svn83148 * wait for channel to become uninitialized. this should be quick. 12472072Svn83148 */ 12482072Svn83148 while (root->fds_chan.state == CHANNEL_UNINITIALIZED && expired == 0) 12492072Svn83148 expired = pthread_cond_timedwait(&root->cv, &root->mt, &twait); 12502072Svn83148 12512072Svn83148 if (root->fds_chan.state == CHANNEL_UNUSABLE) 12522072Svn83148 expired = 1; 12532072Svn83148 12542072Svn83148 (void) pthread_mutex_unlock(&root->mt); 12552072Svn83148 12562072Svn83148 (void) pthread_mutex_lock(&mt); 12572072Svn83148 busy_init = 0; 12582072Svn83148 (void) pthread_mutex_unlock(&mt); 12592072Svn83148 (void) pthread_cond_broadcast(&cv); 12602072Svn83148 12612072Svn83148 (void) atexit(channel_fini); 12622072Svn83148 12632072Svn83148 if (expired == 0) 12642072Svn83148 return (root); 12652072Svn83148 else 12662072Svn83148 return (NULL); 12672072Svn83148 } 12682072Svn83148 12692072Svn83148 12702072Svn83148 static int 12712072Svn83148 sendrecv(struct ldom_hdl *lhp, uint64_t req_num, 12722072Svn83148 void *msg, size_t msglen, ds_svc_hdl_t *svc_hdl, char *svcname, 12732072Svn83148 void **resp, size_t *resplen) 12742072Svn83148 { 12752072Svn83148 struct ldmsvcs_info *lsp; 12762072Svn83148 fds_svc_t *svc; 12772072Svn83148 int maxretries, index, i, ier; 12782072Svn83148 12792072Svn83148 lsp = lhp->lsinfo; 12802072Svn83148 i = 0; 12812072Svn83148 maxretries = 1; 12822072Svn83148 12832072Svn83148 do { 12842072Svn83148 /* 12852072Svn83148 * if any of the calls in this loop fail, retry some number 12862072Svn83148 * of times before giving up. 12872072Svn83148 */ 12882072Svn83148 if ((svc = fds_svc_lookup(lsp, svcname)) == NULL) { 12892072Svn83148 (void) pthread_mutex_lock(&lsp->mt); 12902072Svn83148 12912072Svn83148 if (lsp->fds_chan.state != CHANNEL_READY) 12922072Svn83148 ier = ETIMEDOUT; /* channel not ready */ 12932072Svn83148 else 12942072Svn83148 ier = ENOTSUP; /* service not ready */ 12952072Svn83148 12962072Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 12972072Svn83148 12982072Svn83148 continue; 12992072Svn83148 } else { 13002072Svn83148 ier = 0; 13012072Svn83148 *svc_hdl = svc->hdl; 13022072Svn83148 } 13032072Svn83148 13048634SVuong.Nguyen@Sun.COM index = poller_add_pending(req_num); 13052072Svn83148 13062072Svn83148 if ((ier = fds_send(lsp, msg, msglen)) != 0 || 13072072Svn83148 (ier = poller_recv_data(lhp, req_num, index, resp, 13084358Srb144127 resplen)) != 0) 13092072Svn83148 poller_delete_pending(req_num, index); 13102072Svn83148 13112072Svn83148 } while (i++ < maxretries && ier != 0); 13122072Svn83148 13132072Svn83148 ASSERT(ier == 0 || ier == ETIMEDOUT || ier == ENOTSUP); 13142072Svn83148 13152072Svn83148 return (ier); 13162072Svn83148 } 13172072Svn83148 13182072Svn83148 13192072Svn83148 /* 13202072Svn83148 * input: 13212072Svn83148 * msg_type - requested operation: FMA_CPU_REQ_STATUS or FMA_CPU_REQ_OFFLINE 13222072Svn83148 * cpuid - physical cpu id 13232072Svn83148 * 13242072Svn83148 * normal return values: 13252072Svn83148 * P_OFFLINE - cpu is offline 13262072Svn83148 * P_ONLINE - cpu is online 13272072Svn83148 * 13282072Svn83148 * abnormal return values: 13292072Svn83148 * ETIMEDOUT - LDOM manager is not responding 13302072Svn83148 * ENOTSUP - LDOM service for cpu offlining/status is not available 13312072Svn83148 * ENOMSG - got an unexpected response from the LDOM cpu service 13322072Svn83148 */ 13332072Svn83148 static int 13342072Svn83148 cpu_request(struct ldom_hdl *lhp, uint32_t msg_type, uint32_t cpuid) 13352072Svn83148 { 13362072Svn83148 ds_hdr_t *H; 13372072Svn83148 ds_data_handle_t *D; 13382072Svn83148 fma_cpu_service_req_t *R; 13392072Svn83148 13407850SVuong.Nguyen@Sun.COM char *svcname = LDM_DS_NAME_CPU; 13412072Svn83148 fma_cpu_resp_t *respmsg; 13422072Svn83148 void *resp; 13432072Svn83148 size_t resplen, reqmsglen; 13442072Svn83148 int rc; 13452072Svn83148 13462072Svn83148 if (lhp->lsinfo == NULL) 13472072Svn83148 return (ENOMSG); 13482072Svn83148 13492072Svn83148 reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) + 13504358Srb144127 sizeof (fma_cpu_service_req_t); 13512072Svn83148 13522072Svn83148 H = lhp->allocp(reqmsglen); 13532072Svn83148 D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 13542072Svn83148 R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t)); 13552072Svn83148 13562072Svn83148 H->msg_type = DS_DATA; 13572072Svn83148 H->payload_len = sizeof (ds_data_handle_t) + 13584358Srb144127 sizeof (fma_cpu_service_req_t); 13592072Svn83148 13602072Svn83148 R->req_num = fds_svc_req_num(); 13612072Svn83148 R->msg_type = msg_type; 13622072Svn83148 R->cpu_id = cpuid; 13632072Svn83148 13642072Svn83148 if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen, 13654358Srb144127 &D->svc_handle, svcname, &resp, &resplen)) != 0) { 13662072Svn83148 lhp->freep(H, reqmsglen); 13672072Svn83148 return (rc); 13682072Svn83148 } 13692072Svn83148 13702072Svn83148 lhp->freep(H, reqmsglen); 13712072Svn83148 13722072Svn83148 ASSERT(resplen == sizeof (fma_cpu_resp_t)); 13732072Svn83148 respmsg = (fma_cpu_resp_t *)resp; 13742072Svn83148 13752072Svn83148 rc = ENOMSG; 13762072Svn83148 if (respmsg->result == FMA_CPU_RESP_OK) { 13772072Svn83148 if (respmsg->status == FMA_CPU_STAT_ONLINE) 13782072Svn83148 rc = P_ONLINE; 13792072Svn83148 else if (respmsg->status == FMA_CPU_STAT_OFFLINE) 13802072Svn83148 rc = P_OFFLINE; 13812072Svn83148 } else { 13822072Svn83148 if (msg_type == FMA_CPU_REQ_OFFLINE && 13832072Svn83148 respmsg->status == FMA_CPU_STAT_OFFLINE) 13842072Svn83148 rc = P_OFFLINE; 13852072Svn83148 } 13862072Svn83148 13872072Svn83148 lhp->freep(resp, resplen); 13882072Svn83148 13892072Svn83148 return (rc); 13902072Svn83148 } 13912072Svn83148 13922072Svn83148 13932072Svn83148 /* 13942072Svn83148 * input: 13952072Svn83148 * msg_type - requested operation: FMA_MEM_REQ_STATUS or FMA_MEM_REQ_RETIRE 13962072Svn83148 * pa - starting address of memory page 13972072Svn83148 * pgsize - memory page size in bytes 13982072Svn83148 * 13992072Svn83148 * normal return values for msg_type == FMA_MEM_REQ_STATUS: 14002072Svn83148 * 0 - page is retired 14012072Svn83148 * EAGAIN - page is scheduled for retirement 14022072Svn83148 * EIO - page not scheduled for retirement 14032072Svn83148 * EINVAL - error 14042072Svn83148 * 14052072Svn83148 * normal return values for msg_type == FMA_MEM_REQ_RETIRE: 14062072Svn83148 * 0 - success in retiring page 14072072Svn83148 * EIO - page is already retired 14082072Svn83148 * EAGAIN - page is scheduled for retirement 14092072Svn83148 * EINVAL - error 14102072Svn83148 * 14112072Svn83148 * abnormal return values (regardless of msg_type) 14122072Svn83148 * ETIMEDOUT - LDOM manager is not responding 14132072Svn83148 * ENOTSUP - LDOM service for cpu offlining/status is not available 14142072Svn83148 * ENOMSG - got an unexpected response from the LDOM cpu service 14152072Svn83148 */ 14162072Svn83148 static int 14172072Svn83148 mem_request(struct ldom_hdl *lhp, uint32_t msg_type, uint64_t pa, 14182072Svn83148 uint64_t pgsize) 14192072Svn83148 { 14202072Svn83148 ds_hdr_t *H; 14212072Svn83148 ds_data_handle_t *D; 14222072Svn83148 fma_mem_service_req_t *R; 14232072Svn83148 14247850SVuong.Nguyen@Sun.COM char *svcname = LDM_DS_NAME_MEM; 14252072Svn83148 fma_mem_resp_t *respmsg; 14262072Svn83148 void *resp; 14272072Svn83148 size_t resplen, reqmsglen; 14282072Svn83148 int rc; 14292072Svn83148 14302072Svn83148 if (lhp->lsinfo == NULL) 14312072Svn83148 return (ENOMSG); 14322072Svn83148 14332072Svn83148 reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) + 14344358Srb144127 sizeof (fma_mem_service_req_t); 14352072Svn83148 14362072Svn83148 H = lhp->allocp(reqmsglen); 14372072Svn83148 bzero(H, reqmsglen); 14382072Svn83148 D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 14392072Svn83148 R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t)); 14402072Svn83148 14412072Svn83148 H->msg_type = DS_DATA; 14422072Svn83148 H->payload_len = sizeof (ds_data_handle_t) + 14434358Srb144127 sizeof (fma_mem_service_req_t); 14442072Svn83148 14452072Svn83148 R->req_num = fds_svc_req_num(); 14462072Svn83148 R->msg_type = msg_type; 14472072Svn83148 R->real_addr = pa; 14482072Svn83148 R->length = pgsize; 14492072Svn83148 14502072Svn83148 if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen, 14514358Srb144127 &D->svc_handle, svcname, &resp, &resplen)) != 0) { 14522072Svn83148 lhp->freep(H, reqmsglen); 14532072Svn83148 return (rc); 14542072Svn83148 } 14552072Svn83148 14562072Svn83148 lhp->freep(H, reqmsglen); 14572072Svn83148 14582072Svn83148 ASSERT(resplen == sizeof (fma_mem_resp_t)); 14592072Svn83148 respmsg = (fma_mem_resp_t *)resp; 14602072Svn83148 14612072Svn83148 rc = ENOMSG; 14622072Svn83148 if (msg_type == FMA_MEM_REQ_STATUS) { 14632072Svn83148 if (respmsg->result == FMA_MEM_RESP_OK) { 14642072Svn83148 if (respmsg->status == FMA_MEM_STAT_RETIRED) 14654655Svn83148 rc = 0; /* page is retired */ 14662072Svn83148 else if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 14674655Svn83148 rc = EIO; /* page is not scheduled */ 14682072Svn83148 } else if (respmsg->result == FMA_MEM_RESP_FAILURE) { 14694655Svn83148 if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 14704655Svn83148 rc = EAGAIN; /* page is scheduled */ 14714655Svn83148 else if (respmsg->status == FMA_MEM_STAT_ILLEGAL) 14722072Svn83148 rc = EINVAL; 14732072Svn83148 } 14742072Svn83148 } else if (msg_type == FMA_MEM_REQ_RETIRE) { 14752072Svn83148 if (respmsg->result == FMA_MEM_RESP_OK) { 14762072Svn83148 if (respmsg->status == FMA_MEM_STAT_RETIRED) 14774655Svn83148 rc = 0; /* is successfully retired */ 14782072Svn83148 } else if (respmsg->result == FMA_MEM_RESP_FAILURE) { 14792072Svn83148 if (respmsg->status == FMA_MEM_STAT_RETIRED) 14804655Svn83148 rc = EIO; /* is already retired */ 14814655Svn83148 else if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 14824655Svn83148 rc = EAGAIN; /* is scheduled to retire */ 14832072Svn83148 else if (respmsg->status == FMA_MEM_STAT_ILLEGAL) 14842072Svn83148 rc = EINVAL; 14852072Svn83148 } 14867532SSean.Ye@Sun.COM } else if (msg_type == FMA_MEM_REQ_RESURRECT) { 14877532SSean.Ye@Sun.COM if (respmsg->result == FMA_MEM_RESP_OK) { 14887532SSean.Ye@Sun.COM if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 14897532SSean.Ye@Sun.COM rc = 0; /* is successfully unretired */ 14907532SSean.Ye@Sun.COM } if (respmsg->result == FMA_MEM_RESP_FAILURE) { 14917532SSean.Ye@Sun.COM if (respmsg->status == FMA_MEM_STAT_RETIRED) 14927532SSean.Ye@Sun.COM rc = EAGAIN; /* page couldn't be locked */ 14937532SSean.Ye@Sun.COM else if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 14947532SSean.Ye@Sun.COM rc = EIO; /* page isn't retired already */ 14957532SSean.Ye@Sun.COM else if (respmsg->status == FMA_MEM_STAT_ILLEGAL) 14967532SSean.Ye@Sun.COM rc = EINVAL; 14977532SSean.Ye@Sun.COM } 14982072Svn83148 } 14992072Svn83148 15002072Svn83148 lhp->freep(resp, resplen); 15012072Svn83148 15022072Svn83148 return (rc); 15032072Svn83148 } 15042072Svn83148 15052072Svn83148 15062072Svn83148 /* 15072072Svn83148 * APIs 15082072Svn83148 */ 15092072Svn83148 int 15102072Svn83148 ldmsvcs_check_channel(void) 15112072Svn83148 { 15122072Svn83148 struct stat buf; 15132072Svn83148 15142072Svn83148 if (stat(FDS_VLDC, &buf) == 0) 15152072Svn83148 return (0); /* vldc exists */ 15162072Svn83148 else if (errno == ENOENT || errno == ENOTDIR) 15172072Svn83148 return (1); /* vldc does not exist */ 15182072Svn83148 else 15192072Svn83148 return (-1); /* miscellaneous error */ 15202072Svn83148 } 15212072Svn83148 15222072Svn83148 15232072Svn83148 /*ARGSUSED*/ 15242072Svn83148 void 15252072Svn83148 ldmsvcs_init(struct ldom_hdl *lhp) 15262072Svn83148 { 15272072Svn83148 if (ldmsvcs_check_channel() != 0) 15282072Svn83148 return; 15292072Svn83148 15302072Svn83148 lhp->lsinfo = channel_init(lhp); 15312072Svn83148 poller_add_client(); 15322072Svn83148 } 15332072Svn83148 15342072Svn83148 15352072Svn83148 /*ARGSUSED*/ 15362072Svn83148 void 15372072Svn83148 ldmsvcs_fini(struct ldom_hdl *lhp) 15382072Svn83148 { 15392072Svn83148 if (ldmsvcs_check_channel() != 0) 15402072Svn83148 return; 15412072Svn83148 15422072Svn83148 poller_remove_client(); 15432072Svn83148 } 15442072Svn83148 15452072Svn83148 15462072Svn83148 /*ARGSUSED*/ 15472072Svn83148 ssize_t 15482072Svn83148 ldmsvcs_get_core_md(struct ldom_hdl *lhp, uint64_t **buf) 15492072Svn83148 { 15502072Svn83148 ds_hdr_t *H; 15512072Svn83148 ds_data_handle_t *D; 15522072Svn83148 fma_req_pri_t *R; 15532072Svn83148 15547850SVuong.Nguyen@Sun.COM char *svcname = LDM_DS_NAME_PRI; 15552072Svn83148 void *resp; 15562072Svn83148 size_t resplen, reqmsglen; 15572072Svn83148 ssize_t buflen; 15582072Svn83148 int rc; 15592072Svn83148 15602072Svn83148 if (lhp->lsinfo == NULL) 15612072Svn83148 return (-1); 15622072Svn83148 15632072Svn83148 reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) + 15644358Srb144127 sizeof (fma_req_pri_t); 15652072Svn83148 15662072Svn83148 H = lhp->allocp(reqmsglen); 15672072Svn83148 D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 15682072Svn83148 R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t)); 15692072Svn83148 15702072Svn83148 H->msg_type = DS_DATA; 15712072Svn83148 H->payload_len = sizeof (ds_data_handle_t) + 15724358Srb144127 sizeof (fma_req_pri_t); 15732072Svn83148 15742072Svn83148 R->req_num = fds_svc_req_num(); 15752072Svn83148 15762072Svn83148 if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen, 15774358Srb144127 &D->svc_handle, svcname, &resp, &resplen)) != 0) { 15782072Svn83148 lhp->freep(H, reqmsglen); 15792072Svn83148 errno = rc; 15802072Svn83148 return (-1); 15812072Svn83148 } 15822072Svn83148 15832072Svn83148 lhp->freep(H, reqmsglen); 15842072Svn83148 15852072Svn83148 /* 15862072Svn83148 * resp should contain the req_num immediately followed by the PRI 15872072Svn83148 * (the latter may or may not be present). unfortunately, the 15882072Svn83148 * current compiler flags cause a warning for the following 15892072Svn83148 * definition 15902072Svn83148 * 15912072Svn83148 * typedef struct { 15922072Svn83148 * uint64_t req_num; 15932072Svn83148 * uint8_t pri[]; 15942072Svn83148 * } fma_pri_resp_t; 15952072Svn83148 * 15962072Svn83148 * so we do not use the struct here. 15972072Svn83148 */ 15982072Svn83148 if (resplen <= sizeof (uint64_t)) { 15992072Svn83148 lhp->freep(resp, resplen); 16002072Svn83148 if (resplen == sizeof (uint64_t)) 16012072Svn83148 return (0); 16022072Svn83148 else 16032072Svn83148 return (-1); 16042072Svn83148 } 16052072Svn83148 16062072Svn83148 buflen = resplen - sizeof (uint64_t); 16072072Svn83148 *buf = lhp->allocp(buflen); 16082072Svn83148 16092072Svn83148 bcopy((void *)((ptrdiff_t)resp + sizeof (uint64_t)), *buf, buflen); 16102072Svn83148 lhp->freep(resp, resplen); 16112072Svn83148 16122072Svn83148 return (buflen); 16132072Svn83148 } 16142072Svn83148 16152072Svn83148 16162072Svn83148 /* 16172072Svn83148 * see cpu_request() for a description of return values 16182072Svn83148 */ 16192072Svn83148 int 16202072Svn83148 ldmsvcs_cpu_req_status(struct ldom_hdl *lhp, uint32_t cpuid) 16212072Svn83148 { 16222072Svn83148 return (cpu_request(lhp, FMA_CPU_REQ_STATUS, cpuid)); 16232072Svn83148 } 16242072Svn83148 16252072Svn83148 16262072Svn83148 int 16272072Svn83148 ldmsvcs_cpu_req_offline(struct ldom_hdl *lhp, uint32_t cpuid) 16282072Svn83148 { 16292072Svn83148 return (cpu_request(lhp, FMA_CPU_REQ_OFFLINE, cpuid)); 16302072Svn83148 } 16312072Svn83148 16326111Scy152378 int 16336111Scy152378 ldmsvcs_cpu_req_online(struct ldom_hdl *lhp, uint32_t cpuid) 16346111Scy152378 { 16356111Scy152378 return (cpu_request(lhp, FMA_CPU_REQ_ONLINE, cpuid)); 16366111Scy152378 } 16372072Svn83148 16382072Svn83148 /* 16392072Svn83148 * see mem_request() for a description of return values 16402072Svn83148 */ 16412072Svn83148 int 16422072Svn83148 ldmsvcs_mem_req_status(struct ldom_hdl *lhp, uint64_t pa) 16432072Svn83148 { 16442072Svn83148 return (mem_request(lhp, FMA_MEM_REQ_STATUS, pa, getpagesize())); 16452072Svn83148 } 16462072Svn83148 16472072Svn83148 int 16482072Svn83148 ldmsvcs_mem_req_retire(struct ldom_hdl *lhp, uint64_t pa) 16492072Svn83148 { 16502072Svn83148 return (mem_request(lhp, FMA_MEM_REQ_RETIRE, pa, getpagesize())); 16512072Svn83148 } 16522072Svn83148 16536111Scy152378 int 16546111Scy152378 ldmsvcs_mem_req_unretire(struct ldom_hdl *lhp, uint64_t pa) 16556111Scy152378 { 16566111Scy152378 return (mem_request(lhp, FMA_MEM_REQ_RESURRECT, pa, getpagesize())); 16576111Scy152378 } 16586111Scy152378 16597850SVuong.Nguyen@Sun.COM int 16607850SVuong.Nguyen@Sun.COM ldmsvcs_io_req_id(struct ldom_hdl *lhp, uint64_t addr, uint_t type, 16617850SVuong.Nguyen@Sun.COM uint64_t *virt_addr, char *name, int name_len, uint64_t *did) 16627850SVuong.Nguyen@Sun.COM { 16637850SVuong.Nguyen@Sun.COM 16647850SVuong.Nguyen@Sun.COM ds_hdr_t *H; 16657850SVuong.Nguyen@Sun.COM ds_data_handle_t *D; 16667850SVuong.Nguyen@Sun.COM fma_io_req_t *R; 16677850SVuong.Nguyen@Sun.COM 16687850SVuong.Nguyen@Sun.COM char *svcname = LDM_DS_NAME_IOD; 16697850SVuong.Nguyen@Sun.COM void *resp; 16707850SVuong.Nguyen@Sun.COM fma_io_resp_t *iop; 16717850SVuong.Nguyen@Sun.COM size_t resplen, reqmsglen; 16727850SVuong.Nguyen@Sun.COM int offset; 16737850SVuong.Nguyen@Sun.COM int rc; 16747850SVuong.Nguyen@Sun.COM 16757850SVuong.Nguyen@Sun.COM if (lhp->lsinfo == NULL) 16767850SVuong.Nguyen@Sun.COM return (-1); 16777850SVuong.Nguyen@Sun.COM 16787850SVuong.Nguyen@Sun.COM reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) + 16797850SVuong.Nguyen@Sun.COM sizeof (fma_io_req_t); 16807850SVuong.Nguyen@Sun.COM 16817850SVuong.Nguyen@Sun.COM H = lhp->allocp(reqmsglen); 16827850SVuong.Nguyen@Sun.COM D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 16837850SVuong.Nguyen@Sun.COM R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t)); 16847850SVuong.Nguyen@Sun.COM 16857850SVuong.Nguyen@Sun.COM H->msg_type = DS_DATA; 16867850SVuong.Nguyen@Sun.COM H->payload_len = sizeof (ds_data_handle_t) + sizeof (fma_io_req_t); 16877850SVuong.Nguyen@Sun.COM 16887850SVuong.Nguyen@Sun.COM R->req_num = fds_svc_req_num(); 16897850SVuong.Nguyen@Sun.COM R->msg_type = type; 16907850SVuong.Nguyen@Sun.COM R->rsrc_address = addr; 16917850SVuong.Nguyen@Sun.COM 16927850SVuong.Nguyen@Sun.COM rc = ENOMSG; 16937850SVuong.Nguyen@Sun.COM if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen, 16947850SVuong.Nguyen@Sun.COM &D->svc_handle, svcname, &resp, &resplen)) != 0) { 16957850SVuong.Nguyen@Sun.COM lhp->freep(H, reqmsglen); 16967850SVuong.Nguyen@Sun.COM return (rc); 16977850SVuong.Nguyen@Sun.COM } 16987850SVuong.Nguyen@Sun.COM lhp->freep(H, reqmsglen); 16997850SVuong.Nguyen@Sun.COM 17007850SVuong.Nguyen@Sun.COM /* 17017850SVuong.Nguyen@Sun.COM * resp should contain the req_num, status, virtual addr, domain id 17027850SVuong.Nguyen@Sun.COM * and the domain name. The domain name may or may not be present. 17037850SVuong.Nguyen@Sun.COM */ 17047850SVuong.Nguyen@Sun.COM offset = sizeof (fma_io_resp_t); 17057850SVuong.Nguyen@Sun.COM if (resplen < offset) { 17067850SVuong.Nguyen@Sun.COM lhp->freep(resp, resplen); 17077850SVuong.Nguyen@Sun.COM return (-1); 17087850SVuong.Nguyen@Sun.COM } 17097850SVuong.Nguyen@Sun.COM 17107850SVuong.Nguyen@Sun.COM iop = (fma_io_resp_t *)resp; 17117850SVuong.Nguyen@Sun.COM switch (iop->result) { 17127850SVuong.Nguyen@Sun.COM case FMA_IO_RESP_OK: 17137850SVuong.Nguyen@Sun.COM /* success */ 17147850SVuong.Nguyen@Sun.COM rc = 0; 17157850SVuong.Nguyen@Sun.COM *virt_addr = iop->virt_rsrc_address; 17167850SVuong.Nguyen@Sun.COM *did = iop->domain_id; 17177850SVuong.Nguyen@Sun.COM if (name == NULL || name_len <= 0) 17187850SVuong.Nguyen@Sun.COM break; 17197850SVuong.Nguyen@Sun.COM *name = '\0'; 17207850SVuong.Nguyen@Sun.COM if (resplen > offset) { 17217850SVuong.Nguyen@Sun.COM (void) strncpy(name, (char *)((ptrdiff_t)resp + offset), 17227850SVuong.Nguyen@Sun.COM name_len); 17237850SVuong.Nguyen@Sun.COM } 17247850SVuong.Nguyen@Sun.COM break; 17257850SVuong.Nguyen@Sun.COM default: 17267850SVuong.Nguyen@Sun.COM rc = -1; 17277850SVuong.Nguyen@Sun.COM break; 17287850SVuong.Nguyen@Sun.COM } 17297850SVuong.Nguyen@Sun.COM 17307850SVuong.Nguyen@Sun.COM lhp->freep(resp, resplen); 17317850SVuong.Nguyen@Sun.COM return (rc); 17327850SVuong.Nguyen@Sun.COM } 17337850SVuong.Nguyen@Sun.COM 17342072Svn83148 /* end file */ 1735