131e37bb4Svn83148 /* 231e37bb4Svn83148 * CDDL HEADER START 331e37bb4Svn83148 * 431e37bb4Svn83148 * The contents of this file are subject to the terms of the 531e37bb4Svn83148 * Common Development and Distribution License (the "License"). 631e37bb4Svn83148 * You may not use this file except in compliance with the License. 731e37bb4Svn83148 * 831e37bb4Svn83148 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 931e37bb4Svn83148 * or http://www.opensolaris.org/os/licensing. 1031e37bb4Svn83148 * See the License for the specific language governing permissions 1131e37bb4Svn83148 * and limitations under the License. 1231e37bb4Svn83148 * 1331e37bb4Svn83148 * When distributing Covered Code, include this CDDL HEADER in each 1431e37bb4Svn83148 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1531e37bb4Svn83148 * If applicable, add the following below this CDDL HEADER, with the 1631e37bb4Svn83148 * fields enclosed by brackets "[]" replaced with your own identifying 1731e37bb4Svn83148 * information: Portions Copyright [yyyy] [name of copyright owner] 1831e37bb4Svn83148 * 1931e37bb4Svn83148 * CDDL HEADER END 2031e37bb4Svn83148 */ 2131e37bb4Svn83148 /* 22*f044df33SVuong Nguyen * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 2331e37bb4Svn83148 */ 2431e37bb4Svn83148 2531e37bb4Svn83148 #include <stdlib.h> 2631e37bb4Svn83148 #include <stdio.h> 2725351652SVuong Nguyen 2831e37bb4Svn83148 #include <strings.h> 2931e37bb4Svn83148 #include <sys/types.h> 3031e37bb4Svn83148 #include <sys/stat.h> 3131e37bb4Svn83148 #include <time.h> 3231e37bb4Svn83148 #include <fcntl.h> 3331e37bb4Svn83148 #include <unistd.h> 3431e37bb4Svn83148 #include <errno.h> 3531e37bb4Svn83148 #include <assert.h> 3631e37bb4Svn83148 #include <umem.h> 3731e37bb4Svn83148 #include <alloca.h> 3831e37bb4Svn83148 #include <sys/processor.h> 3931e37bb4Svn83148 #include <poll.h> 4031e37bb4Svn83148 #include <pthread.h> 413dc13b01SVuong Nguyen #include <signal.h> 42c3b50bc5Srb144127 #include <values.h> 43c3b50bc5Srb144127 #include <libscf.h> 4431e37bb4Svn83148 4525351652SVuong Nguyen #include <ctype.h> 4625351652SVuong Nguyen 4731e37bb4Svn83148 #include "ldmsvcs_utils.h" 483dc13b01SVuong Nguyen #include "ldom_alloc.h" 49e6590bdcSVuong Nguyen #include "ldom_utils.h" 5031e37bb4Svn83148 5131e37bb4Svn83148 #define ASSERT(cnd) \ 5231e37bb4Svn83148 ((void) ((cnd) || ((void) fprintf(stderr, \ 5331e37bb4Svn83148 "assertion failure in %s:%d: %s\n", \ 5431e37bb4Svn83148 __FILE__, __LINE__, #cnd), 0))) 5531e37bb4Svn83148 5631e37bb4Svn83148 #define FDS_VLDC \ 5731e37bb4Svn83148 "/devices/virtual-devices@100/channel-devices@200/" \ 5831e37bb4Svn83148 "/virtual-channel-client@1:ldmfma" 5931e37bb4Svn83148 60c3b50bc5Srb144127 /* allow timeouts in sec that are nearly forever but small enough for an int */ 61c3b50bc5Srb144127 #define LDM_TIMEOUT_CEILING (MAXINT / 2) 6231e37bb4Svn83148 6331e37bb4Svn83148 #define MIN(x, y) ((x) < (y) ? (x) : (y)) 6431e37bb4Svn83148 6531e37bb4Svn83148 /* 6631e37bb4Svn83148 * functions in this file are for version 1.0 of FMA domain services 6731e37bb4Svn83148 */ 6831e37bb4Svn83148 static ds_ver_t ds_vers[] = { 6931e37bb4Svn83148 { 1, 0 } 7031e37bb4Svn83148 }; 7131e37bb4Svn83148 7231e37bb4Svn83148 #define DS_NUM_VER (sizeof (ds_vers) / sizeof (ds_ver_t)) 7331e37bb4Svn83148 7431e37bb4Svn83148 /* 7531e37bb4Svn83148 * information for each channel 7631e37bb4Svn83148 */ 7731e37bb4Svn83148 struct ldmsvcs_info { 7831e37bb4Svn83148 pthread_mutex_t mt; 7931e37bb4Svn83148 pthread_cond_t cv; 8031e37bb4Svn83148 fds_channel_t fds_chan; 8131e37bb4Svn83148 fds_reg_svcs_t fmas_svcs; 8231e37bb4Svn83148 int cv_twait; 8331e37bb4Svn83148 }; 8431e37bb4Svn83148 8531e37bb4Svn83148 /* 8631e37bb4Svn83148 * struct listdata_s and struct poller_s are used to maintain the state of 8731e37bb4Svn83148 * the poller thread. this thread is used to manage incoming messages and 8831e37bb4Svn83148 * pass those messages onto the correct requesting thread. see the "poller 8931e37bb4Svn83148 * functions" section for more details. 9031e37bb4Svn83148 */ 9131e37bb4Svn83148 struct listdata_s { 9231e37bb4Svn83148 enum { 9331e37bb4Svn83148 UNUSED, 9431e37bb4Svn83148 PENDING, 9531e37bb4Svn83148 ARRIVED 9631e37bb4Svn83148 } status; 9731e37bb4Svn83148 uint64_t req_num; 9831e37bb4Svn83148 int fd; 9931e37bb4Svn83148 size_t datalen; 10031e37bb4Svn83148 }; 10131e37bb4Svn83148 10231e37bb4Svn83148 static struct poller_s { 10331e37bb4Svn83148 pthread_mutex_t mt; 10431e37bb4Svn83148 pthread_cond_t cv; 10531e37bb4Svn83148 pthread_t polling_tid; 106*f044df33SVuong Nguyen int notify_pipe[2]; 10731e37bb4Svn83148 int doreset; 10831e37bb4Svn83148 int doexit; 10931e37bb4Svn83148 int nclients; 11031e37bb4Svn83148 struct listdata_s **list; 11131e37bb4Svn83148 int list_len; 11231e37bb4Svn83148 int pending_count; 11331e37bb4Svn83148 } pollbase = { 11431e37bb4Svn83148 PTHREAD_MUTEX_INITIALIZER, 11531e37bb4Svn83148 PTHREAD_COND_INITIALIZER, 11631e37bb4Svn83148 0, 117*f044df33SVuong Nguyen {-1, -1}, 11831e37bb4Svn83148 1, 11931e37bb4Svn83148 0, 12031e37bb4Svn83148 0, 12131e37bb4Svn83148 NULL, 12231e37bb4Svn83148 0, 12331e37bb4Svn83148 0 12431e37bb4Svn83148 }; 12531e37bb4Svn83148 12631e37bb4Svn83148 12731e37bb4Svn83148 static struct ldmsvcs_info *channel_init(struct ldom_hdl *lhp); 12831e37bb4Svn83148 static int channel_openreset(struct ldmsvcs_info *lsp); 12931e37bb4Svn83148 static int read_msg(struct ldmsvcs_info *lsp); 13031e37bb4Svn83148 131c3b50bc5Srb144127 static int 132c3b50bc5Srb144127 get_smf_int_val(char *prop_nm, int min, int max, int default_val) 133c3b50bc5Srb144127 { 134c3b50bc5Srb144127 scf_simple_prop_t *prop; /* SMF property */ 135c3b50bc5Srb144127 int64_t *valp; /* prop value ptr */ 136c3b50bc5Srb144127 int64_t val; /* prop value to return */ 137c3b50bc5Srb144127 138c3b50bc5Srb144127 val = default_val; 139c3b50bc5Srb144127 if ((prop = scf_simple_prop_get(NULL, LDM_SVC_NM, LDM_PROP_GROUP_NM, 140c3b50bc5Srb144127 prop_nm)) != NULL) { 141c3b50bc5Srb144127 if ((valp = scf_simple_prop_next_integer(prop)) != NULL) { 142c3b50bc5Srb144127 val = *valp; 143c3b50bc5Srb144127 if (val < min) 144c3b50bc5Srb144127 val = min; 145c3b50bc5Srb144127 else if (val > max) 146c3b50bc5Srb144127 val = max; 147c3b50bc5Srb144127 } 148c3b50bc5Srb144127 scf_simple_prop_free(prop); 149c3b50bc5Srb144127 } 150c3b50bc5Srb144127 return ((int)val); 151c3b50bc5Srb144127 } 152c3b50bc5Srb144127 15331e37bb4Svn83148 static void 15431e37bb4Svn83148 channel_close(struct ldmsvcs_info *lsp) 15531e37bb4Svn83148 { 15631e37bb4Svn83148 (void) pthread_mutex_lock(&lsp->mt); 15731e37bb4Svn83148 158a298b85fSvn83148 if (lsp->fds_chan.state == CHANNEL_OPEN || 159a298b85fSvn83148 lsp->fds_chan.state == CHANNEL_READY) { 16031e37bb4Svn83148 (void) close(lsp->fds_chan.fd); 161c3b50bc5Srb144127 lsp->cv_twait = get_smf_int_val(LDM_INIT_TO_PROP_NM, 162c3b50bc5Srb144127 0, LDM_TIMEOUT_CEILING, LDM_INIT_WAIT_TIME); 163a298b85fSvn83148 lsp->fds_chan.state = CHANNEL_CLOSED; 164a298b85fSvn83148 } 16531e37bb4Svn83148 16631e37bb4Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 16731e37bb4Svn83148 } 16831e37bb4Svn83148 16931e37bb4Svn83148 /* 17031e37bb4Svn83148 * read size bytes of data from a streaming fd into buf 17131e37bb4Svn83148 */ 17231e37bb4Svn83148 static int 17331e37bb4Svn83148 read_stream(int fd, void *buf, size_t size) 17431e37bb4Svn83148 { 17531e37bb4Svn83148 pollfd_t pollfd; 17631e37bb4Svn83148 ssize_t rv; 17731e37bb4Svn83148 size_t data_left; 17831e37bb4Svn83148 ptrdiff_t currentp; 17931e37bb4Svn83148 18031e37bb4Svn83148 pollfd.events = POLLIN; 18131e37bb4Svn83148 pollfd.revents = 0; 18231e37bb4Svn83148 pollfd.fd = fd; 18331e37bb4Svn83148 18431e37bb4Svn83148 currentp = (ptrdiff_t)buf; 18531e37bb4Svn83148 data_left = size; 18631e37bb4Svn83148 18731e37bb4Svn83148 /* 18831e37bb4Svn83148 * data may come in bits and pieces 18931e37bb4Svn83148 */ 19031e37bb4Svn83148 do { 19131e37bb4Svn83148 if ((rv = read(fd, (void *)currentp, data_left)) < 0) { 192*f044df33SVuong Nguyen if (errno == EAGAIN && poll(&pollfd, 1, 3000) > 0) 19331e37bb4Svn83148 continue; /* retry */ 19431e37bb4Svn83148 else 19531e37bb4Svn83148 return (1); 19631e37bb4Svn83148 } 19731e37bb4Svn83148 19831e37bb4Svn83148 data_left -= rv; 19931e37bb4Svn83148 currentp += rv; 20031e37bb4Svn83148 } while (data_left > 0); 20131e37bb4Svn83148 20231e37bb4Svn83148 return (0); 20331e37bb4Svn83148 } 20431e37bb4Svn83148 20531e37bb4Svn83148 20631e37bb4Svn83148 /* 20731e37bb4Svn83148 * poller functions 20831e37bb4Svn83148 * 20931e37bb4Svn83148 * at init time, a thread is created for the purpose of monitoring incoming 21031e37bb4Svn83148 * messages and doing one of the following: 21131e37bb4Svn83148 * 21231e37bb4Svn83148 * 1. doing the initial handshake and version negotiation 21331e37bb4Svn83148 * 21431e37bb4Svn83148 * 2. handing incoming data off to the requesting thread (which is an fmd 21531e37bb4Svn83148 * module or scheme thread) 21631e37bb4Svn83148 */ 21731e37bb4Svn83148 static int 21831e37bb4Svn83148 poller_handle_data(int fd, size_t payloadsize) 21931e37bb4Svn83148 { 22031e37bb4Svn83148 uint64_t *req_num; 22131e37bb4Svn83148 void *pr; 22231e37bb4Svn83148 size_t prlen; 22331e37bb4Svn83148 int i; 22431e37bb4Svn83148 22531e37bb4Svn83148 prlen = sizeof (ds_data_handle_t) + sizeof (uint64_t); 22631e37bb4Svn83148 22731e37bb4Svn83148 if (payloadsize < prlen) 22831e37bb4Svn83148 return (1); 22931e37bb4Svn83148 23031e37bb4Svn83148 pr = alloca(prlen); 23131e37bb4Svn83148 23231e37bb4Svn83148 if (read_stream(fd, pr, prlen) != 0) 23331e37bb4Svn83148 return (1); 23431e37bb4Svn83148 23531e37bb4Svn83148 req_num = (uint64_t *)((ptrdiff_t)pr + sizeof (ds_data_handle_t)); 23631e37bb4Svn83148 23731e37bb4Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 23831e37bb4Svn83148 23931e37bb4Svn83148 for (i = 0; i < pollbase.list_len; i++) { 24031e37bb4Svn83148 if (pollbase.list[i]->req_num == *req_num) { 24131e37bb4Svn83148 ASSERT(pollbase.list[i]->status == PENDING); 24231e37bb4Svn83148 24331e37bb4Svn83148 pollbase.list[i]->status = ARRIVED; 24431e37bb4Svn83148 pollbase.list[i]->fd = fd; 24531e37bb4Svn83148 pollbase.list[i]->datalen = payloadsize - prlen; 24631e37bb4Svn83148 24731e37bb4Svn83148 pollbase.pending_count--; 24831e37bb4Svn83148 (void) pthread_cond_broadcast(&pollbase.cv); 24931e37bb4Svn83148 break; 25031e37bb4Svn83148 } 25131e37bb4Svn83148 } 25231e37bb4Svn83148 25331e37bb4Svn83148 /* 25431e37bb4Svn83148 * now wait for receiving thread to read in the data 25531e37bb4Svn83148 */ 25631e37bb4Svn83148 if (i < pollbase.list_len) { 25731e37bb4Svn83148 while (pollbase.list[i]->status == ARRIVED) 25831e37bb4Svn83148 (void) pthread_cond_wait(&pollbase.cv, &pollbase.mt); 25931e37bb4Svn83148 } 26031e37bb4Svn83148 26131e37bb4Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 26231e37bb4Svn83148 26331e37bb4Svn83148 return (0); 26431e37bb4Svn83148 } 26531e37bb4Svn83148 26631e37bb4Svn83148 26731e37bb4Svn83148 /* 26831e37bb4Svn83148 * note that this function is meant to handle only DS_DATA messages 26931e37bb4Svn83148 */ 27031e37bb4Svn83148 static int 27131e37bb4Svn83148 poller_recv_data(struct ldom_hdl *lhp, uint64_t req_num, int index, 27231e37bb4Svn83148 void **resp, size_t *resplen) 27331e37bb4Svn83148 { 27431e37bb4Svn83148 struct timespec twait; 27531e37bb4Svn83148 int ier; 27631e37bb4Svn83148 27731e37bb4Svn83148 ier = 0; 27831e37bb4Svn83148 twait.tv_sec = time(NULL) + lhp->lsinfo->cv_twait; 27931e37bb4Svn83148 twait.tv_nsec = 0; 28031e37bb4Svn83148 28131e37bb4Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 28231e37bb4Svn83148 28331e37bb4Svn83148 ASSERT(pollbase.list[index]->req_num == req_num); 28431e37bb4Svn83148 28531e37bb4Svn83148 while (pollbase.list[index]->status == PENDING && 28631e37bb4Svn83148 pollbase.doreset == 0 && ier == 0) 28731e37bb4Svn83148 ier = pthread_cond_timedwait(&pollbase.cv, &pollbase.mt, 28831e37bb4Svn83148 &twait); 28931e37bb4Svn83148 29031e37bb4Svn83148 if (ier == 0) { 29131e37bb4Svn83148 if (pollbase.doreset == 0) { 29231e37bb4Svn83148 ASSERT(pollbase.list[index]->status == ARRIVED); 29331e37bb4Svn83148 29431e37bb4Svn83148 /* 29531e37bb4Svn83148 * need to add req_num to beginning of resp 29631e37bb4Svn83148 */ 29731e37bb4Svn83148 *resplen = pollbase.list[index]->datalen + 29831e37bb4Svn83148 sizeof (uint64_t); 29931e37bb4Svn83148 *resp = lhp->allocp(*resplen); 30031e37bb4Svn83148 *((uint64_t *)*resp) = req_num; 30131e37bb4Svn83148 30231e37bb4Svn83148 if (read_stream(pollbase.list[index]->fd, 30331e37bb4Svn83148 (void *)((ptrdiff_t)*resp + sizeof (uint64_t)), 30431e37bb4Svn83148 *resplen - sizeof (uint64_t)) != 0) 30531e37bb4Svn83148 ier = ETIMEDOUT; 30631e37bb4Svn83148 30731e37bb4Svn83148 pollbase.list[index]->status = UNUSED; 30831e37bb4Svn83148 pollbase.list[index]->req_num = 0; 30931e37bb4Svn83148 (void) pthread_cond_broadcast(&pollbase.cv); 31031e37bb4Svn83148 } else { 31131e37bb4Svn83148 if (--(pollbase.pending_count) == 0) 31231e37bb4Svn83148 (void) pthread_cond_broadcast(&pollbase.cv); 31331e37bb4Svn83148 } 31431e37bb4Svn83148 } 31531e37bb4Svn83148 31631e37bb4Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 31731e37bb4Svn83148 31831e37bb4Svn83148 ASSERT(ier == 0 || ier == ETIMEDOUT); 31931e37bb4Svn83148 32031e37bb4Svn83148 return (ier); 32131e37bb4Svn83148 } 32231e37bb4Svn83148 32331e37bb4Svn83148 32431e37bb4Svn83148 static void 32531e37bb4Svn83148 poller_add_client(void) 32631e37bb4Svn83148 { 32731e37bb4Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 32831e37bb4Svn83148 pollbase.nclients++; 32931e37bb4Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 33031e37bb4Svn83148 } 33131e37bb4Svn83148 33231e37bb4Svn83148 33331e37bb4Svn83148 static void 33431e37bb4Svn83148 poller_remove_client(void) 33531e37bb4Svn83148 { 33631e37bb4Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 33731e37bb4Svn83148 pollbase.nclients--; 33831e37bb4Svn83148 ASSERT(pollbase.nclients >= 0); 33931e37bb4Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 34031e37bb4Svn83148 } 34131e37bb4Svn83148 34231e37bb4Svn83148 34331e37bb4Svn83148 static int 3443dc13b01SVuong Nguyen poller_add_pending(uint64_t req_num) 34531e37bb4Svn83148 { 34631e37bb4Svn83148 int newlen, index, i, j; 34731e37bb4Svn83148 34831e37bb4Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 34931e37bb4Svn83148 pollbase.pending_count++; 35031e37bb4Svn83148 35131e37bb4Svn83148 for (j = 0, index = -1; j < 2 && index == -1; j++) { 35231e37bb4Svn83148 for (i = 0; i < pollbase.list_len; i++) { 35331e37bb4Svn83148 if (pollbase.list[i]->status == UNUSED) { 35431e37bb4Svn83148 pollbase.list[i]->status = PENDING; 35531e37bb4Svn83148 pollbase.list[i]->req_num = req_num; 35631e37bb4Svn83148 pollbase.list[i]->datalen = 0; 35731e37bb4Svn83148 index = i; 35831e37bb4Svn83148 break; 35931e37bb4Svn83148 } 36031e37bb4Svn83148 } 36131e37bb4Svn83148 36231e37bb4Svn83148 if (index == -1) { 36331e37bb4Svn83148 struct listdata_s **newlist, **oldlist; 36431e37bb4Svn83148 36531e37bb4Svn83148 /* 36631e37bb4Svn83148 * get to this point if list is not long enough. 36731e37bb4Svn83148 * check for a runaway list. since requests are 36831e37bb4Svn83148 * synchronous (clients send a request and need to 36931e37bb4Svn83148 * wait for the result before returning) the size 37031e37bb4Svn83148 * of the list cannot be much more than the number 37131e37bb4Svn83148 * of clients. 37231e37bb4Svn83148 */ 37331e37bb4Svn83148 ASSERT(pollbase.list_len < pollbase.nclients + 1); 37431e37bb4Svn83148 37531e37bb4Svn83148 newlen = pollbase.list_len + 5; 3763dc13b01SVuong Nguyen newlist = ldom_alloc(newlen * 3773dc13b01SVuong Nguyen sizeof (struct listdata_s *)); 37831e37bb4Svn83148 37931e37bb4Svn83148 for (i = 0; i < pollbase.list_len; i++) 38031e37bb4Svn83148 newlist[i] = pollbase.list[i]; 38131e37bb4Svn83148 38231e37bb4Svn83148 oldlist = pollbase.list; 38331e37bb4Svn83148 pollbase.list = newlist; 3843dc13b01SVuong Nguyen ldom_free(oldlist, pollbase.list_len * 3853dc13b01SVuong Nguyen sizeof (struct listdata_s *)); 38631e37bb4Svn83148 38731e37bb4Svn83148 for (i = pollbase.list_len; i < newlen; i++) { 38831e37bb4Svn83148 pollbase.list[i] = 3893dc13b01SVuong Nguyen ldom_alloc(sizeof (struct listdata_s)); 39031e37bb4Svn83148 pollbase.list[i]->status = UNUSED; 39131e37bb4Svn83148 } 39231e37bb4Svn83148 39331e37bb4Svn83148 pollbase.list_len = newlen; 39431e37bb4Svn83148 } 39531e37bb4Svn83148 } 39631e37bb4Svn83148 39731e37bb4Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 39831e37bb4Svn83148 ASSERT(index != -1); 39931e37bb4Svn83148 40031e37bb4Svn83148 return (index); 40131e37bb4Svn83148 } 40231e37bb4Svn83148 40331e37bb4Svn83148 40431e37bb4Svn83148 static void 40531e37bb4Svn83148 poller_delete_pending(uint64_t req_num, int index) 40631e37bb4Svn83148 { 40731e37bb4Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 40831e37bb4Svn83148 40931e37bb4Svn83148 ASSERT(pollbase.list[index]->req_num == req_num); 41031e37bb4Svn83148 pollbase.list[index]->status = UNUSED; 41131e37bb4Svn83148 41231e37bb4Svn83148 if (--(pollbase.pending_count) == 0 && pollbase.doreset == 1) 41331e37bb4Svn83148 (void) pthread_cond_broadcast(&pollbase.cv); 41431e37bb4Svn83148 41531e37bb4Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 41631e37bb4Svn83148 } 41731e37bb4Svn83148 41831e37bb4Svn83148 41931e37bb4Svn83148 static void 4203dc13b01SVuong Nguyen poller_shutdown(boolean_t wait) 42131e37bb4Svn83148 { 42231e37bb4Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 42331e37bb4Svn83148 42431e37bb4Svn83148 pollbase.doexit = 1; 42531e37bb4Svn83148 42631e37bb4Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 4273dc13b01SVuong Nguyen 4283dc13b01SVuong Nguyen if (wait == B_TRUE) { 429*f044df33SVuong Nguyen /* 430*f044df33SVuong Nguyen * Write a byte to the pipe to notify the poller thread to exit. 431*f044df33SVuong Nguyen * Then wait for it to exit. 432*f044df33SVuong Nguyen */ 433*f044df33SVuong Nguyen (void) write(pollbase.notify_pipe[0], "1", 1); 4343dc13b01SVuong Nguyen (void) pthread_join(pollbase.polling_tid, NULL); 4353dc13b01SVuong Nguyen } 43631e37bb4Svn83148 } 43731e37bb4Svn83148 43831e37bb4Svn83148 43931e37bb4Svn83148 /* 44031e37bb4Svn83148 * perform the polling of incoming messages. manage any resets (usually 44131e37bb4Svn83148 * due to one end of the connection being closed) as well as exit 44231e37bb4Svn83148 * conditions. 44331e37bb4Svn83148 */ 44431e37bb4Svn83148 static void * 44531e37bb4Svn83148 poller_loop(void *arg) 44631e37bb4Svn83148 { 44731e37bb4Svn83148 struct ldmsvcs_info *lsp; 448*f044df33SVuong Nguyen pollfd_t pollfd[2]; 449*f044df33SVuong Nguyen struct pollfd *pipe_fd = &pollfd[0]; 450*f044df33SVuong Nguyen struct pollfd *recv_fd = &pollfd[1]; 45131e37bb4Svn83148 int ier; 45231e37bb4Svn83148 45331e37bb4Svn83148 lsp = (struct ldmsvcs_info *)arg; 45431e37bb4Svn83148 45531e37bb4Svn83148 for (;;) { 45631e37bb4Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 45731e37bb4Svn83148 45831e37bb4Svn83148 if (pollbase.doexit) { 45931e37bb4Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 46031e37bb4Svn83148 break; 46131e37bb4Svn83148 } 46231e37bb4Svn83148 46331e37bb4Svn83148 if (pollbase.doreset) { 46431e37bb4Svn83148 int i; 46531e37bb4Svn83148 46631e37bb4Svn83148 while (pollbase.pending_count > 0) 46731e37bb4Svn83148 (void) pthread_cond_wait(&pollbase.cv, 46831e37bb4Svn83148 &pollbase.mt); 46931e37bb4Svn83148 47031e37bb4Svn83148 ASSERT(pollbase.pending_count == 0); 47131e37bb4Svn83148 for (i = 0; i < pollbase.list_len; i++) 47231e37bb4Svn83148 pollbase.list[i]->status = UNUSED; 47331e37bb4Svn83148 47431e37bb4Svn83148 pollbase.doreset = 0; 47531e37bb4Svn83148 } 476*f044df33SVuong Nguyen 47731e37bb4Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 47831e37bb4Svn83148 47931e37bb4Svn83148 if ((ier = channel_openreset(lsp)) == 1) { 48031e37bb4Svn83148 continue; 48131e37bb4Svn83148 } else if (ier == 2) { 48231e37bb4Svn83148 /* 48331e37bb4Svn83148 * start exit preparations 48431e37bb4Svn83148 */ 4853dc13b01SVuong Nguyen poller_shutdown(B_FALSE); 48631e37bb4Svn83148 continue; 48731e37bb4Svn83148 } 48831e37bb4Svn83148 489*f044df33SVuong Nguyen pipe_fd->fd = pollbase.notify_pipe[1]; /* notification pipe */ 490*f044df33SVuong Nguyen pipe_fd->events = POLLIN; 491*f044df33SVuong Nguyen pipe_fd->revents = 0; 492*f044df33SVuong Nguyen recv_fd->fd = lsp->fds_chan.fd; /* FMA LDC */ 493*f044df33SVuong Nguyen recv_fd->events = POLLIN; 494*f044df33SVuong Nguyen recv_fd->revents = 0; 49531e37bb4Svn83148 496*f044df33SVuong Nguyen if (poll(pollfd, 2, -1) <= 0) { 497*f044df33SVuong Nguyen /* fd got closed */ 49831e37bb4Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 49931e37bb4Svn83148 pollbase.doreset = 1; 50031e37bb4Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 501*f044df33SVuong Nguyen channel_close(lsp); 502*f044df33SVuong Nguyen } else if (pipe_fd->revents & POLLIN) { 503*f044df33SVuong Nguyen /* Receive a notification to exit */ 504*f044df33SVuong Nguyen channel_close(lsp); 505*f044df33SVuong Nguyen pthread_exit((void *)NULL); 506*f044df33SVuong Nguyen } else if (read_msg(lsp) != 0) { 507*f044df33SVuong Nguyen /* fail to read a message from the LDOM manager */ 508*f044df33SVuong Nguyen (void) pthread_mutex_lock(&pollbase.mt); 509*f044df33SVuong Nguyen pollbase.doreset = 1; 510*f044df33SVuong Nguyen (void) pthread_mutex_unlock(&pollbase.mt); 51131e37bb4Svn83148 channel_close(lsp); 51231e37bb4Svn83148 } 51331e37bb4Svn83148 } 51431e37bb4Svn83148 51531e37bb4Svn83148 return (NULL); 51631e37bb4Svn83148 } 51731e37bb4Svn83148 51831e37bb4Svn83148 51931e37bb4Svn83148 /* 52031e37bb4Svn83148 * create the polling thread 52131e37bb4Svn83148 */ 52231e37bb4Svn83148 static int 52331e37bb4Svn83148 poller_init(struct ldmsvcs_info *lsp) 52431e37bb4Svn83148 { 52531e37bb4Svn83148 int rc = 0; 52631e37bb4Svn83148 52731e37bb4Svn83148 (void) pthread_mutex_lock(&pollbase.mt); 52831e37bb4Svn83148 52931e37bb4Svn83148 if (pollbase.polling_tid == 0) { 5303dc13b01SVuong Nguyen pthread_attr_t *attr = NULL; 53131e37bb4Svn83148 53231e37bb4Svn83148 /* 5333dc13b01SVuong Nguyen * create a joinable polling thread for receiving messages 534*f044df33SVuong Nguyen * The notify pipe is for stopping the thread 53531e37bb4Svn83148 */ 536*f044df33SVuong Nguyen (void) notify_setup(pollbase.notify_pipe); 5373dc13b01SVuong Nguyen if (pthread_create(&pollbase.polling_tid, attr, 53831e37bb4Svn83148 poller_loop, lsp) != 0) 53931e37bb4Svn83148 rc = 1; 54031e37bb4Svn83148 } 54131e37bb4Svn83148 54231e37bb4Svn83148 (void) pthread_mutex_unlock(&pollbase.mt); 54331e37bb4Svn83148 54431e37bb4Svn83148 return (rc); 54531e37bb4Svn83148 } 54631e37bb4Svn83148 5473dc13b01SVuong Nguyen /* 5483dc13b01SVuong Nguyen * Cleanup the polling thread 5493dc13b01SVuong Nguyen */ 5503dc13b01SVuong Nguyen static void 5513dc13b01SVuong Nguyen poller_fini(void) 5523dc13b01SVuong Nguyen { 5533dc13b01SVuong Nguyen int i; 5543dc13b01SVuong Nguyen 5553dc13b01SVuong Nguyen /* stop the poller thread */ 5563dc13b01SVuong Nguyen poller_shutdown(B_TRUE); 5573dc13b01SVuong Nguyen 5583dc13b01SVuong Nguyen (void) pthread_mutex_lock(&pollbase.mt); 5593dc13b01SVuong Nguyen 5603dc13b01SVuong Nguyen /* Free up the list of outstanding requests */ 5613dc13b01SVuong Nguyen if (pollbase.list != NULL) { 5623dc13b01SVuong Nguyen for (i = 0; i < pollbase.list_len; i++) { 5633dc13b01SVuong Nguyen if (pollbase.list[i]) { 5643dc13b01SVuong Nguyen ldom_free(pollbase.list[i], 5653dc13b01SVuong Nguyen sizeof (struct listdata_s)); 5663dc13b01SVuong Nguyen } 5673dc13b01SVuong Nguyen } 5683dc13b01SVuong Nguyen ldom_free(pollbase.list, pollbase.list_len * 5693dc13b01SVuong Nguyen sizeof (struct listdata_s *)); 5703dc13b01SVuong Nguyen pollbase.list = NULL; 5713dc13b01SVuong Nguyen pollbase.list_len = 0; 5723dc13b01SVuong Nguyen } 5733dc13b01SVuong Nguyen 5743dc13b01SVuong Nguyen (void) pthread_mutex_unlock(&pollbase.mt); 5753dc13b01SVuong Nguyen } 57631e37bb4Svn83148 57731e37bb4Svn83148 /* 57831e37bb4Svn83148 * utilities for message handlers 57931e37bb4Svn83148 */ 58031e37bb4Svn83148 static int 58131e37bb4Svn83148 fds_send(struct ldmsvcs_info *lsp, void *msg, size_t msglen) 58231e37bb4Svn83148 { 58331e37bb4Svn83148 static pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER; 58431e37bb4Svn83148 58531e37bb4Svn83148 (void) pthread_mutex_lock(&mt); 58631e37bb4Svn83148 58731e37bb4Svn83148 if (write(lsp->fds_chan.fd, msg, msglen) != msglen) { 58831e37bb4Svn83148 channel_close(lsp); 58931e37bb4Svn83148 (void) pthread_mutex_unlock(&mt); 59031e37bb4Svn83148 return (ETIMEDOUT); 59131e37bb4Svn83148 } 59231e37bb4Svn83148 59331e37bb4Svn83148 (void) pthread_mutex_unlock(&mt); 59431e37bb4Svn83148 return (0); 59531e37bb4Svn83148 } 59631e37bb4Svn83148 59731e37bb4Svn83148 59831e37bb4Svn83148 /* 59931e37bb4Svn83148 * Find the max and min version supported 60031e37bb4Svn83148 */ 60131e37bb4Svn83148 static void 60231e37bb4Svn83148 fds_min_max_versions(uint16_t *min_major, uint16_t *max_major) 60331e37bb4Svn83148 { 60431e37bb4Svn83148 int i; 60531e37bb4Svn83148 60631e37bb4Svn83148 *min_major = ds_vers[0].major; 60731e37bb4Svn83148 *max_major = *min_major; 60831e37bb4Svn83148 60931e37bb4Svn83148 for (i = 1; i < DS_NUM_VER; i++) { 61031e37bb4Svn83148 if (ds_vers[i].major < *min_major) 61131e37bb4Svn83148 *min_major = ds_vers[i].major; 61231e37bb4Svn83148 61331e37bb4Svn83148 if (ds_vers[i].major > *max_major) 61431e37bb4Svn83148 *max_major = ds_vers[i].major; 61531e37bb4Svn83148 } 61631e37bb4Svn83148 } 61731e37bb4Svn83148 61831e37bb4Svn83148 /* 61931e37bb4Svn83148 * check whether the major and minor numbers requested by remote ds client 62031e37bb4Svn83148 * can be satisfied. if the requested major is supported, true is 62131e37bb4Svn83148 * returned, and the agreed minor is returned in new_minor. if the 62231e37bb4Svn83148 * requested major is not supported, the routine returns false, and the 62331e37bb4Svn83148 * closest major is returned in *new_major, upon which the ds client should 62431e37bb4Svn83148 * renegotiate. the closest major is the just lower that the requested 62531e37bb4Svn83148 * major number. 62631e37bb4Svn83148 */ 62731e37bb4Svn83148 static boolean_t 62831e37bb4Svn83148 fds_negotiate_version(uint16_t req_major, uint16_t *new_majorp, 62931e37bb4Svn83148 uint16_t *new_minorp) 63031e37bb4Svn83148 { 63131e37bb4Svn83148 int i = 0; 63231e37bb4Svn83148 uint16_t major, lower_major; 63331e37bb4Svn83148 uint16_t min_major, max_major; 63431e37bb4Svn83148 boolean_t found_match = B_FALSE; 63531e37bb4Svn83148 63631e37bb4Svn83148 fds_min_max_versions(&min_major, &max_major); 63731e37bb4Svn83148 63831e37bb4Svn83148 /* 63931e37bb4Svn83148 * if the minimum version supported is greater than the version 64031e37bb4Svn83148 * requested, return the lowest version supported 64131e37bb4Svn83148 */ 64231e37bb4Svn83148 if (min_major > req_major) { 64331e37bb4Svn83148 *new_majorp = min_major; 64431e37bb4Svn83148 return (B_FALSE); 64531e37bb4Svn83148 } 64631e37bb4Svn83148 64731e37bb4Svn83148 /* 64831e37bb4Svn83148 * if the largest version supported is lower than the version 64931e37bb4Svn83148 * requested, return the largest version supported 65031e37bb4Svn83148 */ 65131e37bb4Svn83148 if (max_major < req_major) { 65231e37bb4Svn83148 *new_majorp = max_major; 65331e37bb4Svn83148 return (B_FALSE); 65431e37bb4Svn83148 } 65531e37bb4Svn83148 65631e37bb4Svn83148 /* 65731e37bb4Svn83148 * now we know that the requested version lies between the min and 65831e37bb4Svn83148 * max versions supported. check if the requested major can be 65931e37bb4Svn83148 * found in supported versions. 66031e37bb4Svn83148 */ 66131e37bb4Svn83148 lower_major = min_major; 66231e37bb4Svn83148 for (i = 0; i < DS_NUM_VER; i++) { 66331e37bb4Svn83148 major = ds_vers[i].major; 66431e37bb4Svn83148 if (major == req_major) { 66531e37bb4Svn83148 found_match = B_TRUE; 66631e37bb4Svn83148 *new_minorp = ds_vers[i].minor; 66731e37bb4Svn83148 *new_majorp = major; 66831e37bb4Svn83148 break; 66931e37bb4Svn83148 } else if ((major < req_major) && (major > lower_major)) 67031e37bb4Svn83148 lower_major = major; 67131e37bb4Svn83148 } 67231e37bb4Svn83148 67331e37bb4Svn83148 /* 67431e37bb4Svn83148 * If no match is found, return the closest available number 67531e37bb4Svn83148 */ 67631e37bb4Svn83148 if (!found_match) 67731e37bb4Svn83148 *new_majorp = lower_major; 67831e37bb4Svn83148 67931e37bb4Svn83148 return (found_match); 68031e37bb4Svn83148 } 68131e37bb4Svn83148 68231e37bb4Svn83148 68331e37bb4Svn83148 /* 68431e37bb4Svn83148 * return 0 if service is added; 1 if service is a duplicate 68531e37bb4Svn83148 */ 68631e37bb4Svn83148 static int 68731e37bb4Svn83148 fds_svc_add(struct ldmsvcs_info *lsp, ds_reg_req_t *req, int minor) 68831e37bb4Svn83148 { 68931e37bb4Svn83148 fds_svc_t *svc; 69031e37bb4Svn83148 int i, rc; 69131e37bb4Svn83148 69231e37bb4Svn83148 svc = NULL; 69331e37bb4Svn83148 for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) { 69431e37bb4Svn83148 if (strcmp(lsp->fmas_svcs.tbl[i]->name, req->svc_id) == 0) { 69531e37bb4Svn83148 svc = lsp->fmas_svcs.tbl[i]; 69631e37bb4Svn83148 break; 69731e37bb4Svn83148 } 69831e37bb4Svn83148 } 69931e37bb4Svn83148 70031e37bb4Svn83148 if (svc == NULL) 70131e37bb4Svn83148 return (0); /* we don't need this service */ 70231e37bb4Svn83148 70331e37bb4Svn83148 (void) pthread_mutex_lock(&lsp->fmas_svcs.mt); 70431e37bb4Svn83148 70531e37bb4Svn83148 /* 70631e37bb4Svn83148 * duplicate registration is OK --- we retain the previous entry 70731e37bb4Svn83148 * (which has not been unregistered anyway) 70831e37bb4Svn83148 */ 70931e37bb4Svn83148 if (svc->state == DS_SVC_ACTIVE) { 71031e37bb4Svn83148 rc = 1; 71131e37bb4Svn83148 } else { 71231e37bb4Svn83148 svc->state = DS_SVC_ACTIVE; 71331e37bb4Svn83148 svc->hdl = req->svc_handle; 71431e37bb4Svn83148 svc->ver.major = req->major_vers; 71531e37bb4Svn83148 svc->ver.minor = minor; 71631e37bb4Svn83148 71731e37bb4Svn83148 rc = 0; 71831e37bb4Svn83148 (void) pthread_cond_broadcast(&lsp->fmas_svcs.cv); 71931e37bb4Svn83148 } 72031e37bb4Svn83148 72131e37bb4Svn83148 (void) pthread_mutex_unlock(&lsp->fmas_svcs.mt); 72231e37bb4Svn83148 72331e37bb4Svn83148 return (rc); 72431e37bb4Svn83148 } 72531e37bb4Svn83148 72631e37bb4Svn83148 72731e37bb4Svn83148 static void 72831e37bb4Svn83148 fds_svc_reset(struct ldmsvcs_info *lsp, int index) 72931e37bb4Svn83148 { 73031e37bb4Svn83148 int i, start, end; 73131e37bb4Svn83148 73231e37bb4Svn83148 if (index >= 0) { 73331e37bb4Svn83148 start = index; 73431e37bb4Svn83148 end = index + 1; 73531e37bb4Svn83148 } else { 73631e37bb4Svn83148 start = 0; 73731e37bb4Svn83148 end = lsp->fmas_svcs.nsvcs; 73831e37bb4Svn83148 } 73931e37bb4Svn83148 74031e37bb4Svn83148 (void) pthread_mutex_lock(&lsp->fmas_svcs.mt); 74131e37bb4Svn83148 74231e37bb4Svn83148 for (i = start; i < end; i++) { 74331e37bb4Svn83148 lsp->fmas_svcs.tbl[i]->hdl = 0; 74431e37bb4Svn83148 lsp->fmas_svcs.tbl[i]->state = DS_SVC_INVAL; 74531e37bb4Svn83148 lsp->fmas_svcs.tbl[i]->ver.major = 74631e37bb4Svn83148 ds_vers[DS_NUM_VER - 1].major; 74731e37bb4Svn83148 lsp->fmas_svcs.tbl[i]->ver.minor = 74831e37bb4Svn83148 ds_vers[DS_NUM_VER - 1].minor; 74931e37bb4Svn83148 } 75031e37bb4Svn83148 75131e37bb4Svn83148 (void) pthread_mutex_unlock(&lsp->fmas_svcs.mt); 75231e37bb4Svn83148 } 75331e37bb4Svn83148 75431e37bb4Svn83148 75531e37bb4Svn83148 static int 75631e37bb4Svn83148 fds_svc_remove(struct ldmsvcs_info *lsp, ds_svc_hdl_t svc_handle) 75731e37bb4Svn83148 { 75831e37bb4Svn83148 int i; 75931e37bb4Svn83148 76031e37bb4Svn83148 for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) { 76131e37bb4Svn83148 if (lsp->fmas_svcs.tbl[i]->hdl == svc_handle) { 76231e37bb4Svn83148 fds_svc_reset(lsp, i); 76331e37bb4Svn83148 return (0); 76431e37bb4Svn83148 } 76531e37bb4Svn83148 } 76631e37bb4Svn83148 76731e37bb4Svn83148 return (1); 76831e37bb4Svn83148 } 76931e37bb4Svn83148 77031e37bb4Svn83148 77131e37bb4Svn83148 /* 77231e37bb4Svn83148 * message handlers 77331e37bb4Svn83148 */ 77431e37bb4Svn83148 /*ARGSUSED*/ 77531e37bb4Svn83148 static void 77631e37bb4Svn83148 ds_handle_msg_noop(struct ldmsvcs_info *lsp, void *buf, size_t len) 77731e37bb4Svn83148 { 77831e37bb4Svn83148 } 77931e37bb4Svn83148 78031e37bb4Svn83148 static void 78131e37bb4Svn83148 ds_handle_init_req(struct ldmsvcs_info *lsp, void *buf, size_t len) 78231e37bb4Svn83148 { 78331e37bb4Svn83148 ds_init_req_t *req; 78431e37bb4Svn83148 uint16_t new_major, new_minor; 78531e37bb4Svn83148 size_t msglen; 78631e37bb4Svn83148 78731e37bb4Svn83148 req = (ds_init_req_t *)buf; 78831e37bb4Svn83148 78931e37bb4Svn83148 /* sanity check the incoming message */ 79031e37bb4Svn83148 if (len != sizeof (ds_init_req_t)) { 79131e37bb4Svn83148 channel_close(lsp); 79231e37bb4Svn83148 return; 79331e37bb4Svn83148 } 79431e37bb4Svn83148 79531e37bb4Svn83148 /* 79631e37bb4Svn83148 * Check version info. ACK only if the major numbers exactly 79731e37bb4Svn83148 * match. The service entity can retry with a new minor 79831e37bb4Svn83148 * based on the response sent as part of the NACK. 79931e37bb4Svn83148 */ 80031e37bb4Svn83148 if (fds_negotiate_version(req->major_vers, &new_major, &new_minor)) { 80131e37bb4Svn83148 ds_hdr_t *H; 80231e37bb4Svn83148 ds_init_ack_t *R; 80331e37bb4Svn83148 80431e37bb4Svn83148 msglen = sizeof (ds_hdr_t) + sizeof (ds_init_ack_t); 80531e37bb4Svn83148 H = alloca(msglen); 80631e37bb4Svn83148 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 80731e37bb4Svn83148 80831e37bb4Svn83148 H->msg_type = DS_INIT_ACK; 80931e37bb4Svn83148 H->payload_len = sizeof (ds_init_ack_t); 81031e37bb4Svn83148 R->minor_vers = MIN(new_minor, req->minor_vers); 81131e37bb4Svn83148 81231e37bb4Svn83148 if (fds_send(lsp, H, msglen) != 0) 81331e37bb4Svn83148 return; 81431e37bb4Svn83148 81531e37bb4Svn83148 (void) pthread_mutex_lock(&lsp->mt); 81631e37bb4Svn83148 ASSERT(lsp->fds_chan.state == CHANNEL_OPEN); 81731e37bb4Svn83148 lsp->fds_chan.state = CHANNEL_READY; 818a298b85fSvn83148 819a298b85fSvn83148 /* 820a298b85fSvn83148 * Now the channel is ready after the handshake completes. 821a298b85fSvn83148 * Reset the timeout to a smaller value for receiving messages 822a298b85fSvn83148 * from the domain services. 823a298b85fSvn83148 */ 824c3b50bc5Srb144127 lsp->cv_twait = get_smf_int_val(LDM_RUNNING_TO_PROP_NM, 825c3b50bc5Srb144127 0, LDM_TIMEOUT_CEILING, LDM_RUNNING_WAIT_TIME); 826a298b85fSvn83148 82731e37bb4Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 82831e37bb4Svn83148 } else { 82931e37bb4Svn83148 ds_hdr_t *H; 83031e37bb4Svn83148 ds_init_nack_t *R; 83131e37bb4Svn83148 83231e37bb4Svn83148 msglen = sizeof (ds_hdr_t) + sizeof (ds_init_nack_t); 83331e37bb4Svn83148 H = alloca(msglen); 83431e37bb4Svn83148 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 83531e37bb4Svn83148 83631e37bb4Svn83148 H->msg_type = DS_INIT_NACK; 83731e37bb4Svn83148 H->payload_len = sizeof (ds_init_nack_t); 83831e37bb4Svn83148 R->major_vers = new_major; 83931e37bb4Svn83148 84031e37bb4Svn83148 (void) fds_send(lsp, H, msglen); 84131e37bb4Svn83148 /* 84231e37bb4Svn83148 * do not update state; remote end may attempt to initiate 84331e37bb4Svn83148 * connection with a different version 84431e37bb4Svn83148 */ 84531e37bb4Svn83148 } 84631e37bb4Svn83148 } 84731e37bb4Svn83148 84831e37bb4Svn83148 84931e37bb4Svn83148 /*ARGSUSED*/ 85031e37bb4Svn83148 static void 85131e37bb4Svn83148 ds_handle_reg_req(struct ldmsvcs_info *lsp, void *buf, size_t len) 85231e37bb4Svn83148 { 85331e37bb4Svn83148 ds_reg_req_t *req; 85431e37bb4Svn83148 char *msg; 85531e37bb4Svn83148 uint16_t new_major, new_minor; 85631e37bb4Svn83148 size_t msglen; 85731e37bb4Svn83148 int dup_svcreg = 0; 85831e37bb4Svn83148 85931e37bb4Svn83148 req = (ds_reg_req_t *)buf; 86031e37bb4Svn83148 msg = (char *)req->svc_id; 86131e37bb4Svn83148 86231e37bb4Svn83148 /* 86331e37bb4Svn83148 * Service must be NULL terminated 86431e37bb4Svn83148 */ 86531e37bb4Svn83148 if (req->svc_id == NULL || strlen(req->svc_id) == 0 || 86631e37bb4Svn83148 msg[strlen(req->svc_id)] != '\0') { 86731e37bb4Svn83148 channel_close(lsp); 86831e37bb4Svn83148 return; 86931e37bb4Svn83148 } 87031e37bb4Svn83148 87131e37bb4Svn83148 if (fds_negotiate_version(req->major_vers, &new_major, &new_minor) && 87231e37bb4Svn83148 (dup_svcreg = fds_svc_add(lsp, req, 87331e37bb4Svn83148 MIN(new_minor, req->minor_vers))) == 0) { 87431e37bb4Svn83148 87531e37bb4Svn83148 /* 87631e37bb4Svn83148 * Check version info. ACK only if the major numbers 87731e37bb4Svn83148 * exactly match. The service entity can retry with a new 87831e37bb4Svn83148 * minor based on the response sent as part of the NACK. 87931e37bb4Svn83148 */ 88031e37bb4Svn83148 ds_hdr_t *H; 88131e37bb4Svn83148 ds_reg_ack_t *R; 88231e37bb4Svn83148 88331e37bb4Svn83148 msglen = sizeof (ds_hdr_t) + sizeof (ds_reg_ack_t); 88431e37bb4Svn83148 H = alloca(msglen); 88531e37bb4Svn83148 bzero(H, msglen); 88631e37bb4Svn83148 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 88731e37bb4Svn83148 88831e37bb4Svn83148 H->msg_type = DS_REG_ACK; 88931e37bb4Svn83148 H->payload_len = sizeof (ds_reg_ack_t); 89031e37bb4Svn83148 R->svc_handle = req->svc_handle; 89131e37bb4Svn83148 R->minor_vers = MIN(new_minor, req->minor_vers); 89231e37bb4Svn83148 89331e37bb4Svn83148 (void) fds_send(lsp, H, msglen); 89431e37bb4Svn83148 } else { 89531e37bb4Svn83148 ds_hdr_t *H; 89631e37bb4Svn83148 ds_reg_nack_t *R; 89731e37bb4Svn83148 89831e37bb4Svn83148 msglen = sizeof (ds_hdr_t) + sizeof (ds_reg_nack_t); 89931e37bb4Svn83148 H = alloca(msglen); 90031e37bb4Svn83148 bzero(H, msglen); 90131e37bb4Svn83148 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 90231e37bb4Svn83148 90331e37bb4Svn83148 H->msg_type = DS_REG_NACK; 90431e37bb4Svn83148 H->payload_len = sizeof (ds_reg_nack_t); 90531e37bb4Svn83148 R->svc_handle = req->svc_handle; 90631e37bb4Svn83148 R->major_vers = new_major; 90731e37bb4Svn83148 90831e37bb4Svn83148 if (dup_svcreg) 90931e37bb4Svn83148 R->result = DS_REG_DUP; 91031e37bb4Svn83148 else 91131e37bb4Svn83148 R->result = DS_REG_VER_NACK; 91231e37bb4Svn83148 91331e37bb4Svn83148 (void) fds_send(lsp, H, msglen); 91431e37bb4Svn83148 } 91531e37bb4Svn83148 } 91631e37bb4Svn83148 91731e37bb4Svn83148 91831e37bb4Svn83148 /*ARGSUSED*/ 91931e37bb4Svn83148 static void 92031e37bb4Svn83148 ds_handle_unreg(struct ldmsvcs_info *lsp, void *buf, size_t len) 92131e37bb4Svn83148 { 92231e37bb4Svn83148 ds_unreg_req_t *req; 92331e37bb4Svn83148 size_t msglen; 92431e37bb4Svn83148 92531e37bb4Svn83148 req = (ds_unreg_req_t *)buf; 92631e37bb4Svn83148 92731e37bb4Svn83148 if (fds_svc_remove(lsp, req->svc_handle) == 0) { 92831e37bb4Svn83148 ds_hdr_t *H; 92931e37bb4Svn83148 ds_unreg_ack_t *R; 93031e37bb4Svn83148 93131e37bb4Svn83148 msglen = sizeof (ds_hdr_t) + sizeof (ds_unreg_ack_t); 93231e37bb4Svn83148 H = alloca(msglen); 93331e37bb4Svn83148 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 93431e37bb4Svn83148 93531e37bb4Svn83148 H->msg_type = DS_REG_ACK; 93631e37bb4Svn83148 H->payload_len = sizeof (ds_unreg_ack_t); 93731e37bb4Svn83148 R->svc_handle = req->svc_handle; 93831e37bb4Svn83148 93931e37bb4Svn83148 (void) fds_send(lsp, H, msglen); 94031e37bb4Svn83148 } else { 94131e37bb4Svn83148 ds_hdr_t *H; 94231e37bb4Svn83148 ds_unreg_nack_t *R; 94331e37bb4Svn83148 94431e37bb4Svn83148 msglen = sizeof (ds_hdr_t) + sizeof (ds_unreg_nack_t); 94531e37bb4Svn83148 H = alloca(msglen); 94631e37bb4Svn83148 R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 94731e37bb4Svn83148 94831e37bb4Svn83148 H->msg_type = DS_REG_NACK; 94931e37bb4Svn83148 H->payload_len = sizeof (ds_unreg_nack_t); 95031e37bb4Svn83148 R->svc_handle = req->svc_handle; 95131e37bb4Svn83148 95231e37bb4Svn83148 (void) fds_send(lsp, H, msglen); 95331e37bb4Svn83148 } 95431e37bb4Svn83148 } 95531e37bb4Svn83148 95631e37bb4Svn83148 95731e37bb4Svn83148 /* 95831e37bb4Svn83148 * Message handler lookup table (v1.0 only for now) Future 95931e37bb4Svn83148 * versions can add their own lookup table. 96031e37bb4Svn83148 */ 96131e37bb4Svn83148 typedef void (*ds_msg_handler_t)(struct ldmsvcs_info *lsp, 96231e37bb4Svn83148 void *buf, size_t len); 96331e37bb4Svn83148 96431e37bb4Svn83148 static const ds_msg_handler_t ds_msg_handlers[] = { 96531e37bb4Svn83148 ds_handle_init_req, /* DS_INIT_REQ */ 96631e37bb4Svn83148 ds_handle_msg_noop, /* DS_INIT_ACK */ 96731e37bb4Svn83148 ds_handle_msg_noop, /* DS_INIT_NACK */ 96831e37bb4Svn83148 ds_handle_reg_req, /* DS_REG_REQ */ 96931e37bb4Svn83148 ds_handle_msg_noop, /* DS_REG_ACK */ 97031e37bb4Svn83148 ds_handle_msg_noop, /* DS_REG_NACK */ 97131e37bb4Svn83148 ds_handle_unreg, /* DS_UNREG */ 97231e37bb4Svn83148 ds_handle_msg_noop, /* DS_UNREG_ACK */ 97331e37bb4Svn83148 ds_handle_msg_noop, /* DS_UNREG_NACK */ 97431e37bb4Svn83148 ds_handle_msg_noop, /* DS_DATA */ 97531e37bb4Svn83148 ds_handle_msg_noop /* DS_NACK */ 97631e37bb4Svn83148 }; 97731e37bb4Svn83148 97831e37bb4Svn83148 97931e37bb4Svn83148 /* 98031e37bb4Svn83148 * message and service internal functions 98131e37bb4Svn83148 */ 98231e37bb4Svn83148 static void 9833dc13b01SVuong Nguyen fds_svc_alloc(struct ldmsvcs_info *lsp) 98431e37bb4Svn83148 { 98531e37bb4Svn83148 int i; 98625351652SVuong Nguyen static char *name[] = { LDM_DS_NAME_CPU, LDM_DS_NAME_MEM, 98725351652SVuong Nguyen LDM_DS_NAME_PRI, LDM_DS_NAME_IOD, NULL }; 98831e37bb4Svn83148 98931e37bb4Svn83148 (void) pthread_mutex_init(&lsp->fmas_svcs.mt, NULL); 99031e37bb4Svn83148 (void) pthread_cond_init(&lsp->fmas_svcs.cv, NULL); 99131e37bb4Svn83148 99231e37bb4Svn83148 for (lsp->fmas_svcs.nsvcs = 0; name[lsp->fmas_svcs.nsvcs] != NULL; 99331e37bb4Svn83148 lsp->fmas_svcs.nsvcs++) 99431e37bb4Svn83148 ; 99531e37bb4Svn83148 9963dc13b01SVuong Nguyen lsp->fmas_svcs.tbl = (fds_svc_t **)ldom_alloc(sizeof (fds_svc_t *) * 99731e37bb4Svn83148 lsp->fmas_svcs.nsvcs); 99831e37bb4Svn83148 99931e37bb4Svn83148 for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) { 100031e37bb4Svn83148 lsp->fmas_svcs.tbl[i] = 10013dc13b01SVuong Nguyen (fds_svc_t *)ldom_alloc(sizeof (fds_svc_t)); 100231e37bb4Svn83148 bzero(lsp->fmas_svcs.tbl[i], sizeof (fds_svc_t)); 100331e37bb4Svn83148 lsp->fmas_svcs.tbl[i]->name = name[i]; 100431e37bb4Svn83148 } 100531e37bb4Svn83148 } 100631e37bb4Svn83148 100731e37bb4Svn83148 100831e37bb4Svn83148 static fds_svc_t * 100931e37bb4Svn83148 fds_svc_lookup(struct ldmsvcs_info *lsp, char *name) 101031e37bb4Svn83148 { 101131e37bb4Svn83148 struct timespec twait; 101231e37bb4Svn83148 fds_svc_t *svc; 101331e37bb4Svn83148 int i, ier; 101431e37bb4Svn83148 101531e37bb4Svn83148 if (pthread_mutex_lock(&lsp->fmas_svcs.mt) == EINVAL) 101631e37bb4Svn83148 return (NULL); /* uninitialized or destroyed mutex */ 101731e37bb4Svn83148 101831e37bb4Svn83148 svc = NULL; 101931e37bb4Svn83148 for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) { 102031e37bb4Svn83148 if (strcmp(lsp->fmas_svcs.tbl[i]->name, name) == 0) { 102131e37bb4Svn83148 svc = lsp->fmas_svcs.tbl[i]; 102231e37bb4Svn83148 break; 102331e37bb4Svn83148 } 102431e37bb4Svn83148 } 102531e37bb4Svn83148 102631e37bb4Svn83148 ASSERT(svc != NULL); 102731e37bb4Svn83148 102825351652SVuong Nguyen if (svc->state == DS_SVC_INACTIVE) { 102925351652SVuong Nguyen /* service is not registered */ 103025351652SVuong Nguyen ier = ETIMEDOUT; 103125351652SVuong Nguyen } else { 103231e37bb4Svn83148 ier = 0; 103331e37bb4Svn83148 twait.tv_sec = time(NULL) + lsp->cv_twait; 103431e37bb4Svn83148 twait.tv_nsec = 0; 103531e37bb4Svn83148 103631e37bb4Svn83148 while (svc->state != DS_SVC_ACTIVE && ier == 0 && 103731e37bb4Svn83148 lsp->fds_chan.state != CHANNEL_UNUSABLE) 103831e37bb4Svn83148 ier = pthread_cond_timedwait(&lsp->fmas_svcs.cv, 103931e37bb4Svn83148 &lsp->fmas_svcs.mt, &twait); 104031e37bb4Svn83148 104125351652SVuong Nguyen /* 104225351652SVuong Nguyen * By now, the ds service should have registered already. 104325351652SVuong Nguyen * If it does not, ldmd probably does not support this service. 104425351652SVuong Nguyen * Then mark the service state as inactive. 104525351652SVuong Nguyen */ 104625351652SVuong Nguyen if (ier == ETIMEDOUT) { 104725351652SVuong Nguyen svc->state = DS_SVC_INACTIVE; 104825351652SVuong Nguyen } 104925351652SVuong Nguyen } 105025351652SVuong Nguyen 105131e37bb4Svn83148 (void) pthread_mutex_unlock(&lsp->fmas_svcs.mt); 105231e37bb4Svn83148 105331e37bb4Svn83148 if (ier == 0) 105431e37bb4Svn83148 return (svc); 105531e37bb4Svn83148 else 105631e37bb4Svn83148 return (NULL); 105731e37bb4Svn83148 } 105831e37bb4Svn83148 105931e37bb4Svn83148 106031e37bb4Svn83148 static uint64_t 106131e37bb4Svn83148 fds_svc_req_num(void) 106231e37bb4Svn83148 { 106331e37bb4Svn83148 static uint64_t req_num = 1; 106431e37bb4Svn83148 106531e37bb4Svn83148 return (req_num++); 106631e37bb4Svn83148 } 106731e37bb4Svn83148 106831e37bb4Svn83148 106931e37bb4Svn83148 /* 107031e37bb4Svn83148 * return 0 if successful, 1 if otherwise 107131e37bb4Svn83148 */ 107231e37bb4Svn83148 static int 107331e37bb4Svn83148 read_msg(struct ldmsvcs_info *lsp) 107431e37bb4Svn83148 { 107531e37bb4Svn83148 ds_hdr_t header; 107631e37bb4Svn83148 void *msg_buf; 107731e37bb4Svn83148 107831e37bb4Svn83148 /* 107931e37bb4Svn83148 * read the header 108031e37bb4Svn83148 */ 108131e37bb4Svn83148 if (read_stream(lsp->fds_chan.fd, &header, sizeof (ds_hdr_t)) != 0) 108231e37bb4Svn83148 return (1); 108331e37bb4Svn83148 108431e37bb4Svn83148 if (header.msg_type >= 108531e37bb4Svn83148 sizeof (ds_msg_handlers) / sizeof (ds_msg_handler_t)) 108631e37bb4Svn83148 return (1); 108731e37bb4Svn83148 108831e37bb4Svn83148 /* 108931e37bb4Svn83148 * handle data as a special case 109031e37bb4Svn83148 */ 109131e37bb4Svn83148 if (header.msg_type == 9) 109231e37bb4Svn83148 return (poller_handle_data(lsp->fds_chan.fd, 109331e37bb4Svn83148 header.payload_len)); 109431e37bb4Svn83148 109531e37bb4Svn83148 /* 109631e37bb4Svn83148 * all other types of messages should be small 109731e37bb4Svn83148 */ 109831e37bb4Svn83148 ASSERT(header.payload_len < 1024); 109931e37bb4Svn83148 msg_buf = alloca(header.payload_len); 110031e37bb4Svn83148 110131e37bb4Svn83148 /* 110231e37bb4Svn83148 * read the payload 110331e37bb4Svn83148 */ 110431e37bb4Svn83148 if (read_stream(lsp->fds_chan.fd, msg_buf, header.payload_len) != 0) 110531e37bb4Svn83148 return (1); 110631e37bb4Svn83148 110731e37bb4Svn83148 (*ds_msg_handlers[header.msg_type])(lsp, msg_buf, header.payload_len); 110831e37bb4Svn83148 110931e37bb4Svn83148 return (0); 111031e37bb4Svn83148 } 111131e37bb4Svn83148 111231e37bb4Svn83148 111331e37bb4Svn83148 /* 111431e37bb4Svn83148 * return values: 111531e37bb4Svn83148 * 0 - success 111631e37bb4Svn83148 * 1 - problem with opening the channel 111731e37bb4Svn83148 * 2 - channed not opened; request to exit has been detected 111831e37bb4Svn83148 */ 111931e37bb4Svn83148 static int 112031e37bb4Svn83148 channel_openreset(struct ldmsvcs_info *lsp) 112131e37bb4Svn83148 { 112231e37bb4Svn83148 int ier; 112331e37bb4Svn83148 112431e37bb4Svn83148 ier = pthread_mutex_lock(&lsp->mt); 112531e37bb4Svn83148 112631e37bb4Svn83148 if (ier == EINVAL || lsp->fds_chan.state == CHANNEL_EXIT || 112731e37bb4Svn83148 lsp->fds_chan.state == CHANNEL_UNUSABLE) { 112831e37bb4Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 112931e37bb4Svn83148 return (2); 113031e37bb4Svn83148 } 113131e37bb4Svn83148 113231e37bb4Svn83148 if (lsp->fds_chan.state == CHANNEL_UNINITIALIZED || 113331e37bb4Svn83148 lsp->fds_chan.state == CHANNEL_CLOSED) { 113431e37bb4Svn83148 (void) pthread_cond_broadcast(&lsp->cv); 113531e37bb4Svn83148 113631e37bb4Svn83148 if ((lsp->fds_chan.fd = open(FDS_VLDC, O_RDWR)) < 0) { 113731e37bb4Svn83148 lsp->fds_chan.state = CHANNEL_UNUSABLE; 1138c3b50bc5Srb144127 lsp->cv_twait = get_smf_int_val(LDM_RUNNING_TO_PROP_NM, 1139c3b50bc5Srb144127 0, LDM_TIMEOUT_CEILING, LDM_RUNNING_WAIT_TIME); 114031e37bb4Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 114131e37bb4Svn83148 (void) pthread_cond_broadcast(&lsp->fmas_svcs.cv); 114231e37bb4Svn83148 114331e37bb4Svn83148 return (2); 114431e37bb4Svn83148 } else { 114531e37bb4Svn83148 vldc_opt_op_t op; 114631e37bb4Svn83148 114731e37bb4Svn83148 op.op_sel = VLDC_OP_SET; 114831e37bb4Svn83148 op.opt_sel = VLDC_OPT_MODE; 114920ae46ebSha137994 op.opt_val = LDC_MODE_RELIABLE; 115031e37bb4Svn83148 115131e37bb4Svn83148 if (ioctl(lsp->fds_chan.fd, VLDC_IOCTL_OPT_OP, 115231e37bb4Svn83148 &op) != 0) { 115331e37bb4Svn83148 (void) close(lsp->fds_chan.fd); 115431e37bb4Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 115531e37bb4Svn83148 return (1); 115631e37bb4Svn83148 } 115731e37bb4Svn83148 } 115831e37bb4Svn83148 lsp->fds_chan.state = CHANNEL_OPEN; 115931e37bb4Svn83148 } 116031e37bb4Svn83148 116131e37bb4Svn83148 if (lsp->fds_chan.state == CHANNEL_OPEN) { 116231e37bb4Svn83148 /* 116331e37bb4Svn83148 * reset various channel parameters 116431e37bb4Svn83148 */ 116531e37bb4Svn83148 lsp->fds_chan.ver.major = 0; 116631e37bb4Svn83148 lsp->fds_chan.ver.minor = 0; 116731e37bb4Svn83148 fds_svc_reset(lsp, -1); 116831e37bb4Svn83148 } 116931e37bb4Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 117031e37bb4Svn83148 117131e37bb4Svn83148 return (0); 117231e37bb4Svn83148 } 117331e37bb4Svn83148 117431e37bb4Svn83148 117531e37bb4Svn83148 static void 117631e37bb4Svn83148 channel_fini(void) 117731e37bb4Svn83148 { 11783dc13b01SVuong Nguyen int i; 117931e37bb4Svn83148 struct ldmsvcs_info *lsp; 118031e37bb4Svn83148 118131e37bb4Svn83148 /* 118231e37bb4Svn83148 * End the poller thread 118331e37bb4Svn83148 */ 11843dc13b01SVuong Nguyen poller_fini(); 118531e37bb4Svn83148 118631e37bb4Svn83148 if ((lsp = channel_init(NULL)) == NULL) 118731e37bb4Svn83148 return; 118831e37bb4Svn83148 118931e37bb4Svn83148 (void) pthread_mutex_lock(&lsp->mt); 119031e37bb4Svn83148 119131e37bb4Svn83148 lsp->fds_chan.state = CHANNEL_EXIT; 119231e37bb4Svn83148 (void) close(lsp->fds_chan.fd); 119331e37bb4Svn83148 119431e37bb4Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 11953dc13b01SVuong Nguyen 11963dc13b01SVuong Nguyen /* Free the ldom service structure */ 11973dc13b01SVuong Nguyen for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) { 11983dc13b01SVuong Nguyen ldom_free(lsp->fmas_svcs.tbl[i], sizeof (fds_svc_t)); 11993dc13b01SVuong Nguyen } 12003dc13b01SVuong Nguyen ldom_free(lsp->fmas_svcs.tbl, 12013dc13b01SVuong Nguyen lsp->fmas_svcs.nsvcs * sizeof (fds_svc_t *)); 12023dc13b01SVuong Nguyen ldom_free(lsp, sizeof (struct ldmsvcs_info)); 120331e37bb4Svn83148 } 120431e37bb4Svn83148 120531e37bb4Svn83148 120631e37bb4Svn83148 static struct ldmsvcs_info * 120731e37bb4Svn83148 channel_init(struct ldom_hdl *lhp) 120831e37bb4Svn83148 { 120931e37bb4Svn83148 static pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER; 121031e37bb4Svn83148 static pthread_cond_t cv = PTHREAD_COND_INITIALIZER; 121131e37bb4Svn83148 static struct ldmsvcs_info *root = NULL; 121231e37bb4Svn83148 static int busy_init = 0; 121331e37bb4Svn83148 121431e37bb4Svn83148 struct timespec twait; 121531e37bb4Svn83148 int expired; 121631e37bb4Svn83148 121731e37bb4Svn83148 (void) pthread_mutex_lock(&mt); 121831e37bb4Svn83148 121931e37bb4Svn83148 while (busy_init == 1) 122031e37bb4Svn83148 (void) pthread_cond_wait(&cv, &mt); 122131e37bb4Svn83148 122231e37bb4Svn83148 if (root != NULL || (lhp == NULL && root == NULL)) { 122331e37bb4Svn83148 (void) pthread_mutex_unlock(&mt); 122431e37bb4Svn83148 return (root); 122531e37bb4Svn83148 } 122631e37bb4Svn83148 122731e37bb4Svn83148 /* 122831e37bb4Svn83148 * get to this point if we need to open the channel 122931e37bb4Svn83148 */ 123031e37bb4Svn83148 busy_init = 1; 123131e37bb4Svn83148 (void) pthread_mutex_unlock(&mt); 123231e37bb4Svn83148 123331e37bb4Svn83148 root = (struct ldmsvcs_info *) 12343dc13b01SVuong Nguyen ldom_alloc(sizeof (struct ldmsvcs_info)); 123531e37bb4Svn83148 bzero(root, sizeof (struct ldmsvcs_info)); 123631e37bb4Svn83148 123731e37bb4Svn83148 root->fds_chan.state = CHANNEL_UNINITIALIZED; 1238c3b50bc5Srb144127 root->cv_twait = get_smf_int_val(LDM_INIT_TO_PROP_NM, 1239c3b50bc5Srb144127 0, LDM_TIMEOUT_CEILING, LDM_INIT_WAIT_TIME); 124031e37bb4Svn83148 124131e37bb4Svn83148 if (pthread_mutex_init(&root->mt, NULL) != 0 || 124231e37bb4Svn83148 pthread_cond_init(&root->cv, NULL) != 0) { 12433dc13b01SVuong Nguyen ldom_free(root, sizeof (struct ldmsvcs_info)); 124431e37bb4Svn83148 return (NULL); 124531e37bb4Svn83148 } 124631e37bb4Svn83148 12473dc13b01SVuong Nguyen fds_svc_alloc(root); 124831e37bb4Svn83148 fds_svc_reset(root, -1); 124931e37bb4Svn83148 125031e37bb4Svn83148 (void) poller_init(root); 125131e37bb4Svn83148 125231e37bb4Svn83148 expired = 0; 125331e37bb4Svn83148 twait.tv_sec = time(NULL) + 10; 125431e37bb4Svn83148 twait.tv_nsec = 0; 125531e37bb4Svn83148 125631e37bb4Svn83148 (void) pthread_mutex_lock(&root->mt); 125731e37bb4Svn83148 125831e37bb4Svn83148 /* 125931e37bb4Svn83148 * wait for channel to become uninitialized. this should be quick. 126031e37bb4Svn83148 */ 126131e37bb4Svn83148 while (root->fds_chan.state == CHANNEL_UNINITIALIZED && expired == 0) 126231e37bb4Svn83148 expired = pthread_cond_timedwait(&root->cv, &root->mt, &twait); 126331e37bb4Svn83148 126431e37bb4Svn83148 if (root->fds_chan.state == CHANNEL_UNUSABLE) 126531e37bb4Svn83148 expired = 1; 126631e37bb4Svn83148 126731e37bb4Svn83148 (void) pthread_mutex_unlock(&root->mt); 126831e37bb4Svn83148 126931e37bb4Svn83148 (void) pthread_mutex_lock(&mt); 127031e37bb4Svn83148 busy_init = 0; 127131e37bb4Svn83148 (void) pthread_mutex_unlock(&mt); 127231e37bb4Svn83148 (void) pthread_cond_broadcast(&cv); 127331e37bb4Svn83148 127431e37bb4Svn83148 (void) atexit(channel_fini); 127531e37bb4Svn83148 127631e37bb4Svn83148 if (expired == 0) 127731e37bb4Svn83148 return (root); 127831e37bb4Svn83148 else 127931e37bb4Svn83148 return (NULL); 128031e37bb4Svn83148 } 128131e37bb4Svn83148 128231e37bb4Svn83148 128331e37bb4Svn83148 static int 128431e37bb4Svn83148 sendrecv(struct ldom_hdl *lhp, uint64_t req_num, 128531e37bb4Svn83148 void *msg, size_t msglen, ds_svc_hdl_t *svc_hdl, char *svcname, 128631e37bb4Svn83148 void **resp, size_t *resplen) 128731e37bb4Svn83148 { 128831e37bb4Svn83148 struct ldmsvcs_info *lsp; 128931e37bb4Svn83148 fds_svc_t *svc; 129031e37bb4Svn83148 int maxretries, index, i, ier; 129131e37bb4Svn83148 129231e37bb4Svn83148 lsp = lhp->lsinfo; 129331e37bb4Svn83148 i = 0; 129431e37bb4Svn83148 maxretries = 1; 129531e37bb4Svn83148 129631e37bb4Svn83148 do { 129731e37bb4Svn83148 /* 129831e37bb4Svn83148 * if any of the calls in this loop fail, retry some number 129931e37bb4Svn83148 * of times before giving up. 130031e37bb4Svn83148 */ 130131e37bb4Svn83148 if ((svc = fds_svc_lookup(lsp, svcname)) == NULL) { 130231e37bb4Svn83148 (void) pthread_mutex_lock(&lsp->mt); 130331e37bb4Svn83148 130431e37bb4Svn83148 if (lsp->fds_chan.state != CHANNEL_READY) 130531e37bb4Svn83148 ier = ETIMEDOUT; /* channel not ready */ 130631e37bb4Svn83148 else 130731e37bb4Svn83148 ier = ENOTSUP; /* service not ready */ 130831e37bb4Svn83148 130931e37bb4Svn83148 (void) pthread_mutex_unlock(&lsp->mt); 131031e37bb4Svn83148 131131e37bb4Svn83148 continue; 131231e37bb4Svn83148 } else { 131331e37bb4Svn83148 ier = 0; 131431e37bb4Svn83148 *svc_hdl = svc->hdl; 131531e37bb4Svn83148 } 131631e37bb4Svn83148 13173dc13b01SVuong Nguyen index = poller_add_pending(req_num); 131831e37bb4Svn83148 131931e37bb4Svn83148 if ((ier = fds_send(lsp, msg, msglen)) != 0 || 132031e37bb4Svn83148 (ier = poller_recv_data(lhp, req_num, index, resp, 132131e37bb4Svn83148 resplen)) != 0) 132231e37bb4Svn83148 poller_delete_pending(req_num, index); 132331e37bb4Svn83148 132431e37bb4Svn83148 } while (i++ < maxretries && ier != 0); 132531e37bb4Svn83148 132631e37bb4Svn83148 ASSERT(ier == 0 || ier == ETIMEDOUT || ier == ENOTSUP); 132731e37bb4Svn83148 132831e37bb4Svn83148 return (ier); 132931e37bb4Svn83148 } 133031e37bb4Svn83148 133131e37bb4Svn83148 133231e37bb4Svn83148 /* 133331e37bb4Svn83148 * input: 133431e37bb4Svn83148 * msg_type - requested operation: FMA_CPU_REQ_STATUS or FMA_CPU_REQ_OFFLINE 133531e37bb4Svn83148 * cpuid - physical cpu id 133631e37bb4Svn83148 * 133731e37bb4Svn83148 * normal return values: 133831e37bb4Svn83148 * P_OFFLINE - cpu is offline 133931e37bb4Svn83148 * P_ONLINE - cpu is online 134031e37bb4Svn83148 * 134131e37bb4Svn83148 * abnormal return values: 134231e37bb4Svn83148 * ETIMEDOUT - LDOM manager is not responding 134331e37bb4Svn83148 * ENOTSUP - LDOM service for cpu offlining/status is not available 134431e37bb4Svn83148 * ENOMSG - got an unexpected response from the LDOM cpu service 134531e37bb4Svn83148 */ 134631e37bb4Svn83148 static int 134731e37bb4Svn83148 cpu_request(struct ldom_hdl *lhp, uint32_t msg_type, uint32_t cpuid) 134831e37bb4Svn83148 { 134931e37bb4Svn83148 ds_hdr_t *H; 135031e37bb4Svn83148 ds_data_handle_t *D; 135131e37bb4Svn83148 fma_cpu_service_req_t *R; 135231e37bb4Svn83148 135325351652SVuong Nguyen char *svcname = LDM_DS_NAME_CPU; 135431e37bb4Svn83148 fma_cpu_resp_t *respmsg; 135531e37bb4Svn83148 void *resp; 135631e37bb4Svn83148 size_t resplen, reqmsglen; 135731e37bb4Svn83148 int rc; 135831e37bb4Svn83148 135931e37bb4Svn83148 if (lhp->lsinfo == NULL) 136031e37bb4Svn83148 return (ENOMSG); 136131e37bb4Svn83148 136231e37bb4Svn83148 reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) + 136331e37bb4Svn83148 sizeof (fma_cpu_service_req_t); 136431e37bb4Svn83148 136531e37bb4Svn83148 H = lhp->allocp(reqmsglen); 136631e37bb4Svn83148 D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 136731e37bb4Svn83148 R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t)); 136831e37bb4Svn83148 136931e37bb4Svn83148 H->msg_type = DS_DATA; 137031e37bb4Svn83148 H->payload_len = sizeof (ds_data_handle_t) + 137131e37bb4Svn83148 sizeof (fma_cpu_service_req_t); 137231e37bb4Svn83148 137331e37bb4Svn83148 R->req_num = fds_svc_req_num(); 137431e37bb4Svn83148 R->msg_type = msg_type; 137531e37bb4Svn83148 R->cpu_id = cpuid; 137631e37bb4Svn83148 137731e37bb4Svn83148 if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen, 137831e37bb4Svn83148 &D->svc_handle, svcname, &resp, &resplen)) != 0) { 137931e37bb4Svn83148 lhp->freep(H, reqmsglen); 138031e37bb4Svn83148 return (rc); 138131e37bb4Svn83148 } 138231e37bb4Svn83148 138331e37bb4Svn83148 lhp->freep(H, reqmsglen); 138431e37bb4Svn83148 138531e37bb4Svn83148 ASSERT(resplen == sizeof (fma_cpu_resp_t)); 138631e37bb4Svn83148 respmsg = (fma_cpu_resp_t *)resp; 138731e37bb4Svn83148 138831e37bb4Svn83148 rc = ENOMSG; 138931e37bb4Svn83148 if (respmsg->result == FMA_CPU_RESP_OK) { 139031e37bb4Svn83148 if (respmsg->status == FMA_CPU_STAT_ONLINE) 139131e37bb4Svn83148 rc = P_ONLINE; 139231e37bb4Svn83148 else if (respmsg->status == FMA_CPU_STAT_OFFLINE) 139331e37bb4Svn83148 rc = P_OFFLINE; 139431e37bb4Svn83148 } else { 139531e37bb4Svn83148 if (msg_type == FMA_CPU_REQ_OFFLINE && 139631e37bb4Svn83148 respmsg->status == FMA_CPU_STAT_OFFLINE) 139731e37bb4Svn83148 rc = P_OFFLINE; 139831e37bb4Svn83148 } 139931e37bb4Svn83148 140031e37bb4Svn83148 lhp->freep(resp, resplen); 140131e37bb4Svn83148 140231e37bb4Svn83148 return (rc); 140331e37bb4Svn83148 } 140431e37bb4Svn83148 140531e37bb4Svn83148 140631e37bb4Svn83148 /* 140731e37bb4Svn83148 * input: 140831e37bb4Svn83148 * msg_type - requested operation: FMA_MEM_REQ_STATUS or FMA_MEM_REQ_RETIRE 140931e37bb4Svn83148 * pa - starting address of memory page 141031e37bb4Svn83148 * pgsize - memory page size in bytes 141131e37bb4Svn83148 * 141231e37bb4Svn83148 * normal return values for msg_type == FMA_MEM_REQ_STATUS: 141331e37bb4Svn83148 * 0 - page is retired 141431e37bb4Svn83148 * EAGAIN - page is scheduled for retirement 141531e37bb4Svn83148 * EIO - page not scheduled for retirement 141631e37bb4Svn83148 * EINVAL - error 141731e37bb4Svn83148 * 141831e37bb4Svn83148 * normal return values for msg_type == FMA_MEM_REQ_RETIRE: 141931e37bb4Svn83148 * 0 - success in retiring page 142031e37bb4Svn83148 * EIO - page is already retired 142131e37bb4Svn83148 * EAGAIN - page is scheduled for retirement 142231e37bb4Svn83148 * EINVAL - error 142331e37bb4Svn83148 * 142431e37bb4Svn83148 * abnormal return values (regardless of msg_type) 142531e37bb4Svn83148 * ETIMEDOUT - LDOM manager is not responding 142631e37bb4Svn83148 * ENOTSUP - LDOM service for cpu offlining/status is not available 142731e37bb4Svn83148 * ENOMSG - got an unexpected response from the LDOM cpu service 142831e37bb4Svn83148 */ 142931e37bb4Svn83148 static int 143031e37bb4Svn83148 mem_request(struct ldom_hdl *lhp, uint32_t msg_type, uint64_t pa, 143131e37bb4Svn83148 uint64_t pgsize) 143231e37bb4Svn83148 { 143331e37bb4Svn83148 ds_hdr_t *H; 143431e37bb4Svn83148 ds_data_handle_t *D; 143531e37bb4Svn83148 fma_mem_service_req_t *R; 143631e37bb4Svn83148 143725351652SVuong Nguyen char *svcname = LDM_DS_NAME_MEM; 143831e37bb4Svn83148 fma_mem_resp_t *respmsg; 143931e37bb4Svn83148 void *resp; 144031e37bb4Svn83148 size_t resplen, reqmsglen; 144131e37bb4Svn83148 int rc; 144231e37bb4Svn83148 144331e37bb4Svn83148 if (lhp->lsinfo == NULL) 144431e37bb4Svn83148 return (ENOMSG); 144531e37bb4Svn83148 144631e37bb4Svn83148 reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) + 144731e37bb4Svn83148 sizeof (fma_mem_service_req_t); 144831e37bb4Svn83148 144931e37bb4Svn83148 H = lhp->allocp(reqmsglen); 145031e37bb4Svn83148 bzero(H, reqmsglen); 145131e37bb4Svn83148 D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 145231e37bb4Svn83148 R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t)); 145331e37bb4Svn83148 145431e37bb4Svn83148 H->msg_type = DS_DATA; 145531e37bb4Svn83148 H->payload_len = sizeof (ds_data_handle_t) + 145631e37bb4Svn83148 sizeof (fma_mem_service_req_t); 145731e37bb4Svn83148 145831e37bb4Svn83148 R->req_num = fds_svc_req_num(); 145931e37bb4Svn83148 R->msg_type = msg_type; 146031e37bb4Svn83148 R->real_addr = pa; 146131e37bb4Svn83148 R->length = pgsize; 146231e37bb4Svn83148 146331e37bb4Svn83148 if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen, 146431e37bb4Svn83148 &D->svc_handle, svcname, &resp, &resplen)) != 0) { 146531e37bb4Svn83148 lhp->freep(H, reqmsglen); 146631e37bb4Svn83148 return (rc); 146731e37bb4Svn83148 } 146831e37bb4Svn83148 146931e37bb4Svn83148 lhp->freep(H, reqmsglen); 147031e37bb4Svn83148 147131e37bb4Svn83148 ASSERT(resplen == sizeof (fma_mem_resp_t)); 147231e37bb4Svn83148 respmsg = (fma_mem_resp_t *)resp; 147331e37bb4Svn83148 147431e37bb4Svn83148 rc = ENOMSG; 147531e37bb4Svn83148 if (msg_type == FMA_MEM_REQ_STATUS) { 147631e37bb4Svn83148 if (respmsg->result == FMA_MEM_RESP_OK) { 147731e37bb4Svn83148 if (respmsg->status == FMA_MEM_STAT_RETIRED) 14781557e65fSvn83148 rc = 0; /* page is retired */ 147931e37bb4Svn83148 else if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 14801557e65fSvn83148 rc = EIO; /* page is not scheduled */ 148131e37bb4Svn83148 } else if (respmsg->result == FMA_MEM_RESP_FAILURE) { 14821557e65fSvn83148 if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 14831557e65fSvn83148 rc = EAGAIN; /* page is scheduled */ 14841557e65fSvn83148 else if (respmsg->status == FMA_MEM_STAT_ILLEGAL) 148531e37bb4Svn83148 rc = EINVAL; 148631e37bb4Svn83148 } 148731e37bb4Svn83148 } else if (msg_type == FMA_MEM_REQ_RETIRE) { 148831e37bb4Svn83148 if (respmsg->result == FMA_MEM_RESP_OK) { 148931e37bb4Svn83148 if (respmsg->status == FMA_MEM_STAT_RETIRED) 14901557e65fSvn83148 rc = 0; /* is successfully retired */ 149131e37bb4Svn83148 } else if (respmsg->result == FMA_MEM_RESP_FAILURE) { 149231e37bb4Svn83148 if (respmsg->status == FMA_MEM_STAT_RETIRED) 14931557e65fSvn83148 rc = EIO; /* is already retired */ 14941557e65fSvn83148 else if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 14951557e65fSvn83148 rc = EAGAIN; /* is scheduled to retire */ 149631e37bb4Svn83148 else if (respmsg->status == FMA_MEM_STAT_ILLEGAL) 149731e37bb4Svn83148 rc = EINVAL; 149831e37bb4Svn83148 } 1499e4b86885SCheng Sean Ye } else if (msg_type == FMA_MEM_REQ_RESURRECT) { 1500e4b86885SCheng Sean Ye if (respmsg->result == FMA_MEM_RESP_OK) { 1501e4b86885SCheng Sean Ye if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 1502e4b86885SCheng Sean Ye rc = 0; /* is successfully unretired */ 1503e4b86885SCheng Sean Ye } if (respmsg->result == FMA_MEM_RESP_FAILURE) { 1504e4b86885SCheng Sean Ye if (respmsg->status == FMA_MEM_STAT_RETIRED) 1505e4b86885SCheng Sean Ye rc = EAGAIN; /* page couldn't be locked */ 1506e4b86885SCheng Sean Ye else if (respmsg->status == FMA_MEM_STAT_NOTRETIRED) 1507e4b86885SCheng Sean Ye rc = EIO; /* page isn't retired already */ 1508e4b86885SCheng Sean Ye else if (respmsg->status == FMA_MEM_STAT_ILLEGAL) 1509e4b86885SCheng Sean Ye rc = EINVAL; 1510e4b86885SCheng Sean Ye } 151131e37bb4Svn83148 } 151231e37bb4Svn83148 151331e37bb4Svn83148 lhp->freep(resp, resplen); 151431e37bb4Svn83148 151531e37bb4Svn83148 return (rc); 151631e37bb4Svn83148 } 151731e37bb4Svn83148 151831e37bb4Svn83148 151931e37bb4Svn83148 /* 152031e37bb4Svn83148 * APIs 152131e37bb4Svn83148 */ 152231e37bb4Svn83148 int 152331e37bb4Svn83148 ldmsvcs_check_channel(void) 152431e37bb4Svn83148 { 152531e37bb4Svn83148 struct stat buf; 152631e37bb4Svn83148 152731e37bb4Svn83148 if (stat(FDS_VLDC, &buf) == 0) 152831e37bb4Svn83148 return (0); /* vldc exists */ 152931e37bb4Svn83148 else if (errno == ENOENT || errno == ENOTDIR) 153031e37bb4Svn83148 return (1); /* vldc does not exist */ 153131e37bb4Svn83148 else 153231e37bb4Svn83148 return (-1); /* miscellaneous error */ 153331e37bb4Svn83148 } 153431e37bb4Svn83148 153531e37bb4Svn83148 153631e37bb4Svn83148 /*ARGSUSED*/ 153731e37bb4Svn83148 void 153831e37bb4Svn83148 ldmsvcs_init(struct ldom_hdl *lhp) 153931e37bb4Svn83148 { 154031e37bb4Svn83148 if (ldmsvcs_check_channel() != 0) 154131e37bb4Svn83148 return; 154231e37bb4Svn83148 154331e37bb4Svn83148 lhp->lsinfo = channel_init(lhp); 154431e37bb4Svn83148 poller_add_client(); 154531e37bb4Svn83148 } 154631e37bb4Svn83148 154731e37bb4Svn83148 154831e37bb4Svn83148 /*ARGSUSED*/ 154931e37bb4Svn83148 void 155031e37bb4Svn83148 ldmsvcs_fini(struct ldom_hdl *lhp) 155131e37bb4Svn83148 { 155231e37bb4Svn83148 if (ldmsvcs_check_channel() != 0) 155331e37bb4Svn83148 return; 155431e37bb4Svn83148 155531e37bb4Svn83148 poller_remove_client(); 155631e37bb4Svn83148 } 155731e37bb4Svn83148 155831e37bb4Svn83148 155931e37bb4Svn83148 /*ARGSUSED*/ 156031e37bb4Svn83148 ssize_t 156131e37bb4Svn83148 ldmsvcs_get_core_md(struct ldom_hdl *lhp, uint64_t **buf) 156231e37bb4Svn83148 { 156331e37bb4Svn83148 ds_hdr_t *H; 156431e37bb4Svn83148 ds_data_handle_t *D; 156531e37bb4Svn83148 fma_req_pri_t *R; 156631e37bb4Svn83148 156725351652SVuong Nguyen char *svcname = LDM_DS_NAME_PRI; 156831e37bb4Svn83148 void *resp; 156931e37bb4Svn83148 size_t resplen, reqmsglen; 157031e37bb4Svn83148 ssize_t buflen; 157131e37bb4Svn83148 int rc; 157231e37bb4Svn83148 157331e37bb4Svn83148 if (lhp->lsinfo == NULL) 157431e37bb4Svn83148 return (-1); 157531e37bb4Svn83148 157631e37bb4Svn83148 reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) + 157731e37bb4Svn83148 sizeof (fma_req_pri_t); 157831e37bb4Svn83148 157931e37bb4Svn83148 H = lhp->allocp(reqmsglen); 158031e37bb4Svn83148 D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 158131e37bb4Svn83148 R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t)); 158231e37bb4Svn83148 158331e37bb4Svn83148 H->msg_type = DS_DATA; 158431e37bb4Svn83148 H->payload_len = sizeof (ds_data_handle_t) + 158531e37bb4Svn83148 sizeof (fma_req_pri_t); 158631e37bb4Svn83148 158731e37bb4Svn83148 R->req_num = fds_svc_req_num(); 158831e37bb4Svn83148 158931e37bb4Svn83148 if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen, 159031e37bb4Svn83148 &D->svc_handle, svcname, &resp, &resplen)) != 0) { 159131e37bb4Svn83148 lhp->freep(H, reqmsglen); 159231e37bb4Svn83148 errno = rc; 159331e37bb4Svn83148 return (-1); 159431e37bb4Svn83148 } 159531e37bb4Svn83148 159631e37bb4Svn83148 lhp->freep(H, reqmsglen); 159731e37bb4Svn83148 159831e37bb4Svn83148 /* 159931e37bb4Svn83148 * resp should contain the req_num immediately followed by the PRI 160031e37bb4Svn83148 * (the latter may or may not be present). unfortunately, the 160131e37bb4Svn83148 * current compiler flags cause a warning for the following 160231e37bb4Svn83148 * definition 160331e37bb4Svn83148 * 160431e37bb4Svn83148 * typedef struct { 160531e37bb4Svn83148 * uint64_t req_num; 160631e37bb4Svn83148 * uint8_t pri[]; 160731e37bb4Svn83148 * } fma_pri_resp_t; 160831e37bb4Svn83148 * 160931e37bb4Svn83148 * so we do not use the struct here. 161031e37bb4Svn83148 */ 161131e37bb4Svn83148 if (resplen <= sizeof (uint64_t)) { 161231e37bb4Svn83148 lhp->freep(resp, resplen); 161331e37bb4Svn83148 if (resplen == sizeof (uint64_t)) 161431e37bb4Svn83148 return (0); 161531e37bb4Svn83148 else 161631e37bb4Svn83148 return (-1); 161731e37bb4Svn83148 } 161831e37bb4Svn83148 161931e37bb4Svn83148 buflen = resplen - sizeof (uint64_t); 162031e37bb4Svn83148 *buf = lhp->allocp(buflen); 162131e37bb4Svn83148 162231e37bb4Svn83148 bcopy((void *)((ptrdiff_t)resp + sizeof (uint64_t)), *buf, buflen); 162331e37bb4Svn83148 lhp->freep(resp, resplen); 162431e37bb4Svn83148 162531e37bb4Svn83148 return (buflen); 162631e37bb4Svn83148 } 162731e37bb4Svn83148 162831e37bb4Svn83148 162931e37bb4Svn83148 /* 163031e37bb4Svn83148 * see cpu_request() for a description of return values 163131e37bb4Svn83148 */ 163231e37bb4Svn83148 int 163331e37bb4Svn83148 ldmsvcs_cpu_req_status(struct ldom_hdl *lhp, uint32_t cpuid) 163431e37bb4Svn83148 { 163531e37bb4Svn83148 return (cpu_request(lhp, FMA_CPU_REQ_STATUS, cpuid)); 163631e37bb4Svn83148 } 163731e37bb4Svn83148 163831e37bb4Svn83148 163931e37bb4Svn83148 int 164031e37bb4Svn83148 ldmsvcs_cpu_req_offline(struct ldom_hdl *lhp, uint32_t cpuid) 164131e37bb4Svn83148 { 164231e37bb4Svn83148 return (cpu_request(lhp, FMA_CPU_REQ_OFFLINE, cpuid)); 164331e37bb4Svn83148 } 164431e37bb4Svn83148 16455f149bcaScy152378 int 16465f149bcaScy152378 ldmsvcs_cpu_req_online(struct ldom_hdl *lhp, uint32_t cpuid) 16475f149bcaScy152378 { 16485f149bcaScy152378 return (cpu_request(lhp, FMA_CPU_REQ_ONLINE, cpuid)); 16495f149bcaScy152378 } 165031e37bb4Svn83148 165131e37bb4Svn83148 /* 165231e37bb4Svn83148 * see mem_request() for a description of return values 165331e37bb4Svn83148 */ 165431e37bb4Svn83148 int 165531e37bb4Svn83148 ldmsvcs_mem_req_status(struct ldom_hdl *lhp, uint64_t pa) 165631e37bb4Svn83148 { 165731e37bb4Svn83148 return (mem_request(lhp, FMA_MEM_REQ_STATUS, pa, getpagesize())); 165831e37bb4Svn83148 } 165931e37bb4Svn83148 166031e37bb4Svn83148 int 166131e37bb4Svn83148 ldmsvcs_mem_req_retire(struct ldom_hdl *lhp, uint64_t pa) 166231e37bb4Svn83148 { 166331e37bb4Svn83148 return (mem_request(lhp, FMA_MEM_REQ_RETIRE, pa, getpagesize())); 166431e37bb4Svn83148 } 166531e37bb4Svn83148 16665f149bcaScy152378 int 16675f149bcaScy152378 ldmsvcs_mem_req_unretire(struct ldom_hdl *lhp, uint64_t pa) 16685f149bcaScy152378 { 16695f149bcaScy152378 return (mem_request(lhp, FMA_MEM_REQ_RESURRECT, pa, getpagesize())); 16705f149bcaScy152378 } 16715f149bcaScy152378 167225351652SVuong Nguyen int 167325351652SVuong Nguyen ldmsvcs_io_req_id(struct ldom_hdl *lhp, uint64_t addr, uint_t type, 167425351652SVuong Nguyen uint64_t *virt_addr, char *name, int name_len, uint64_t *did) 167525351652SVuong Nguyen { 167625351652SVuong Nguyen 167725351652SVuong Nguyen ds_hdr_t *H; 167825351652SVuong Nguyen ds_data_handle_t *D; 167925351652SVuong Nguyen fma_io_req_t *R; 168025351652SVuong Nguyen 168125351652SVuong Nguyen char *svcname = LDM_DS_NAME_IOD; 168225351652SVuong Nguyen void *resp; 168325351652SVuong Nguyen fma_io_resp_t *iop; 168425351652SVuong Nguyen size_t resplen, reqmsglen; 168525351652SVuong Nguyen int offset; 168625351652SVuong Nguyen int rc; 168725351652SVuong Nguyen 168825351652SVuong Nguyen if (lhp->lsinfo == NULL) 168925351652SVuong Nguyen return (-1); 169025351652SVuong Nguyen 169125351652SVuong Nguyen reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) + 169225351652SVuong Nguyen sizeof (fma_io_req_t); 169325351652SVuong Nguyen 169425351652SVuong Nguyen H = lhp->allocp(reqmsglen); 169525351652SVuong Nguyen D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t)); 169625351652SVuong Nguyen R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t)); 169725351652SVuong Nguyen 169825351652SVuong Nguyen H->msg_type = DS_DATA; 169925351652SVuong Nguyen H->payload_len = sizeof (ds_data_handle_t) + sizeof (fma_io_req_t); 170025351652SVuong Nguyen 170125351652SVuong Nguyen R->req_num = fds_svc_req_num(); 170225351652SVuong Nguyen R->msg_type = type; 170325351652SVuong Nguyen R->rsrc_address = addr; 170425351652SVuong Nguyen 170525351652SVuong Nguyen rc = ENOMSG; 170625351652SVuong Nguyen if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen, 170725351652SVuong Nguyen &D->svc_handle, svcname, &resp, &resplen)) != 0) { 170825351652SVuong Nguyen lhp->freep(H, reqmsglen); 170925351652SVuong Nguyen return (rc); 171025351652SVuong Nguyen } 171125351652SVuong Nguyen lhp->freep(H, reqmsglen); 171225351652SVuong Nguyen 171325351652SVuong Nguyen /* 171425351652SVuong Nguyen * resp should contain the req_num, status, virtual addr, domain id 171525351652SVuong Nguyen * and the domain name. The domain name may or may not be present. 171625351652SVuong Nguyen */ 171725351652SVuong Nguyen offset = sizeof (fma_io_resp_t); 171825351652SVuong Nguyen if (resplen < offset) { 171925351652SVuong Nguyen lhp->freep(resp, resplen); 172025351652SVuong Nguyen return (-1); 172125351652SVuong Nguyen } 172225351652SVuong Nguyen 172325351652SVuong Nguyen iop = (fma_io_resp_t *)resp; 172425351652SVuong Nguyen switch (iop->result) { 172525351652SVuong Nguyen case FMA_IO_RESP_OK: 172625351652SVuong Nguyen /* success */ 172725351652SVuong Nguyen rc = 0; 172825351652SVuong Nguyen *virt_addr = iop->virt_rsrc_address; 172925351652SVuong Nguyen *did = iop->domain_id; 173025351652SVuong Nguyen if (name == NULL || name_len <= 0) 173125351652SVuong Nguyen break; 173225351652SVuong Nguyen *name = '\0'; 173325351652SVuong Nguyen if (resplen > offset) { 173425351652SVuong Nguyen (void) strncpy(name, (char *)((ptrdiff_t)resp + offset), 173525351652SVuong Nguyen name_len); 173625351652SVuong Nguyen } 173725351652SVuong Nguyen break; 173825351652SVuong Nguyen default: 173925351652SVuong Nguyen rc = -1; 174025351652SVuong Nguyen break; 174125351652SVuong Nguyen } 174225351652SVuong Nguyen 174325351652SVuong Nguyen lhp->freep(resp, resplen); 174425351652SVuong Nguyen return (rc); 174525351652SVuong Nguyen } 174625351652SVuong Nguyen 174731e37bb4Svn83148 /* end file */ 1748