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
get_smf_int_val(char * prop_nm,int min,int max,int default_val)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
channel_close(struct ldmsvcs_info * lsp)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
read_stream(int fd,void * buf,size_t size)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
poller_handle_data(int fd,size_t payloadsize)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
poller_recv_data(struct ldom_hdl * lhp,uint64_t req_num,int index,void ** resp,size_t * resplen)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
poller_add_client(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
poller_remove_client(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
poller_add_pending(uint64_t req_num)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
poller_delete_pending(uint64_t req_num,int index)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
poller_shutdown(boolean_t wait)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 *
poller_loop(void * arg)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
poller_init(struct ldmsvcs_info * lsp)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
poller_fini(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
fds_send(struct ldmsvcs_info * lsp,void * msg,size_t msglen)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
fds_min_max_versions(uint16_t * min_major,uint16_t * max_major)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
fds_negotiate_version(uint16_t req_major,uint16_t * new_majorp,uint16_t * new_minorp)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
fds_svc_add(struct ldmsvcs_info * lsp,ds_reg_req_t * req,int minor)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
fds_svc_reset(struct ldmsvcs_info * lsp,int index)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
fds_svc_remove(struct ldmsvcs_info * lsp,ds_svc_hdl_t svc_handle)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
ds_handle_msg_noop(struct ldmsvcs_info * lsp,void * buf,size_t len)77631e37bb4Svn83148 ds_handle_msg_noop(struct ldmsvcs_info *lsp, void *buf, size_t len)
77731e37bb4Svn83148 {
77831e37bb4Svn83148 }
77931e37bb4Svn83148
78031e37bb4Svn83148 static void
ds_handle_init_req(struct ldmsvcs_info * lsp,void * buf,size_t len)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
ds_handle_reg_req(struct ldmsvcs_info * lsp,void * buf,size_t len)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
ds_handle_unreg(struct ldmsvcs_info * lsp,void * buf,size_t len)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
fds_svc_alloc(struct ldmsvcs_info * lsp)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 *
fds_svc_lookup(struct ldmsvcs_info * lsp,char * name)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
fds_svc_req_num(void)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
read_msg(struct ldmsvcs_info * lsp)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
channel_openreset(struct ldmsvcs_info * lsp)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
channel_fini(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 *
channel_init(struct ldom_hdl * lhp)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
sendrecv(struct ldom_hdl * lhp,uint64_t req_num,void * msg,size_t msglen,ds_svc_hdl_t * svc_hdl,char * svcname,void ** resp,size_t * resplen)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
cpu_request(struct ldom_hdl * lhp,uint32_t msg_type,uint32_t cpuid)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
mem_request(struct ldom_hdl * lhp,uint32_t msg_type,uint64_t pa,uint64_t pgsize)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
ldmsvcs_check_channel(void)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
ldmsvcs_init(struct ldom_hdl * lhp)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
ldmsvcs_fini(struct ldom_hdl * lhp)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
ldmsvcs_get_core_md(struct ldom_hdl * lhp,uint64_t ** buf)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
ldmsvcs_cpu_req_status(struct ldom_hdl * lhp,uint32_t cpuid)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
ldmsvcs_cpu_req_offline(struct ldom_hdl * lhp,uint32_t cpuid)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
ldmsvcs_cpu_req_online(struct ldom_hdl * lhp,uint32_t cpuid)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
ldmsvcs_mem_req_status(struct ldom_hdl * lhp,uint64_t pa)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
ldmsvcs_mem_req_retire(struct ldom_hdl * lhp,uint64_t pa)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
ldmsvcs_mem_req_unretire(struct ldom_hdl * lhp,uint64_t pa)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
ldmsvcs_io_req_id(struct ldom_hdl * lhp,uint64_t addr,uint_t type,uint64_t * virt_addr,char * name,int name_len,uint64_t * did)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