xref: /onnv-gate/usr/src/lib/fm/libldom/sparc/ldmsvcs_utils.c (revision 6408:2dba2c05f7fb)
12072Svn83148 /*
22072Svn83148  * CDDL HEADER START
32072Svn83148  *
42072Svn83148  * The contents of this file are subject to the terms of the
52072Svn83148  * Common Development and Distribution License (the "License").
62072Svn83148  * You may not use this file except in compliance with the License.
72072Svn83148  *
82072Svn83148  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92072Svn83148  * or http://www.opensolaris.org/os/licensing.
102072Svn83148  * See the License for the specific language governing permissions
112072Svn83148  * and limitations under the License.
122072Svn83148  *
132072Svn83148  * When distributing Covered Code, include this CDDL HEADER in each
142072Svn83148  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152072Svn83148  * If applicable, add the following below this CDDL HEADER, with the
162072Svn83148  * fields enclosed by brackets "[]" replaced with your own identifying
172072Svn83148  * information: Portions Copyright [yyyy] [name of copyright owner]
182072Svn83148  *
192072Svn83148  * CDDL HEADER END
202072Svn83148  */
212072Svn83148 /*
226111Scy152378  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
232072Svn83148  * Use is subject to license terms.
242072Svn83148  */
252072Svn83148 
262072Svn83148 #pragma ident	"%Z%%M%	%I%	%E% SMI"
272072Svn83148 
282072Svn83148 #include <stdlib.h>
292072Svn83148 #include <stdio.h>
302072Svn83148 #include <strings.h>
312072Svn83148 #include <sys/types.h>
322072Svn83148 #include <sys/stat.h>
332072Svn83148 #include <time.h>
342072Svn83148 #include <fcntl.h>
352072Svn83148 #include <unistd.h>
362072Svn83148 #include <errno.h>
372072Svn83148 #include <assert.h>
382072Svn83148 #include <umem.h>
392072Svn83148 #include <alloca.h>
402072Svn83148 #include <sys/processor.h>
412072Svn83148 #include <poll.h>
422072Svn83148 #include <pthread.h>
434358Srb144127 #include <values.h>
444358Srb144127 #include <libscf.h>
452072Svn83148 
462072Svn83148 #include "ldmsvcs_utils.h"
472072Svn83148 
482072Svn83148 #define	ASSERT(cnd) \
492072Svn83148 	((void) ((cnd) || ((void) fprintf(stderr, \
502072Svn83148 		"assertion failure in %s:%d: %s\n", \
512072Svn83148 		__FILE__, __LINE__, #cnd), 0)))
522072Svn83148 
532072Svn83148 #define	FDS_VLDC \
542072Svn83148 	"/devices/virtual-devices@100/channel-devices@200/" \
552072Svn83148 	"/virtual-channel-client@1:ldmfma"
562072Svn83148 
574358Srb144127 /* allow timeouts in sec that are nearly forever but small enough for an int */
584358Srb144127 #define	LDM_TIMEOUT_CEILING	(MAXINT / 2)
592072Svn83148 
602072Svn83148 #define	MIN(x, y)	((x) < (y) ? (x) : (y))
612072Svn83148 
622072Svn83148 /*
632072Svn83148  * functions in this file are for version 1.0 of FMA domain services
642072Svn83148  */
652072Svn83148 static ds_ver_t ds_vers[] = {
662072Svn83148 	{ 1, 0 }
672072Svn83148 };
682072Svn83148 
692072Svn83148 #define	DS_NUM_VER	(sizeof (ds_vers) / sizeof (ds_ver_t))
702072Svn83148 
712072Svn83148 /*
722072Svn83148  * information for each channel
732072Svn83148  */
742072Svn83148 struct ldmsvcs_info {
752072Svn83148 	pthread_mutex_t mt;
762072Svn83148 	pthread_cond_t cv;
772072Svn83148 	fds_channel_t fds_chan;
782072Svn83148 	fds_reg_svcs_t fmas_svcs;
792072Svn83148 	int cv_twait;
802072Svn83148 };
812072Svn83148 
822072Svn83148 /*
832072Svn83148  * struct listdata_s and struct poller_s are used to maintain the state of
842072Svn83148  * the poller thread.  this thread is used to manage incoming messages and
852072Svn83148  * pass those messages onto the correct requesting thread.  see the "poller
862072Svn83148  * functions" section for more details.
872072Svn83148  */
882072Svn83148 struct listdata_s {
892072Svn83148 	enum {
902072Svn83148 		UNUSED,
912072Svn83148 		PENDING,
922072Svn83148 		ARRIVED
932072Svn83148 	} status;
942072Svn83148 	uint64_t req_num;
952072Svn83148 	int fd;
962072Svn83148 	size_t datalen;
972072Svn83148 };
982072Svn83148 
992072Svn83148 static struct poller_s {
1002072Svn83148 	pthread_mutex_t mt;
1012072Svn83148 	pthread_cond_t cv;
1022072Svn83148 	pthread_t polling_tid;
1032072Svn83148 	int doreset;
1042072Svn83148 	int doexit;
1052072Svn83148 	int nclients;
1062072Svn83148 	struct listdata_s **list;
1072072Svn83148 	int list_len;
1082072Svn83148 	int pending_count;
1092072Svn83148 } pollbase = {
1102072Svn83148 	PTHREAD_MUTEX_INITIALIZER,
1112072Svn83148 	PTHREAD_COND_INITIALIZER,
1122072Svn83148 	0,
1132072Svn83148 	1,
1142072Svn83148 	0,
1152072Svn83148 	0,
1162072Svn83148 	NULL,
1172072Svn83148 	0,
1182072Svn83148 	0
1192072Svn83148 };
1202072Svn83148 
1212072Svn83148 
1222072Svn83148 static struct ldmsvcs_info *channel_init(struct ldom_hdl *lhp);
1232072Svn83148 static int channel_openreset(struct ldmsvcs_info *lsp);
1242072Svn83148 static int read_msg(struct ldmsvcs_info *lsp);
1252072Svn83148 
1262072Svn83148 
1274358Srb144127 static int
1284358Srb144127 get_smf_int_val(char *prop_nm, int min, int max, int default_val)
1294358Srb144127 {
1304358Srb144127 	scf_simple_prop_t	*prop;		/* SMF property */
1314358Srb144127 	int64_t			*valp;		/* prop value ptr */
1324358Srb144127 	int64_t			val;		/* prop value to return */
1334358Srb144127 
1344358Srb144127 	val = default_val;
1354358Srb144127 	if ((prop = scf_simple_prop_get(NULL, LDM_SVC_NM, LDM_PROP_GROUP_NM,
1364358Srb144127 	    prop_nm)) != NULL) {
1374358Srb144127 		if ((valp = scf_simple_prop_next_integer(prop)) != NULL) {
1384358Srb144127 			val = *valp;
1394358Srb144127 			if (val < min)
1404358Srb144127 				val = min;
1414358Srb144127 			else if (val > max)
1424358Srb144127 				val = max;
1434358Srb144127 		}
1444358Srb144127 		scf_simple_prop_free(prop);
1454358Srb144127 	}
1464358Srb144127 	return ((int)val);
1474358Srb144127 }
1484358Srb144127 
1492072Svn83148 static void
1502072Svn83148 channel_close(struct ldmsvcs_info *lsp)
1512072Svn83148 {
1522072Svn83148 	(void) pthread_mutex_lock(&lsp->mt);
1532072Svn83148 
1543327Svn83148 	if (lsp->fds_chan.state == CHANNEL_OPEN ||
1554358Srb144127 	    lsp->fds_chan.state == CHANNEL_READY) {
1563327Svn83148 		(void) close(lsp->fds_chan.fd);
1574358Srb144127 		lsp->cv_twait = get_smf_int_val(LDM_INIT_TO_PROP_NM,
1584358Srb144127 		    0, LDM_TIMEOUT_CEILING, LDM_INIT_WAIT_TIME);
1593327Svn83148 		lsp->fds_chan.state = CHANNEL_CLOSED;
1603327Svn83148 	}
1612072Svn83148 
1622072Svn83148 	(void) pthread_mutex_unlock(&lsp->mt);
1632072Svn83148 }
1642072Svn83148 
1652072Svn83148 /*
1662072Svn83148  * read size bytes of data from a streaming fd into buf
1672072Svn83148  */
1682072Svn83148 static int
1692072Svn83148 read_stream(int fd, void *buf, size_t size)
1702072Svn83148 {
1712072Svn83148 	pollfd_t pollfd;
1722072Svn83148 	ssize_t rv;
1732072Svn83148 	size_t data_left;
1742072Svn83148 	ptrdiff_t currentp;
1752072Svn83148 
1762072Svn83148 	pollfd.events = POLLIN;
1772072Svn83148 	pollfd.revents = 0;
1782072Svn83148 	pollfd.fd = fd;
1792072Svn83148 
1802072Svn83148 	currentp = (ptrdiff_t)buf;
1812072Svn83148 	data_left = size;
1822072Svn83148 
1832072Svn83148 	/*
1842072Svn83148 	 * data may come in bits and pieces
1852072Svn83148 	 */
1862072Svn83148 	do {
1872072Svn83148 		if ((rv = read(fd, (void *)currentp, data_left)) < 0) {
1882072Svn83148 			if (errno == EAGAIN && poll(&pollfd, 1, -1) > 0)
1892072Svn83148 				continue;	/* retry */
1902072Svn83148 			else
1912072Svn83148 				return (1);
1922072Svn83148 		}
1932072Svn83148 
1942072Svn83148 		data_left -= rv;
1952072Svn83148 		currentp += rv;
1962072Svn83148 	} while (data_left > 0);
1972072Svn83148 
1982072Svn83148 	return (0);
1992072Svn83148 }
2002072Svn83148 
2012072Svn83148 
2022072Svn83148 /*
2032072Svn83148  * poller functions
2042072Svn83148  *
2052072Svn83148  * at init time, a thread is created for the purpose of monitoring incoming
2062072Svn83148  * messages and doing one of the following:
2072072Svn83148  *
2082072Svn83148  * 1. doing the initial handshake and version negotiation
2092072Svn83148  *
2102072Svn83148  * 2. handing incoming data off to the requesting thread (which is an fmd
2112072Svn83148  * module or scheme thread)
2122072Svn83148  */
2132072Svn83148 static int
2142072Svn83148 poller_handle_data(int fd, size_t payloadsize)
2152072Svn83148 {
2162072Svn83148 	uint64_t *req_num;
2172072Svn83148 	void *pr;
2182072Svn83148 	size_t prlen;
2192072Svn83148 	int i;
2202072Svn83148 
2212072Svn83148 	prlen = sizeof (ds_data_handle_t) + sizeof (uint64_t);
2222072Svn83148 
2232072Svn83148 	if (payloadsize < prlen)
2242072Svn83148 		return (1);
2252072Svn83148 
2262072Svn83148 	pr = alloca(prlen);
2272072Svn83148 
2282072Svn83148 	if (read_stream(fd, pr, prlen) != 0)
2292072Svn83148 		return (1);
2302072Svn83148 
2312072Svn83148 	req_num = (uint64_t *)((ptrdiff_t)pr + sizeof (ds_data_handle_t));
2322072Svn83148 
2332072Svn83148 	(void) pthread_mutex_lock(&pollbase.mt);
2342072Svn83148 
2352072Svn83148 	for (i = 0; i < pollbase.list_len; i++) {
2362072Svn83148 		if (pollbase.list[i]->req_num == *req_num) {
2372072Svn83148 			ASSERT(pollbase.list[i]->status == PENDING);
2382072Svn83148 
2392072Svn83148 			pollbase.list[i]->status = ARRIVED;
2402072Svn83148 			pollbase.list[i]->fd = fd;
2412072Svn83148 			pollbase.list[i]->datalen = payloadsize - prlen;
2422072Svn83148 
2432072Svn83148 			pollbase.pending_count--;
2442072Svn83148 			(void) pthread_cond_broadcast(&pollbase.cv);
2452072Svn83148 			break;
2462072Svn83148 		}
2472072Svn83148 	}
2482072Svn83148 
2492072Svn83148 	/*
2502072Svn83148 	 * now wait for receiving thread to read in the data
2512072Svn83148 	 */
2522072Svn83148 	if (i < pollbase.list_len) {
2532072Svn83148 		while (pollbase.list[i]->status == ARRIVED)
2542072Svn83148 			(void) pthread_cond_wait(&pollbase.cv, &pollbase.mt);
2552072Svn83148 	}
2562072Svn83148 
2572072Svn83148 	(void) pthread_mutex_unlock(&pollbase.mt);
2582072Svn83148 
2592072Svn83148 	return (0);
2602072Svn83148 }
2612072Svn83148 
2622072Svn83148 
2632072Svn83148 /*
2642072Svn83148  * note that this function is meant to handle only DS_DATA messages
2652072Svn83148  */
2662072Svn83148 static int
2672072Svn83148 poller_recv_data(struct ldom_hdl *lhp, uint64_t req_num, int index,
2682072Svn83148 		void **resp, size_t *resplen)
2692072Svn83148 {
2702072Svn83148 	struct timespec twait;
2712072Svn83148 	int ier;
2722072Svn83148 
2732072Svn83148 	ier = 0;
2742072Svn83148 	twait.tv_sec = time(NULL) + lhp->lsinfo->cv_twait;
2752072Svn83148 	twait.tv_nsec = 0;
2762072Svn83148 
2772072Svn83148 	(void) pthread_mutex_lock(&pollbase.mt);
2782072Svn83148 
2792072Svn83148 	ASSERT(pollbase.list[index]->req_num == req_num);
2802072Svn83148 
2812072Svn83148 	while (pollbase.list[index]->status == PENDING &&
2822072Svn83148 	    pollbase.doreset == 0 && ier == 0)
2832072Svn83148 		ier = pthread_cond_timedwait(&pollbase.cv, &pollbase.mt,
2844358Srb144127 		    &twait);
2852072Svn83148 
2862072Svn83148 	if (ier == 0) {
2872072Svn83148 		if (pollbase.doreset == 0) {
2882072Svn83148 			ASSERT(pollbase.list[index]->status == ARRIVED);
2892072Svn83148 
2902072Svn83148 			/*
2912072Svn83148 			 * need to add req_num to beginning of resp
2922072Svn83148 			 */
2932072Svn83148 			*resplen = pollbase.list[index]->datalen +
2944358Srb144127 			    sizeof (uint64_t);
2952072Svn83148 			*resp = lhp->allocp(*resplen);
2962072Svn83148 			*((uint64_t *)*resp) = req_num;
2972072Svn83148 
2982072Svn83148 			if (read_stream(pollbase.list[index]->fd,
2994358Srb144127 			    (void *)((ptrdiff_t)*resp + sizeof (uint64_t)),
3004358Srb144127 			    *resplen - sizeof (uint64_t)) != 0)
3012072Svn83148 				ier = ETIMEDOUT;
3022072Svn83148 
3032072Svn83148 			pollbase.list[index]->status = UNUSED;
3042072Svn83148 			pollbase.list[index]->req_num = 0;
3052072Svn83148 			(void) pthread_cond_broadcast(&pollbase.cv);
3062072Svn83148 		} else {
3072072Svn83148 			if (--(pollbase.pending_count) == 0)
3082072Svn83148 				(void) pthread_cond_broadcast(&pollbase.cv);
3092072Svn83148 		}
3102072Svn83148 	}
3112072Svn83148 
3122072Svn83148 	(void) pthread_mutex_unlock(&pollbase.mt);
3132072Svn83148 
3142072Svn83148 	ASSERT(ier == 0 || ier == ETIMEDOUT);
3152072Svn83148 
3162072Svn83148 	return (ier);
3172072Svn83148 }
3182072Svn83148 
3192072Svn83148 
3202072Svn83148 static void
3212072Svn83148 poller_add_client(void)
3222072Svn83148 {
3232072Svn83148 	(void) pthread_mutex_lock(&pollbase.mt);
3242072Svn83148 	pollbase.nclients++;
3252072Svn83148 	(void) pthread_mutex_unlock(&pollbase.mt);
3262072Svn83148 }
3272072Svn83148 
3282072Svn83148 
3292072Svn83148 static void
3302072Svn83148 poller_remove_client(void)
3312072Svn83148 {
3322072Svn83148 	(void) pthread_mutex_lock(&pollbase.mt);
3332072Svn83148 	pollbase.nclients--;
3342072Svn83148 	ASSERT(pollbase.nclients >= 0);
3352072Svn83148 	(void) pthread_mutex_unlock(&pollbase.mt);
3362072Svn83148 }
3372072Svn83148 
3382072Svn83148 
3392072Svn83148 static int
3402072Svn83148 poller_add_pending(struct ldom_hdl *lhp, uint64_t req_num)
3412072Svn83148 {
3422072Svn83148 	int newlen, index, i, j;
3432072Svn83148 
3442072Svn83148 	(void) pthread_mutex_lock(&pollbase.mt);
3452072Svn83148 	pollbase.pending_count++;
3462072Svn83148 
3472072Svn83148 	for (j = 0, index = -1; j < 2 && index == -1; j++) {
3482072Svn83148 		for (i = 0; i < pollbase.list_len; i++) {
3492072Svn83148 			if (pollbase.list[i]->status == UNUSED) {
3502072Svn83148 				pollbase.list[i]->status = PENDING;
3512072Svn83148 				pollbase.list[i]->req_num = req_num;
3522072Svn83148 				pollbase.list[i]->datalen = 0;
3532072Svn83148 				index = i;
3542072Svn83148 				break;
3552072Svn83148 			}
3562072Svn83148 		}
3572072Svn83148 
3582072Svn83148 		if (index == -1) {
3592072Svn83148 			struct listdata_s **newlist, **oldlist;
3602072Svn83148 
3612072Svn83148 			/*
3622072Svn83148 			 * get to this point if list is not long enough.
3632072Svn83148 			 * check for a runaway list.  since requests are
3642072Svn83148 			 * synchronous (clients send a request and need to
3652072Svn83148 			 * wait for the result before returning) the size
3662072Svn83148 			 * of the list cannot be much more than the number
3672072Svn83148 			 * of clients.
3682072Svn83148 			 */
3692072Svn83148 			ASSERT(pollbase.list_len < pollbase.nclients + 1);
3702072Svn83148 
3712072Svn83148 			newlen = pollbase.list_len + 5;
3722072Svn83148 			newlist = lhp->allocp(newlen *
3734358Srb144127 			    sizeof (struct listdata_s));
3742072Svn83148 
3752072Svn83148 			for (i = 0; i < pollbase.list_len; i++)
3762072Svn83148 				newlist[i] = pollbase.list[i];
3772072Svn83148 
3782072Svn83148 			oldlist = pollbase.list;
3792072Svn83148 			pollbase.list = newlist;
3802072Svn83148 			lhp->freep(oldlist, pollbase.list_len *
3814358Srb144127 			    sizeof (struct listdata_s));
3822072Svn83148 
3832072Svn83148 			for (i = pollbase.list_len; i < newlen; i++) {
3842072Svn83148 				pollbase.list[i] =
3852072Svn83148 				    lhp->allocp(sizeof (struct listdata_s));
3862072Svn83148 				pollbase.list[i]->status = UNUSED;
3872072Svn83148 			}
3882072Svn83148 
3892072Svn83148 			pollbase.list_len = newlen;
3902072Svn83148 		}
3912072Svn83148 	}
3922072Svn83148 
3932072Svn83148 	(void) pthread_mutex_unlock(&pollbase.mt);
3942072Svn83148 	ASSERT(index != -1);
3952072Svn83148 
3962072Svn83148 	return (index);
3972072Svn83148 }
3982072Svn83148 
3992072Svn83148 
4002072Svn83148 static void
4012072Svn83148 poller_delete_pending(uint64_t req_num, int index)
4022072Svn83148 {
4032072Svn83148 	(void) pthread_mutex_lock(&pollbase.mt);
4042072Svn83148 
4052072Svn83148 	ASSERT(pollbase.list[index]->req_num == req_num);
4062072Svn83148 	pollbase.list[index]->status = UNUSED;
4072072Svn83148 
4082072Svn83148 	if (--(pollbase.pending_count) == 0 && pollbase.doreset == 1)
4092072Svn83148 		(void) pthread_cond_broadcast(&pollbase.cv);
4102072Svn83148 
4112072Svn83148 	(void) pthread_mutex_unlock(&pollbase.mt);
4122072Svn83148 }
4132072Svn83148 
4142072Svn83148 
4152072Svn83148 static void
4162072Svn83148 poller_shutdown(void)
4172072Svn83148 {
4182072Svn83148 	(void) pthread_mutex_lock(&pollbase.mt);
4192072Svn83148 
4202072Svn83148 	pollbase.doexit = 1;
4212072Svn83148 
4222072Svn83148 	(void) pthread_mutex_unlock(&pollbase.mt);
4232072Svn83148 }
4242072Svn83148 
4252072Svn83148 
4262072Svn83148 /*
4272072Svn83148  * perform the polling of incoming messages.  manage any resets (usually
4282072Svn83148  * due to one end of the connection being closed) as well as exit
4292072Svn83148  * conditions.
4302072Svn83148  */
4312072Svn83148 static void *
4322072Svn83148 poller_loop(void *arg)
4332072Svn83148 {
4342072Svn83148 	struct ldmsvcs_info *lsp;
4352072Svn83148 	pollfd_t pollfd;
4362072Svn83148 	int ier;
4372072Svn83148 
4382072Svn83148 	lsp = (struct ldmsvcs_info *)arg;
4392072Svn83148 
4402072Svn83148 	for (;;) {
4412072Svn83148 		(void) pthread_mutex_lock(&pollbase.mt);
4422072Svn83148 
4432072Svn83148 		if (pollbase.doexit) {
4442072Svn83148 			(void) pthread_mutex_unlock(&pollbase.mt);
4452072Svn83148 			break;
4462072Svn83148 		}
4472072Svn83148 
4482072Svn83148 		if (pollbase.doreset) {
4492072Svn83148 			int i;
4502072Svn83148 
4512072Svn83148 			while (pollbase.pending_count > 0)
4522072Svn83148 				(void) pthread_cond_wait(&pollbase.cv,
4534358Srb144127 				    &pollbase.mt);
4542072Svn83148 
4552072Svn83148 			ASSERT(pollbase.pending_count == 0);
4562072Svn83148 			for (i = 0; i < pollbase.list_len; i++)
4572072Svn83148 				pollbase.list[i]->status = UNUSED;
4582072Svn83148 
4592072Svn83148 			pollbase.doreset = 0;
4602072Svn83148 		}
4612072Svn83148 		(void) pthread_mutex_unlock(&pollbase.mt);
4622072Svn83148 
4632072Svn83148 		if ((ier = channel_openreset(lsp)) == 1) {
4642072Svn83148 			continue;
4652072Svn83148 		} else if (ier == 2) {
4662072Svn83148 			/*
4672072Svn83148 			 * start exit preparations
4682072Svn83148 			 */
4692072Svn83148 			poller_shutdown();
4702072Svn83148 			continue;
4712072Svn83148 		}
4722072Svn83148 
4732072Svn83148 		pollfd.events = POLLIN;
4742072Svn83148 		pollfd.revents = 0;
4752072Svn83148 		pollfd.fd = lsp->fds_chan.fd;
4762072Svn83148 
4772072Svn83148 		if (poll(&pollfd, 1, -1) <= 0 || read_msg(lsp) != 0) {
4782072Svn83148 			/*
4792072Svn83148 			 * read error and/or fd got closed
4802072Svn83148 			 */
4812072Svn83148 			(void) pthread_mutex_lock(&pollbase.mt);
4822072Svn83148 			pollbase.doreset = 1;
4832072Svn83148 			(void) pthread_mutex_unlock(&pollbase.mt);
4842072Svn83148 
4852072Svn83148 			channel_close(lsp);
4862072Svn83148 		}
4872072Svn83148 	}
4882072Svn83148 
4892072Svn83148 	return (NULL);
4902072Svn83148 }
4912072Svn83148 
4922072Svn83148 
4932072Svn83148 /*
4942072Svn83148  * create the polling thread
4952072Svn83148  */
4962072Svn83148 static int
4972072Svn83148 poller_init(struct ldmsvcs_info *lsp)
4982072Svn83148 {
4992072Svn83148 	int rc = 0;
5002072Svn83148 
5012072Svn83148 	(void) pthread_mutex_lock(&pollbase.mt);
5022072Svn83148 
5032072Svn83148 	if (pollbase.polling_tid == 0) {
5042072Svn83148 		pthread_attr_t attr;
5052072Svn83148 
5062072Svn83148 		/*
5072072Svn83148 		 * create polling thread for receiving messages
5082072Svn83148 		 */
5092072Svn83148 		(void) pthread_attr_init(&attr);
5102072Svn83148 		(void) pthread_attr_setdetachstate(&attr,
5114358Srb144127 		    PTHREAD_CREATE_DETACHED);
5122072Svn83148 
5132072Svn83148 		if (pthread_create(&pollbase.polling_tid, &attr,
5144358Srb144127 		    poller_loop, lsp) != 0)
5152072Svn83148 			rc = 1;
5162072Svn83148 
5172072Svn83148 		(void) pthread_attr_destroy(&attr);
5182072Svn83148 	}
5192072Svn83148 
5202072Svn83148 	(void) pthread_mutex_unlock(&pollbase.mt);
5212072Svn83148 
5222072Svn83148 	return (rc);
5232072Svn83148 }
5242072Svn83148 
5252072Svn83148 
5262072Svn83148 /*
5272072Svn83148  * utilities for message handlers
5282072Svn83148  */
5292072Svn83148 static int
5302072Svn83148 fds_send(struct ldmsvcs_info *lsp, void *msg, size_t msglen)
5312072Svn83148 {
5322072Svn83148 	static pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER;
5332072Svn83148 
5342072Svn83148 	(void) pthread_mutex_lock(&mt);
5352072Svn83148 
5362072Svn83148 	if (write(lsp->fds_chan.fd, msg, msglen) != msglen) {
5372072Svn83148 		channel_close(lsp);
5382072Svn83148 		(void) pthread_mutex_unlock(&mt);
5392072Svn83148 		return (ETIMEDOUT);
5402072Svn83148 	}
5412072Svn83148 
5422072Svn83148 	(void) pthread_mutex_unlock(&mt);
5432072Svn83148 	return (0);
5442072Svn83148 }
5452072Svn83148 
5462072Svn83148 
5472072Svn83148 /*
5482072Svn83148  * Find the max and min version supported
5492072Svn83148  */
5502072Svn83148 static void
5512072Svn83148 fds_min_max_versions(uint16_t *min_major, uint16_t *max_major)
5522072Svn83148 {
5532072Svn83148 	int i;
5542072Svn83148 
5552072Svn83148 	*min_major = ds_vers[0].major;
5562072Svn83148 	*max_major = *min_major;
5572072Svn83148 
5582072Svn83148 	for (i = 1; i < DS_NUM_VER; i++) {
5592072Svn83148 		if (ds_vers[i].major < *min_major)
5602072Svn83148 			*min_major = ds_vers[i].major;
5612072Svn83148 
5622072Svn83148 		if (ds_vers[i].major > *max_major)
5632072Svn83148 			*max_major = ds_vers[i].major;
5642072Svn83148 	}
5652072Svn83148 }
5662072Svn83148 
5672072Svn83148 /*
5682072Svn83148  * check whether the major and minor numbers requested by remote ds client
5692072Svn83148  * can be satisfied.  if the requested major is supported, true is
5702072Svn83148  * returned, and the agreed minor is returned in new_minor.  if the
5712072Svn83148  * requested major is not supported, the routine returns false, and the
5722072Svn83148  * closest major is returned in *new_major, upon which the ds client should
5732072Svn83148  * renegotiate.  the closest major is the just lower that the requested
5742072Svn83148  * major number.
5752072Svn83148  */
5762072Svn83148 static boolean_t
5772072Svn83148 fds_negotiate_version(uint16_t req_major, uint16_t *new_majorp,
5782072Svn83148     uint16_t *new_minorp)
5792072Svn83148 {
5802072Svn83148 	int i = 0;
5812072Svn83148 	uint16_t major, lower_major;
5822072Svn83148 	uint16_t min_major, max_major;
5832072Svn83148 	boolean_t found_match = B_FALSE;
5842072Svn83148 
5852072Svn83148 	fds_min_max_versions(&min_major, &max_major);
5862072Svn83148 
5872072Svn83148 	/*
5882072Svn83148 	 * if the minimum version supported is greater than the version
5892072Svn83148 	 * requested, return the lowest version supported
5902072Svn83148 	 */
5912072Svn83148 	if (min_major > req_major) {
5922072Svn83148 		*new_majorp = min_major;
5932072Svn83148 		return (B_FALSE);
5942072Svn83148 	}
5952072Svn83148 
5962072Svn83148 	/*
5972072Svn83148 	 * if the largest version supported is lower than the version
5982072Svn83148 	 * requested, return the largest version supported
5992072Svn83148 	 */
6002072Svn83148 	if (max_major < req_major) {
6012072Svn83148 		*new_majorp = max_major;
6022072Svn83148 		return (B_FALSE);
6032072Svn83148 	}
6042072Svn83148 
6052072Svn83148 	/*
6062072Svn83148 	 * now we know that the requested version lies between the min and
6072072Svn83148 	 * max versions supported.  check if the requested major can be
6082072Svn83148 	 * found in supported versions.
6092072Svn83148 	 */
6102072Svn83148 	lower_major = min_major;
6112072Svn83148 	for (i = 0; i < DS_NUM_VER; i++) {
6122072Svn83148 		major = ds_vers[i].major;
6132072Svn83148 		if (major == req_major) {
6142072Svn83148 			found_match = B_TRUE;
6152072Svn83148 			*new_minorp = ds_vers[i].minor;
6162072Svn83148 			*new_majorp = major;
6172072Svn83148 			break;
6182072Svn83148 		} else if ((major < req_major) && (major > lower_major))
6192072Svn83148 			lower_major = major;
6202072Svn83148 	}
6212072Svn83148 
6222072Svn83148 	/*
6232072Svn83148 	 * If  no match is found, return the closest available number
6242072Svn83148 	 */
6252072Svn83148 	if (!found_match)
6262072Svn83148 		*new_majorp = lower_major;
6272072Svn83148 
6282072Svn83148 	return (found_match);
6292072Svn83148 }
6302072Svn83148 
6312072Svn83148 
6322072Svn83148 /*
6332072Svn83148  * return 0 if service is added; 1 if service is a duplicate
6342072Svn83148  */
6352072Svn83148 static int
6362072Svn83148 fds_svc_add(struct ldmsvcs_info *lsp, ds_reg_req_t *req, int minor)
6372072Svn83148 {
6382072Svn83148 	fds_svc_t *svc;
6392072Svn83148 	int i, rc;
6402072Svn83148 
6412072Svn83148 	svc = NULL;
6422072Svn83148 	for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) {
6432072Svn83148 		if (strcmp(lsp->fmas_svcs.tbl[i]->name, req->svc_id) == 0) {
6442072Svn83148 			svc = lsp->fmas_svcs.tbl[i];
6452072Svn83148 			break;
6462072Svn83148 		}
6472072Svn83148 	}
6482072Svn83148 
6492072Svn83148 	if (svc == NULL)
6502072Svn83148 		return (0);	/* we don't need this service */
6512072Svn83148 
6522072Svn83148 	(void) pthread_mutex_lock(&lsp->fmas_svcs.mt);
6532072Svn83148 
6542072Svn83148 	/*
6552072Svn83148 	 * duplicate registration is OK --- we retain the previous entry
6562072Svn83148 	 * (which has not been unregistered anyway)
6572072Svn83148 	 */
6582072Svn83148 	if (svc->state == DS_SVC_ACTIVE) {
6592072Svn83148 		rc = 1;
6602072Svn83148 	} else {
6612072Svn83148 		svc->state = DS_SVC_ACTIVE;
6622072Svn83148 		svc->hdl = req->svc_handle;
6632072Svn83148 		svc->ver.major = req->major_vers;
6642072Svn83148 		svc->ver.minor = minor;
6652072Svn83148 
6662072Svn83148 		rc = 0;
6672072Svn83148 		(void) pthread_cond_broadcast(&lsp->fmas_svcs.cv);
6682072Svn83148 	}
6692072Svn83148 
6702072Svn83148 	(void) pthread_mutex_unlock(&lsp->fmas_svcs.mt);
6712072Svn83148 
6722072Svn83148 	return (rc);
6732072Svn83148 }
6742072Svn83148 
6752072Svn83148 
6762072Svn83148 static void
6772072Svn83148 fds_svc_reset(struct ldmsvcs_info *lsp, int index)
6782072Svn83148 {
6792072Svn83148 	int i, start, end;
6802072Svn83148 
6812072Svn83148 	if (index >= 0) {
6822072Svn83148 		start = index;
6832072Svn83148 		end = index + 1;
6842072Svn83148 	} else {
6852072Svn83148 		start = 0;
6862072Svn83148 		end = lsp->fmas_svcs.nsvcs;
6872072Svn83148 	}
6882072Svn83148 
6892072Svn83148 	(void) pthread_mutex_lock(&lsp->fmas_svcs.mt);
6902072Svn83148 
6912072Svn83148 	for (i = start; i < end; i++) {
6922072Svn83148 		lsp->fmas_svcs.tbl[i]->hdl = 0;
6932072Svn83148 		lsp->fmas_svcs.tbl[i]->state = DS_SVC_INVAL;
6942072Svn83148 		lsp->fmas_svcs.tbl[i]->ver.major =
6954358Srb144127 		    ds_vers[DS_NUM_VER - 1].major;
6962072Svn83148 		lsp->fmas_svcs.tbl[i]->ver.minor =
6974358Srb144127 		    ds_vers[DS_NUM_VER - 1].minor;
6982072Svn83148 	}
6992072Svn83148 
7002072Svn83148 	(void) pthread_mutex_unlock(&lsp->fmas_svcs.mt);
7012072Svn83148 }
7022072Svn83148 
7032072Svn83148 
7042072Svn83148 static int
7052072Svn83148 fds_svc_remove(struct ldmsvcs_info *lsp, ds_svc_hdl_t svc_handle)
7062072Svn83148 {
7072072Svn83148 	int i;
7082072Svn83148 
7092072Svn83148 	for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) {
7102072Svn83148 		if (lsp->fmas_svcs.tbl[i]->hdl == svc_handle) {
7112072Svn83148 			fds_svc_reset(lsp, i);
7122072Svn83148 			return (0);
7132072Svn83148 		}
7142072Svn83148 	}
7152072Svn83148 
7162072Svn83148 	return (1);
7172072Svn83148 }
7182072Svn83148 
7192072Svn83148 
7202072Svn83148 /*
7212072Svn83148  * message handlers
7222072Svn83148  */
7232072Svn83148 /*ARGSUSED*/
7242072Svn83148 static void
7252072Svn83148 ds_handle_msg_noop(struct ldmsvcs_info *lsp, void *buf, size_t len)
7262072Svn83148 {
7272072Svn83148 }
7282072Svn83148 
7292072Svn83148 static void
7302072Svn83148 ds_handle_init_req(struct ldmsvcs_info *lsp, void *buf, size_t len)
7312072Svn83148 {
7322072Svn83148 	ds_init_req_t *req;
7332072Svn83148 	uint16_t new_major, new_minor;
7342072Svn83148 	size_t msglen;
7352072Svn83148 
7362072Svn83148 	req = (ds_init_req_t *)buf;
7372072Svn83148 
7382072Svn83148 	/* sanity check the incoming message */
7392072Svn83148 	if (len != sizeof (ds_init_req_t)) {
7402072Svn83148 		channel_close(lsp);
7412072Svn83148 		return;
7422072Svn83148 	}
7432072Svn83148 
7442072Svn83148 	/*
7452072Svn83148 	 * Check version info. ACK only if the major numbers exactly
7462072Svn83148 	 * match. The service entity can retry with a new minor
7472072Svn83148 	 * based on the response sent as part of the NACK.
7482072Svn83148 	 */
7492072Svn83148 	if (fds_negotiate_version(req->major_vers, &new_major, &new_minor)) {
7502072Svn83148 		ds_hdr_t *H;
7512072Svn83148 		ds_init_ack_t *R;
7522072Svn83148 
7532072Svn83148 		msglen = sizeof (ds_hdr_t) + sizeof (ds_init_ack_t);
7542072Svn83148 		H = alloca(msglen);
7552072Svn83148 		R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
7562072Svn83148 
7572072Svn83148 		H->msg_type = DS_INIT_ACK;
7582072Svn83148 		H->payload_len = sizeof (ds_init_ack_t);
7592072Svn83148 		R->minor_vers = MIN(new_minor, req->minor_vers);
7602072Svn83148 
7612072Svn83148 		if (fds_send(lsp, H, msglen) != 0)
7622072Svn83148 			return;
7632072Svn83148 
7642072Svn83148 		(void) pthread_mutex_lock(&lsp->mt);
7652072Svn83148 		ASSERT(lsp->fds_chan.state == CHANNEL_OPEN);
7662072Svn83148 		lsp->fds_chan.state = CHANNEL_READY;
7673327Svn83148 
7683327Svn83148 		/*
7693327Svn83148 		 * Now the channel is ready after the handshake completes.
7703327Svn83148 		 * Reset the timeout to a smaller value for receiving messages
7713327Svn83148 		 * from the domain services.
7723327Svn83148 		 */
7734358Srb144127 		lsp->cv_twait = get_smf_int_val(LDM_RUNNING_TO_PROP_NM,
7744358Srb144127 		    0, LDM_TIMEOUT_CEILING, LDM_RUNNING_WAIT_TIME);
7753327Svn83148 
7762072Svn83148 		(void) pthread_mutex_unlock(&lsp->mt);
7772072Svn83148 	} else {
7782072Svn83148 		ds_hdr_t *H;
7792072Svn83148 		ds_init_nack_t *R;
7802072Svn83148 
7812072Svn83148 		msglen = sizeof (ds_hdr_t) + sizeof (ds_init_nack_t);
7822072Svn83148 		H = alloca(msglen);
7832072Svn83148 		R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
7842072Svn83148 
7852072Svn83148 		H->msg_type = DS_INIT_NACK;
7862072Svn83148 		H->payload_len = sizeof (ds_init_nack_t);
7872072Svn83148 		R->major_vers = new_major;
7882072Svn83148 
7892072Svn83148 		(void) fds_send(lsp, H, msglen);
7902072Svn83148 		/*
7912072Svn83148 		 * do not update state; remote end may attempt to initiate
7922072Svn83148 		 * connection with a different version
7932072Svn83148 		 */
7942072Svn83148 	}
7952072Svn83148 }
7962072Svn83148 
7972072Svn83148 
7982072Svn83148 /*ARGSUSED*/
7992072Svn83148 static void
8002072Svn83148 ds_handle_reg_req(struct ldmsvcs_info *lsp, void *buf, size_t len)
8012072Svn83148 {
8022072Svn83148 	ds_reg_req_t *req;
8032072Svn83148 	char *msg;
8042072Svn83148 	uint16_t new_major, new_minor;
8052072Svn83148 	size_t msglen;
8062072Svn83148 	int dup_svcreg = 0;
8072072Svn83148 
8082072Svn83148 	req = (ds_reg_req_t *)buf;
8092072Svn83148 	msg = (char *)req->svc_id;
8102072Svn83148 
8112072Svn83148 	/*
8122072Svn83148 	 * Service must be NULL terminated
8132072Svn83148 	 */
8142072Svn83148 	if (req->svc_id == NULL || strlen(req->svc_id) == 0 ||
8152072Svn83148 	    msg[strlen(req->svc_id)] != '\0') {
8162072Svn83148 		channel_close(lsp);
8172072Svn83148 		return;
8182072Svn83148 	}
8192072Svn83148 
8202072Svn83148 	if (fds_negotiate_version(req->major_vers, &new_major, &new_minor) &&
8212072Svn83148 	    (dup_svcreg = fds_svc_add(lsp, req,
8224358Srb144127 	    MIN(new_minor, req->minor_vers))) == 0) {
8232072Svn83148 
8242072Svn83148 		/*
8252072Svn83148 		 * Check version info. ACK only if the major numbers
8262072Svn83148 		 * exactly match. The service entity can retry with a new
8272072Svn83148 		 * minor based on the response sent as part of the NACK.
8282072Svn83148 		 */
8292072Svn83148 		ds_hdr_t *H;
8302072Svn83148 		ds_reg_ack_t *R;
8312072Svn83148 
8322072Svn83148 		msglen = sizeof (ds_hdr_t) + sizeof (ds_reg_ack_t);
8332072Svn83148 		H = alloca(msglen);
8342072Svn83148 		bzero(H, msglen);
8352072Svn83148 		R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
8362072Svn83148 
8372072Svn83148 		H->msg_type = DS_REG_ACK;
8382072Svn83148 		H->payload_len = sizeof (ds_reg_ack_t);
8392072Svn83148 		R->svc_handle = req->svc_handle;
8402072Svn83148 		R->minor_vers = MIN(new_minor, req->minor_vers);
8412072Svn83148 
8422072Svn83148 		(void) fds_send(lsp, H, msglen);
8432072Svn83148 	} else {
8442072Svn83148 		ds_hdr_t *H;
8452072Svn83148 		ds_reg_nack_t *R;
8462072Svn83148 
8472072Svn83148 		msglen = sizeof (ds_hdr_t) + sizeof (ds_reg_nack_t);
8482072Svn83148 		H = alloca(msglen);
8492072Svn83148 		bzero(H, msglen);
8502072Svn83148 		R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
8512072Svn83148 
8522072Svn83148 		H->msg_type = DS_REG_NACK;
8532072Svn83148 		H->payload_len = sizeof (ds_reg_nack_t);
8542072Svn83148 		R->svc_handle = req->svc_handle;
8552072Svn83148 		R->major_vers = new_major;
8562072Svn83148 
8572072Svn83148 		if (dup_svcreg)
8582072Svn83148 			R->result = DS_REG_DUP;
8592072Svn83148 		else
8602072Svn83148 			R->result = DS_REG_VER_NACK;
8612072Svn83148 
8622072Svn83148 		(void) fds_send(lsp, H, msglen);
8632072Svn83148 	}
8642072Svn83148 }
8652072Svn83148 
8662072Svn83148 
8672072Svn83148 /*ARGSUSED*/
8682072Svn83148 static void
8692072Svn83148 ds_handle_unreg(struct ldmsvcs_info *lsp, void *buf, size_t len)
8702072Svn83148 {
8712072Svn83148 	ds_unreg_req_t *req;
8722072Svn83148 	size_t msglen;
8732072Svn83148 
8742072Svn83148 	req = (ds_unreg_req_t *)buf;
8752072Svn83148 
8762072Svn83148 	if (fds_svc_remove(lsp, req->svc_handle) == 0) {
8772072Svn83148 		ds_hdr_t *H;
8782072Svn83148 		ds_unreg_ack_t *R;
8792072Svn83148 
8802072Svn83148 		msglen = sizeof (ds_hdr_t) + sizeof (ds_unreg_ack_t);
8812072Svn83148 		H = alloca(msglen);
8822072Svn83148 		R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
8832072Svn83148 
8842072Svn83148 		H->msg_type = DS_REG_ACK;
8852072Svn83148 		H->payload_len = sizeof (ds_unreg_ack_t);
8862072Svn83148 		R->svc_handle = req->svc_handle;
8872072Svn83148 
8882072Svn83148 		(void) fds_send(lsp, H, msglen);
8892072Svn83148 	} else {
8902072Svn83148 		ds_hdr_t *H;
8912072Svn83148 		ds_unreg_nack_t *R;
8922072Svn83148 
8932072Svn83148 		msglen = sizeof (ds_hdr_t) + sizeof (ds_unreg_nack_t);
8942072Svn83148 		H = alloca(msglen);
8952072Svn83148 		R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
8962072Svn83148 
8972072Svn83148 		H->msg_type = DS_REG_NACK;
8982072Svn83148 		H->payload_len = sizeof (ds_unreg_nack_t);
8992072Svn83148 		R->svc_handle = req->svc_handle;
9002072Svn83148 
9012072Svn83148 		(void) fds_send(lsp, H, msglen);
9022072Svn83148 	}
9032072Svn83148 }
9042072Svn83148 
9052072Svn83148 
9062072Svn83148 /*
9072072Svn83148  * Message handler lookup table (v1.0 only for now) Future
9082072Svn83148  * versions can add their own lookup table.
9092072Svn83148  */
9102072Svn83148 typedef void (*ds_msg_handler_t)(struct ldmsvcs_info *lsp,
9112072Svn83148 				void *buf, size_t len);
9122072Svn83148 
9132072Svn83148 static const ds_msg_handler_t ds_msg_handlers[] = {
9142072Svn83148 	ds_handle_init_req,		/* DS_INIT_REQ */
9152072Svn83148 	ds_handle_msg_noop,		/* DS_INIT_ACK */
9162072Svn83148 	ds_handle_msg_noop,		/* DS_INIT_NACK */
9172072Svn83148 	ds_handle_reg_req,		/* DS_REG_REQ */
9182072Svn83148 	ds_handle_msg_noop,		/* DS_REG_ACK */
9192072Svn83148 	ds_handle_msg_noop,		/* DS_REG_NACK */
9202072Svn83148 	ds_handle_unreg,		/* DS_UNREG */
9212072Svn83148 	ds_handle_msg_noop,		/* DS_UNREG_ACK */
9222072Svn83148 	ds_handle_msg_noop,		/* DS_UNREG_NACK */
9232072Svn83148 	ds_handle_msg_noop,		/* DS_DATA */
9242072Svn83148 	ds_handle_msg_noop		/* DS_NACK */
9252072Svn83148 };
9262072Svn83148 
9272072Svn83148 
9282072Svn83148 /*
9292072Svn83148  * message and service internal functions
9302072Svn83148  */
9312072Svn83148 static void
9322072Svn83148 fds_svc_alloc(struct ldom_hdl *lhp, struct ldmsvcs_info *lsp)
9332072Svn83148 {
9342072Svn83148 	int i;
9352072Svn83148 	char *name[] = { "fma-phys-cpu-service", "fma-phys-mem-service",
9362072Svn83148 			"fma-pri-service", NULL };
9372072Svn83148 
9382072Svn83148 	(void) pthread_mutex_init(&lsp->fmas_svcs.mt, NULL);
9392072Svn83148 	(void) pthread_cond_init(&lsp->fmas_svcs.cv, NULL);
9402072Svn83148 
9412072Svn83148 	for (lsp->fmas_svcs.nsvcs = 0; name[lsp->fmas_svcs.nsvcs] != NULL;
9422072Svn83148 	    lsp->fmas_svcs.nsvcs++)
9432072Svn83148 		;
9442072Svn83148 
9452072Svn83148 	lsp->fmas_svcs.tbl = (fds_svc_t **)lhp->allocp(sizeof (fds_svc_t *) *
9464358Srb144127 	    lsp->fmas_svcs.nsvcs);
9472072Svn83148 
9482072Svn83148 	for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) {
9492072Svn83148 		lsp->fmas_svcs.tbl[i] =
9504358Srb144127 		    (fds_svc_t *)lhp->allocp(sizeof (fds_svc_t));
9512072Svn83148 		bzero(lsp->fmas_svcs.tbl[i], sizeof (fds_svc_t));
9522072Svn83148 		lsp->fmas_svcs.tbl[i]->name = name[i];
9532072Svn83148 	}
9542072Svn83148 }
9552072Svn83148 
9562072Svn83148 
9572072Svn83148 static fds_svc_t *
9582072Svn83148 fds_svc_lookup(struct ldmsvcs_info *lsp, char *name)
9592072Svn83148 {
9602072Svn83148 	struct timespec twait;
9612072Svn83148 	fds_svc_t *svc;
9622072Svn83148 	int i, ier;
9632072Svn83148 
9642072Svn83148 	if (pthread_mutex_lock(&lsp->fmas_svcs.mt) == EINVAL)
9652072Svn83148 		return (NULL);	/* uninitialized or destroyed mutex */
9662072Svn83148 
9672072Svn83148 	svc = NULL;
9682072Svn83148 	for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) {
9692072Svn83148 		if (strcmp(lsp->fmas_svcs.tbl[i]->name, name) == 0) {
9702072Svn83148 			svc = lsp->fmas_svcs.tbl[i];
9712072Svn83148 			break;
9722072Svn83148 		}
9732072Svn83148 	}
9742072Svn83148 
9752072Svn83148 	ASSERT(svc != NULL);
9762072Svn83148 
9772072Svn83148 	ier = 0;
9782072Svn83148 	twait.tv_sec = time(NULL) + lsp->cv_twait;
9792072Svn83148 	twait.tv_nsec = 0;
9802072Svn83148 
9812072Svn83148 	while (svc->state != DS_SVC_ACTIVE && ier == 0 &&
9822072Svn83148 	    lsp->fds_chan.state != CHANNEL_UNUSABLE)
9832072Svn83148 		ier = pthread_cond_timedwait(&lsp->fmas_svcs.cv,
9844358Srb144127 		    &lsp->fmas_svcs.mt, &twait);
9852072Svn83148 
9862072Svn83148 	(void) pthread_mutex_unlock(&lsp->fmas_svcs.mt);
9872072Svn83148 
9882072Svn83148 	if (ier == 0)
9892072Svn83148 		return (svc);
9902072Svn83148 	else
9912072Svn83148 		return (NULL);
9922072Svn83148 }
9932072Svn83148 
9942072Svn83148 
9952072Svn83148 static uint64_t
9962072Svn83148 fds_svc_req_num(void)
9972072Svn83148 {
9982072Svn83148 	static uint64_t req_num = 1;
9992072Svn83148 
10002072Svn83148 	return (req_num++);
10012072Svn83148 }
10022072Svn83148 
10032072Svn83148 
10042072Svn83148 /*
10052072Svn83148  * return 0 if successful, 1 if otherwise
10062072Svn83148  */
10072072Svn83148 static int
10082072Svn83148 read_msg(struct ldmsvcs_info *lsp)
10092072Svn83148 {
10102072Svn83148 	ds_hdr_t header;
10112072Svn83148 	void *msg_buf;
10122072Svn83148 
10132072Svn83148 	/*
10142072Svn83148 	 * read the header
10152072Svn83148 	 */
10162072Svn83148 	if (read_stream(lsp->fds_chan.fd, &header, sizeof (ds_hdr_t)) != 0)
10172072Svn83148 		return (1);
10182072Svn83148 
10192072Svn83148 	if (header.msg_type >=
10202072Svn83148 	    sizeof (ds_msg_handlers) / sizeof (ds_msg_handler_t))
10214358Srb144127 		return (1);
10222072Svn83148 
10232072Svn83148 	/*
10242072Svn83148 	 * handle data as a special case
10252072Svn83148 	 */
10262072Svn83148 	if (header.msg_type == 9)
10272072Svn83148 		return (poller_handle_data(lsp->fds_chan.fd,
10284358Srb144127 		    header.payload_len));
10292072Svn83148 
10302072Svn83148 	/*
10312072Svn83148 	 * all other types of messages should be small
10322072Svn83148 	 */
10332072Svn83148 	ASSERT(header.payload_len < 1024);
10342072Svn83148 	msg_buf = alloca(header.payload_len);
10352072Svn83148 
10362072Svn83148 	/*
10372072Svn83148 	 * read the payload
10382072Svn83148 	 */
10392072Svn83148 	if (read_stream(lsp->fds_chan.fd, msg_buf, header.payload_len) != 0)
10402072Svn83148 		return (1);
10412072Svn83148 
10422072Svn83148 	(*ds_msg_handlers[header.msg_type])(lsp, msg_buf, header.payload_len);
10432072Svn83148 
10442072Svn83148 	return (0);
10452072Svn83148 }
10462072Svn83148 
10472072Svn83148 
10482072Svn83148 /*
10492072Svn83148  * return values:
10502072Svn83148  *  0 - success
10512072Svn83148  *  1 - problem with opening the channel
10522072Svn83148  *  2 - channed not opened; request to exit has been detected
10532072Svn83148  */
10542072Svn83148 static int
10552072Svn83148 channel_openreset(struct ldmsvcs_info *lsp)
10562072Svn83148 {
10572072Svn83148 	int ier;
10582072Svn83148 
10592072Svn83148 	ier = pthread_mutex_lock(&lsp->mt);
10602072Svn83148 
10612072Svn83148 	if (ier == EINVAL || lsp->fds_chan.state == CHANNEL_EXIT ||
10622072Svn83148 	    lsp->fds_chan.state == CHANNEL_UNUSABLE) {
10632072Svn83148 		(void) pthread_mutex_unlock(&lsp->mt);
10642072Svn83148 		return (2);
10652072Svn83148 	}
10662072Svn83148 
10672072Svn83148 	if (lsp->fds_chan.state == CHANNEL_UNINITIALIZED ||
10682072Svn83148 	    lsp->fds_chan.state == CHANNEL_CLOSED) {
10692072Svn83148 		(void) pthread_cond_broadcast(&lsp->cv);
10702072Svn83148 
10712072Svn83148 		if ((lsp->fds_chan.fd = open(FDS_VLDC, O_RDWR)) < 0) {
10722072Svn83148 			lsp->fds_chan.state = CHANNEL_UNUSABLE;
10734358Srb144127 			lsp->cv_twait = get_smf_int_val(LDM_RUNNING_TO_PROP_NM,
10744358Srb144127 			    0, LDM_TIMEOUT_CEILING, LDM_RUNNING_WAIT_TIME);
10752072Svn83148 			(void) pthread_mutex_unlock(&lsp->mt);
10762072Svn83148 			(void) pthread_cond_broadcast(&lsp->fmas_svcs.cv);
10772072Svn83148 
10782072Svn83148 			return (2);
10792072Svn83148 		} else {
10802072Svn83148 			vldc_opt_op_t op;
10812072Svn83148 
10822072Svn83148 			op.op_sel = VLDC_OP_SET;
10832072Svn83148 			op.opt_sel = VLDC_OPT_MODE;
1084*6408Sha137994 			op.opt_val = LDC_MODE_RELIABLE;
10852072Svn83148 
10862072Svn83148 			if (ioctl(lsp->fds_chan.fd, VLDC_IOCTL_OPT_OP,
10874358Srb144127 			    &op) != 0) {
10882072Svn83148 				(void) close(lsp->fds_chan.fd);
10892072Svn83148 				(void) pthread_mutex_unlock(&lsp->mt);
10902072Svn83148 				return (1);
10912072Svn83148 			}
10922072Svn83148 		}
10932072Svn83148 		lsp->fds_chan.state = CHANNEL_OPEN;
10942072Svn83148 	}
10952072Svn83148 
10962072Svn83148 	if (lsp->fds_chan.state == CHANNEL_OPEN) {
10972072Svn83148 		/*
10982072Svn83148 		 * reset various channel parameters
10992072Svn83148 		 */
11002072Svn83148 		lsp->fds_chan.ver.major = 0;
11012072Svn83148 		lsp->fds_chan.ver.minor = 0;
11022072Svn83148 		fds_svc_reset(lsp, -1);
11032072Svn83148 	}
11042072Svn83148 	(void) pthread_mutex_unlock(&lsp->mt);
11052072Svn83148 
11062072Svn83148 	return (0);
11072072Svn83148 }
11082072Svn83148 
11092072Svn83148 
11102072Svn83148 static void
11112072Svn83148 channel_fini(void)
11122072Svn83148 {
11132072Svn83148 	struct ldmsvcs_info *lsp;
11142072Svn83148 
11152072Svn83148 	/*
11162072Svn83148 	 * End the poller thread
11172072Svn83148 	 */
11182072Svn83148 	poller_shutdown();
11192072Svn83148 
11202072Svn83148 	if ((lsp = channel_init(NULL)) == NULL)
11212072Svn83148 		return;
11222072Svn83148 
11232072Svn83148 	(void) pthread_mutex_lock(&lsp->mt);
11242072Svn83148 
11252072Svn83148 	lsp->fds_chan.state = CHANNEL_EXIT;
11262072Svn83148 	(void) close(lsp->fds_chan.fd);
11272072Svn83148 
11282072Svn83148 	(void) pthread_mutex_unlock(&lsp->mt);
11292072Svn83148 }
11302072Svn83148 
11312072Svn83148 
11322072Svn83148 static struct ldmsvcs_info *
11332072Svn83148 channel_init(struct ldom_hdl *lhp)
11342072Svn83148 {
11352072Svn83148 	static pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER;
11362072Svn83148 	static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
11372072Svn83148 	static struct ldmsvcs_info *root = NULL;
11382072Svn83148 	static int busy_init = 0;
11392072Svn83148 
11402072Svn83148 	struct timespec twait;
11412072Svn83148 	int expired;
11422072Svn83148 
11432072Svn83148 	(void) pthread_mutex_lock(&mt);
11442072Svn83148 
11452072Svn83148 	while (busy_init == 1)
11462072Svn83148 		(void) pthread_cond_wait(&cv, &mt);
11472072Svn83148 
11482072Svn83148 	if (root != NULL || (lhp == NULL && root == NULL)) {
11492072Svn83148 		(void) pthread_mutex_unlock(&mt);
11502072Svn83148 		return (root);
11512072Svn83148 	}
11522072Svn83148 
11532072Svn83148 	/*
11542072Svn83148 	 * get to this point if we need to open the channel
11552072Svn83148 	 */
11562072Svn83148 	busy_init = 1;
11572072Svn83148 	(void) pthread_mutex_unlock(&mt);
11582072Svn83148 
11592072Svn83148 	root = (struct ldmsvcs_info *)
11604358Srb144127 	    lhp->allocp(sizeof (struct ldmsvcs_info));
11612072Svn83148 	bzero(root, sizeof (struct ldmsvcs_info));
11622072Svn83148 
11632072Svn83148 	root->fds_chan.state = CHANNEL_UNINITIALIZED;
11644358Srb144127 	root->cv_twait = get_smf_int_val(LDM_INIT_TO_PROP_NM,
11654358Srb144127 	    0, LDM_TIMEOUT_CEILING, LDM_INIT_WAIT_TIME);
11662072Svn83148 
11672072Svn83148 	if (pthread_mutex_init(&root->mt, NULL) != 0 ||
11682072Svn83148 	    pthread_cond_init(&root->cv, NULL) != 0) {
11692072Svn83148 		lhp->freep(root, sizeof (struct ldmsvcs_info));
11702072Svn83148 		return (NULL);
11712072Svn83148 	}
11722072Svn83148 
11732072Svn83148 	fds_svc_alloc(lhp, root);
11742072Svn83148 	fds_svc_reset(root, -1);
11752072Svn83148 
11762072Svn83148 	(void) poller_init(root);
11772072Svn83148 
11782072Svn83148 	expired = 0;
11792072Svn83148 	twait.tv_sec = time(NULL) + 10;
11802072Svn83148 	twait.tv_nsec = 0;
11812072Svn83148 
11822072Svn83148 	(void) pthread_mutex_lock(&root->mt);
11832072Svn83148 
11842072Svn83148 	/*
11852072Svn83148 	 * wait for channel to become uninitialized.  this should be quick.
11862072Svn83148 	 */
11872072Svn83148 	while (root->fds_chan.state == CHANNEL_UNINITIALIZED && expired == 0)
11882072Svn83148 		expired = pthread_cond_timedwait(&root->cv, &root->mt, &twait);
11892072Svn83148 
11902072Svn83148 	if (root->fds_chan.state == CHANNEL_UNUSABLE)
11912072Svn83148 		expired = 1;
11922072Svn83148 
11932072Svn83148 	(void) pthread_mutex_unlock(&root->mt);
11942072Svn83148 
11952072Svn83148 	(void) pthread_mutex_lock(&mt);
11962072Svn83148 	busy_init = 0;
11972072Svn83148 	(void) pthread_mutex_unlock(&mt);
11982072Svn83148 	(void) pthread_cond_broadcast(&cv);
11992072Svn83148 
12002072Svn83148 	(void) atexit(channel_fini);
12012072Svn83148 
12022072Svn83148 	if (expired == 0)
12032072Svn83148 		return (root);
12042072Svn83148 	else
12052072Svn83148 		return (NULL);
12062072Svn83148 }
12072072Svn83148 
12082072Svn83148 
12092072Svn83148 static int
12102072Svn83148 sendrecv(struct ldom_hdl *lhp, uint64_t req_num,
12112072Svn83148 	void *msg, size_t msglen, ds_svc_hdl_t *svc_hdl, char *svcname,
12122072Svn83148 	void **resp, size_t *resplen)
12132072Svn83148 {
12142072Svn83148 	struct ldmsvcs_info *lsp;
12152072Svn83148 	fds_svc_t *svc;
12162072Svn83148 	int maxretries, index, i, ier;
12172072Svn83148 
12182072Svn83148 	lsp = lhp->lsinfo;
12192072Svn83148 	i = 0;
12202072Svn83148 	maxretries = 1;
12212072Svn83148 
12222072Svn83148 	do {
12232072Svn83148 		/*
12242072Svn83148 		 * if any of the calls in this loop fail, retry some number
12252072Svn83148 		 * of times before giving up.
12262072Svn83148 		 */
12272072Svn83148 		if ((svc = fds_svc_lookup(lsp, svcname)) == NULL) {
12282072Svn83148 			(void) pthread_mutex_lock(&lsp->mt);
12292072Svn83148 
12302072Svn83148 			if (lsp->fds_chan.state != CHANNEL_READY)
12312072Svn83148 				ier = ETIMEDOUT;	/* channel not ready */
12322072Svn83148 			else
12332072Svn83148 				ier = ENOTSUP;		/* service not ready */
12342072Svn83148 
12352072Svn83148 			(void) pthread_mutex_unlock(&lsp->mt);
12362072Svn83148 
12372072Svn83148 			continue;
12382072Svn83148 		} else {
12392072Svn83148 			ier = 0;
12402072Svn83148 			*svc_hdl = svc->hdl;
12412072Svn83148 		}
12422072Svn83148 
12432072Svn83148 		index = poller_add_pending(lhp, req_num);
12442072Svn83148 
12452072Svn83148 		if ((ier = fds_send(lsp, msg, msglen)) != 0 ||
12462072Svn83148 		    (ier = poller_recv_data(lhp, req_num, index, resp,
12474358Srb144127 		    resplen)) != 0)
12482072Svn83148 			poller_delete_pending(req_num, index);
12492072Svn83148 
12502072Svn83148 	} while (i++ < maxretries && ier != 0);
12512072Svn83148 
12522072Svn83148 	ASSERT(ier == 0 || ier == ETIMEDOUT || ier == ENOTSUP);
12532072Svn83148 
12542072Svn83148 	return (ier);
12552072Svn83148 }
12562072Svn83148 
12572072Svn83148 
12582072Svn83148 /*
12592072Svn83148  * input:
12602072Svn83148  *   msg_type - requested operation: FMA_CPU_REQ_STATUS or FMA_CPU_REQ_OFFLINE
12612072Svn83148  *   cpuid - physical cpu id
12622072Svn83148  *
12632072Svn83148  * normal return values:
12642072Svn83148  *   P_OFFLINE - cpu is offline
12652072Svn83148  *   P_ONLINE - cpu is online
12662072Svn83148  *
12672072Svn83148  * abnormal return values:
12682072Svn83148  *   ETIMEDOUT - LDOM manager is not responding
12692072Svn83148  *   ENOTSUP - LDOM service for cpu offlining/status is not available
12702072Svn83148  *   ENOMSG - got an unexpected response from the LDOM cpu service
12712072Svn83148  */
12722072Svn83148 static int
12732072Svn83148 cpu_request(struct ldom_hdl *lhp, uint32_t msg_type, uint32_t cpuid)
12742072Svn83148 {
12752072Svn83148 	ds_hdr_t *H;
12762072Svn83148 	ds_data_handle_t *D;
12772072Svn83148 	fma_cpu_service_req_t *R;
12782072Svn83148 
12792072Svn83148 	char *svcname = "fma-phys-cpu-service";
12802072Svn83148 	fma_cpu_resp_t *respmsg;
12812072Svn83148 	void *resp;
12822072Svn83148 	size_t resplen, reqmsglen;
12832072Svn83148 	int rc;
12842072Svn83148 
12852072Svn83148 	if (lhp->lsinfo == NULL)
12862072Svn83148 		return (ENOMSG);
12872072Svn83148 
12882072Svn83148 	reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) +
12894358Srb144127 	    sizeof (fma_cpu_service_req_t);
12902072Svn83148 
12912072Svn83148 	H = lhp->allocp(reqmsglen);
12922072Svn83148 	D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
12932072Svn83148 	R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t));
12942072Svn83148 
12952072Svn83148 	H->msg_type = DS_DATA;
12962072Svn83148 	H->payload_len = sizeof (ds_data_handle_t) +
12974358Srb144127 	    sizeof (fma_cpu_service_req_t);
12982072Svn83148 
12992072Svn83148 	R->req_num = fds_svc_req_num();
13002072Svn83148 	R->msg_type = msg_type;
13012072Svn83148 	R->cpu_id = cpuid;
13022072Svn83148 
13032072Svn83148 	if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen,
13044358Srb144127 	    &D->svc_handle, svcname, &resp, &resplen)) != 0) {
13052072Svn83148 		lhp->freep(H, reqmsglen);
13062072Svn83148 		return (rc);
13072072Svn83148 	}
13082072Svn83148 
13092072Svn83148 	lhp->freep(H, reqmsglen);
13102072Svn83148 
13112072Svn83148 	ASSERT(resplen == sizeof (fma_cpu_resp_t));
13122072Svn83148 	respmsg = (fma_cpu_resp_t *)resp;
13132072Svn83148 
13142072Svn83148 	rc = ENOMSG;
13152072Svn83148 	if (respmsg->result == FMA_CPU_RESP_OK) {
13162072Svn83148 		if (respmsg->status == FMA_CPU_STAT_ONLINE)
13172072Svn83148 			rc = P_ONLINE;
13182072Svn83148 		else if (respmsg->status == FMA_CPU_STAT_OFFLINE)
13192072Svn83148 			rc = P_OFFLINE;
13202072Svn83148 	} else {
13212072Svn83148 		if (msg_type == FMA_CPU_REQ_OFFLINE &&
13222072Svn83148 		    respmsg->status == FMA_CPU_STAT_OFFLINE)
13232072Svn83148 			rc = P_OFFLINE;
13242072Svn83148 	}
13252072Svn83148 
13262072Svn83148 	lhp->freep(resp, resplen);
13272072Svn83148 
13282072Svn83148 	return (rc);
13292072Svn83148 }
13302072Svn83148 
13312072Svn83148 
13322072Svn83148 /*
13332072Svn83148  * input:
13342072Svn83148  *   msg_type - requested operation: FMA_MEM_REQ_STATUS or FMA_MEM_REQ_RETIRE
13352072Svn83148  *   pa - starting address of memory page
13362072Svn83148  *   pgsize - memory page size in bytes
13372072Svn83148  *
13382072Svn83148  * normal return values for msg_type == FMA_MEM_REQ_STATUS:
13392072Svn83148  *   0 - page is retired
13402072Svn83148  *   EAGAIN - page is scheduled for retirement
13412072Svn83148  *   EIO - page not scheduled for retirement
13422072Svn83148  *   EINVAL - error
13432072Svn83148  *
13442072Svn83148  * normal return values for msg_type == FMA_MEM_REQ_RETIRE:
13452072Svn83148  *   0 - success in retiring page
13462072Svn83148  *   EIO - page is already retired
13472072Svn83148  *   EAGAIN - page is scheduled for retirement
13482072Svn83148  *   EINVAL - error
13492072Svn83148  *
13502072Svn83148  * abnormal return values (regardless of msg_type)
13512072Svn83148  *   ETIMEDOUT - LDOM manager is not responding
13522072Svn83148  *   ENOTSUP - LDOM service for cpu offlining/status is not available
13532072Svn83148  *   ENOMSG - got an unexpected response from the LDOM cpu service
13542072Svn83148  */
13552072Svn83148 static int
13562072Svn83148 mem_request(struct ldom_hdl *lhp, uint32_t msg_type, uint64_t pa,
13572072Svn83148 	    uint64_t pgsize)
13582072Svn83148 {
13592072Svn83148 	ds_hdr_t *H;
13602072Svn83148 	ds_data_handle_t *D;
13612072Svn83148 	fma_mem_service_req_t *R;
13622072Svn83148 
13632072Svn83148 	char *svcname = "fma-phys-mem-service";
13642072Svn83148 	fma_mem_resp_t *respmsg;
13652072Svn83148 	void *resp;
13662072Svn83148 	size_t resplen, reqmsglen;
13672072Svn83148 	int rc;
13682072Svn83148 
13692072Svn83148 	if (lhp->lsinfo == NULL)
13702072Svn83148 		return (ENOMSG);
13712072Svn83148 
13722072Svn83148 	reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) +
13734358Srb144127 	    sizeof (fma_mem_service_req_t);
13742072Svn83148 
13752072Svn83148 	H = lhp->allocp(reqmsglen);
13762072Svn83148 	bzero(H, reqmsglen);
13772072Svn83148 	D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
13782072Svn83148 	R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t));
13792072Svn83148 
13802072Svn83148 	H->msg_type = DS_DATA;
13812072Svn83148 	H->payload_len = sizeof (ds_data_handle_t) +
13824358Srb144127 	    sizeof (fma_mem_service_req_t);
13832072Svn83148 
13842072Svn83148 	R->req_num = fds_svc_req_num();
13852072Svn83148 	R->msg_type = msg_type;
13862072Svn83148 	R->real_addr = pa;
13872072Svn83148 	R->length = pgsize;
13882072Svn83148 
13892072Svn83148 	if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen,
13904358Srb144127 	    &D->svc_handle, svcname, &resp, &resplen)) != 0) {
13912072Svn83148 		lhp->freep(H, reqmsglen);
13922072Svn83148 		return (rc);
13932072Svn83148 	}
13942072Svn83148 
13952072Svn83148 	lhp->freep(H, reqmsglen);
13962072Svn83148 
13972072Svn83148 	ASSERT(resplen == sizeof (fma_mem_resp_t));
13982072Svn83148 	respmsg = (fma_mem_resp_t *)resp;
13992072Svn83148 
14002072Svn83148 	rc = ENOMSG;
14012072Svn83148 	if (msg_type == FMA_MEM_REQ_STATUS) {
14022072Svn83148 		if (respmsg->result == FMA_MEM_RESP_OK) {
14032072Svn83148 			if (respmsg->status == FMA_MEM_STAT_RETIRED)
14044655Svn83148 				rc = 0;		/* page is retired */
14052072Svn83148 			else if (respmsg->status == FMA_MEM_STAT_NOTRETIRED)
14064655Svn83148 				rc = EIO;	/* page is not scheduled */
14072072Svn83148 		} else if (respmsg->result == FMA_MEM_RESP_FAILURE) {
14084655Svn83148 			if (respmsg->status == FMA_MEM_STAT_NOTRETIRED)
14094655Svn83148 				rc = EAGAIN;	/* page is scheduled */
14104655Svn83148 			else if (respmsg->status == FMA_MEM_STAT_ILLEGAL)
14112072Svn83148 				rc = EINVAL;
14122072Svn83148 		}
14132072Svn83148 	} else if (msg_type == FMA_MEM_REQ_RETIRE) {
14142072Svn83148 		if (respmsg->result == FMA_MEM_RESP_OK) {
14152072Svn83148 			if (respmsg->status == FMA_MEM_STAT_RETIRED)
14164655Svn83148 				rc = 0;		/* is successfully retired */
14172072Svn83148 		} else if (respmsg->result == FMA_MEM_RESP_FAILURE) {
14182072Svn83148 			if (respmsg->status == FMA_MEM_STAT_RETIRED)
14194655Svn83148 				rc = EIO;	/* is already retired */
14204655Svn83148 			else if (respmsg->status == FMA_MEM_STAT_NOTRETIRED)
14214655Svn83148 				rc = EAGAIN;	/* is scheduled to retire */
14222072Svn83148 			else if (respmsg->status == FMA_MEM_STAT_ILLEGAL)
14232072Svn83148 				rc = EINVAL;
14242072Svn83148 		}
14252072Svn83148 	}
14262072Svn83148 
14272072Svn83148 	lhp->freep(resp, resplen);
14282072Svn83148 
14292072Svn83148 	return (rc);
14302072Svn83148 }
14312072Svn83148 
14322072Svn83148 
14332072Svn83148 /*
14342072Svn83148  * APIs
14352072Svn83148  */
14362072Svn83148 int
14372072Svn83148 ldmsvcs_check_channel(void)
14382072Svn83148 {
14392072Svn83148 	struct stat buf;
14402072Svn83148 
14412072Svn83148 	if (stat(FDS_VLDC, &buf) == 0)
14422072Svn83148 		return (0);	/* vldc exists */
14432072Svn83148 	else if (errno == ENOENT || errno == ENOTDIR)
14442072Svn83148 		return (1);	/* vldc does not exist */
14452072Svn83148 	else
14462072Svn83148 		return (-1);	/* miscellaneous error */
14472072Svn83148 }
14482072Svn83148 
14492072Svn83148 
14502072Svn83148 /*ARGSUSED*/
14512072Svn83148 void
14522072Svn83148 ldmsvcs_init(struct ldom_hdl *lhp)
14532072Svn83148 {
14542072Svn83148 	if (ldmsvcs_check_channel() != 0)
14552072Svn83148 		return;
14562072Svn83148 
14572072Svn83148 	lhp->lsinfo = channel_init(lhp);
14582072Svn83148 	poller_add_client();
14592072Svn83148 }
14602072Svn83148 
14612072Svn83148 
14622072Svn83148 /*ARGSUSED*/
14632072Svn83148 void
14642072Svn83148 ldmsvcs_fini(struct ldom_hdl *lhp)
14652072Svn83148 {
14662072Svn83148 	if (ldmsvcs_check_channel() != 0)
14672072Svn83148 		return;
14682072Svn83148 
14692072Svn83148 	poller_remove_client();
14702072Svn83148 }
14712072Svn83148 
14722072Svn83148 
14732072Svn83148 /*ARGSUSED*/
14742072Svn83148 ssize_t
14752072Svn83148 ldmsvcs_get_core_md(struct ldom_hdl *lhp, uint64_t **buf)
14762072Svn83148 {
14772072Svn83148 	ds_hdr_t *H;
14782072Svn83148 	ds_data_handle_t *D;
14792072Svn83148 	fma_req_pri_t *R;
14802072Svn83148 
14812072Svn83148 	char *svcname = "fma-pri-service";
14822072Svn83148 	void *resp;
14832072Svn83148 	size_t resplen, reqmsglen;
14842072Svn83148 	ssize_t buflen;
14852072Svn83148 	int rc;
14862072Svn83148 
14872072Svn83148 	if (lhp->lsinfo == NULL)
14882072Svn83148 		return (-1);
14892072Svn83148 
14902072Svn83148 	reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) +
14914358Srb144127 	    sizeof (fma_req_pri_t);
14922072Svn83148 
14932072Svn83148 	H = lhp->allocp(reqmsglen);
14942072Svn83148 	D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
14952072Svn83148 	R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t));
14962072Svn83148 
14972072Svn83148 	H->msg_type = DS_DATA;
14982072Svn83148 	H->payload_len = sizeof (ds_data_handle_t) +
14994358Srb144127 	    sizeof (fma_req_pri_t);
15002072Svn83148 
15012072Svn83148 	R->req_num = fds_svc_req_num();
15022072Svn83148 
15032072Svn83148 	if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen,
15044358Srb144127 	    &D->svc_handle, svcname, &resp, &resplen)) != 0) {
15052072Svn83148 		lhp->freep(H, reqmsglen);
15062072Svn83148 		errno = rc;
15072072Svn83148 		return (-1);
15082072Svn83148 	}
15092072Svn83148 
15102072Svn83148 	lhp->freep(H, reqmsglen);
15112072Svn83148 
15122072Svn83148 	/*
15132072Svn83148 	 * resp should contain the req_num immediately followed by the PRI
15142072Svn83148 	 * (the latter may or may not be present).  unfortunately, the
15152072Svn83148 	 * current compiler flags cause a warning for the following
15162072Svn83148 	 * definition
15172072Svn83148 	 *
15182072Svn83148 	 * typedef struct {
15192072Svn83148 	 *    uint64_t req_num;
15202072Svn83148 	 *    uint8_t pri[];
15212072Svn83148 	 *  } fma_pri_resp_t;
15222072Svn83148 	 *
15232072Svn83148 	 * so we do not use the struct here.
15242072Svn83148 	 */
15252072Svn83148 	if (resplen <= sizeof (uint64_t)) {
15262072Svn83148 		lhp->freep(resp, resplen);
15272072Svn83148 		if (resplen == sizeof (uint64_t))
15282072Svn83148 			return (0);
15292072Svn83148 		else
15302072Svn83148 			return (-1);
15312072Svn83148 	}
15322072Svn83148 
15332072Svn83148 	buflen = resplen - sizeof (uint64_t);
15342072Svn83148 	*buf = lhp->allocp(buflen);
15352072Svn83148 
15362072Svn83148 	bcopy((void *)((ptrdiff_t)resp + sizeof (uint64_t)), *buf, buflen);
15372072Svn83148 	lhp->freep(resp, resplen);
15382072Svn83148 
15392072Svn83148 	return (buflen);
15402072Svn83148 }
15412072Svn83148 
15422072Svn83148 
15432072Svn83148 /*
15442072Svn83148  * see cpu_request() for a description of return values
15452072Svn83148  */
15462072Svn83148 int
15472072Svn83148 ldmsvcs_cpu_req_status(struct ldom_hdl *lhp, uint32_t cpuid)
15482072Svn83148 {
15492072Svn83148 	return (cpu_request(lhp, FMA_CPU_REQ_STATUS, cpuid));
15502072Svn83148 }
15512072Svn83148 
15522072Svn83148 
15532072Svn83148 int
15542072Svn83148 ldmsvcs_cpu_req_offline(struct ldom_hdl *lhp, uint32_t cpuid)
15552072Svn83148 {
15562072Svn83148 	return (cpu_request(lhp, FMA_CPU_REQ_OFFLINE, cpuid));
15572072Svn83148 }
15582072Svn83148 
15596111Scy152378 int
15606111Scy152378 ldmsvcs_cpu_req_online(struct ldom_hdl *lhp, uint32_t cpuid)
15616111Scy152378 {
15626111Scy152378 	return (cpu_request(lhp, FMA_CPU_REQ_ONLINE, cpuid));
15636111Scy152378 }
15642072Svn83148 
15652072Svn83148 /*
15662072Svn83148  * see mem_request() for a description of return values
15672072Svn83148  */
15682072Svn83148 int
15692072Svn83148 ldmsvcs_mem_req_status(struct ldom_hdl *lhp, uint64_t pa)
15702072Svn83148 {
15712072Svn83148 	return (mem_request(lhp, FMA_MEM_REQ_STATUS, pa, getpagesize()));
15722072Svn83148 }
15732072Svn83148 
15742072Svn83148 int
15752072Svn83148 ldmsvcs_mem_req_retire(struct ldom_hdl *lhp, uint64_t pa)
15762072Svn83148 {
15772072Svn83148 	return (mem_request(lhp, FMA_MEM_REQ_RETIRE, pa, getpagesize()));
15782072Svn83148 }
15792072Svn83148 
15806111Scy152378 int
15816111Scy152378 ldmsvcs_mem_req_unretire(struct ldom_hdl *lhp, uint64_t pa)
15826111Scy152378 {
15836111Scy152378 	return (mem_request(lhp, FMA_MEM_REQ_RESURRECT, pa, getpagesize()));
15846111Scy152378 }
15856111Scy152378 
15862072Svn83148 /* end file */
1587