xref: /titanic_51/usr/src/lib/fm/libldom/sparc/ldmsvcs_utils.c (revision f044df33d9fe9e8e3ed7344a8b548b17f20709f2)
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