xref: /titanic_51/usr/src/lib/fm/libldom/sparc/ldmsvcs_utils.c (revision 1bf5e2ae883107708d4e1651562a348519be0e6a)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <strings.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <time.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <errno.h>
35 #include <assert.h>
36 #include <umem.h>
37 #include <alloca.h>
38 #include <sys/processor.h>
39 #include <poll.h>
40 #include <pthread.h>
41 #include <values.h>
42 #include <libscf.h>
43 
44 #include "ldmsvcs_utils.h"
45 
46 #define	ASSERT(cnd) \
47 	((void) ((cnd) || ((void) fprintf(stderr, \
48 		"assertion failure in %s:%d: %s\n", \
49 		__FILE__, __LINE__, #cnd), 0)))
50 
51 #define	FDS_VLDC \
52 	"/devices/virtual-devices@100/channel-devices@200/" \
53 	"/virtual-channel-client@1:ldmfma"
54 
55 /* allow timeouts in sec that are nearly forever but small enough for an int */
56 #define	LDM_TIMEOUT_CEILING	(MAXINT / 2)
57 
58 #define	MIN(x, y)	((x) < (y) ? (x) : (y))
59 
60 /*
61  * functions in this file are for version 1.0 of FMA domain services
62  */
63 static ds_ver_t ds_vers[] = {
64 	{ 1, 0 }
65 };
66 
67 #define	DS_NUM_VER	(sizeof (ds_vers) / sizeof (ds_ver_t))
68 
69 /*
70  * information for each channel
71  */
72 struct ldmsvcs_info {
73 	pthread_mutex_t mt;
74 	pthread_cond_t cv;
75 	fds_channel_t fds_chan;
76 	fds_reg_svcs_t fmas_svcs;
77 	int cv_twait;
78 };
79 
80 /*
81  * struct listdata_s and struct poller_s are used to maintain the state of
82  * the poller thread.  this thread is used to manage incoming messages and
83  * pass those messages onto the correct requesting thread.  see the "poller
84  * functions" section for more details.
85  */
86 struct listdata_s {
87 	enum {
88 		UNUSED,
89 		PENDING,
90 		ARRIVED
91 	} status;
92 	uint64_t req_num;
93 	int fd;
94 	size_t datalen;
95 };
96 
97 static struct poller_s {
98 	pthread_mutex_t mt;
99 	pthread_cond_t cv;
100 	pthread_t polling_tid;
101 	int doreset;
102 	int doexit;
103 	int nclients;
104 	struct listdata_s **list;
105 	int list_len;
106 	int pending_count;
107 } pollbase = {
108 	PTHREAD_MUTEX_INITIALIZER,
109 	PTHREAD_COND_INITIALIZER,
110 	0,
111 	1,
112 	0,
113 	0,
114 	NULL,
115 	0,
116 	0
117 };
118 
119 
120 static struct ldmsvcs_info *channel_init(struct ldom_hdl *lhp);
121 static int channel_openreset(struct ldmsvcs_info *lsp);
122 static int read_msg(struct ldmsvcs_info *lsp);
123 
124 
125 static int
126 get_smf_int_val(char *prop_nm, int min, int max, int default_val)
127 {
128 	scf_simple_prop_t	*prop;		/* SMF property */
129 	int64_t			*valp;		/* prop value ptr */
130 	int64_t			val;		/* prop value to return */
131 
132 	val = default_val;
133 	if ((prop = scf_simple_prop_get(NULL, LDM_SVC_NM, LDM_PROP_GROUP_NM,
134 	    prop_nm)) != NULL) {
135 		if ((valp = scf_simple_prop_next_integer(prop)) != NULL) {
136 			val = *valp;
137 			if (val < min)
138 				val = min;
139 			else if (val > max)
140 				val = max;
141 		}
142 		scf_simple_prop_free(prop);
143 	}
144 	return ((int)val);
145 }
146 
147 static void
148 channel_close(struct ldmsvcs_info *lsp)
149 {
150 	(void) pthread_mutex_lock(&lsp->mt);
151 
152 	if (lsp->fds_chan.state == CHANNEL_OPEN ||
153 	    lsp->fds_chan.state == CHANNEL_READY) {
154 		(void) close(lsp->fds_chan.fd);
155 		lsp->cv_twait = get_smf_int_val(LDM_INIT_TO_PROP_NM,
156 		    0, LDM_TIMEOUT_CEILING, LDM_INIT_WAIT_TIME);
157 		lsp->fds_chan.state = CHANNEL_CLOSED;
158 	}
159 
160 	(void) pthread_mutex_unlock(&lsp->mt);
161 }
162 
163 /*
164  * read size bytes of data from a streaming fd into buf
165  */
166 static int
167 read_stream(int fd, void *buf, size_t size)
168 {
169 	pollfd_t pollfd;
170 	ssize_t rv;
171 	size_t data_left;
172 	ptrdiff_t currentp;
173 
174 	pollfd.events = POLLIN;
175 	pollfd.revents = 0;
176 	pollfd.fd = fd;
177 
178 	currentp = (ptrdiff_t)buf;
179 	data_left = size;
180 
181 	/*
182 	 * data may come in bits and pieces
183 	 */
184 	do {
185 		if ((rv = read(fd, (void *)currentp, data_left)) < 0) {
186 			if (errno == EAGAIN && poll(&pollfd, 1, -1) > 0)
187 				continue;	/* retry */
188 			else
189 				return (1);
190 		}
191 
192 		data_left -= rv;
193 		currentp += rv;
194 	} while (data_left > 0);
195 
196 	return (0);
197 }
198 
199 
200 /*
201  * poller functions
202  *
203  * at init time, a thread is created for the purpose of monitoring incoming
204  * messages and doing one of the following:
205  *
206  * 1. doing the initial handshake and version negotiation
207  *
208  * 2. handing incoming data off to the requesting thread (which is an fmd
209  * module or scheme thread)
210  */
211 static int
212 poller_handle_data(int fd, size_t payloadsize)
213 {
214 	uint64_t *req_num;
215 	void *pr;
216 	size_t prlen;
217 	int i;
218 
219 	prlen = sizeof (ds_data_handle_t) + sizeof (uint64_t);
220 
221 	if (payloadsize < prlen)
222 		return (1);
223 
224 	pr = alloca(prlen);
225 
226 	if (read_stream(fd, pr, prlen) != 0)
227 		return (1);
228 
229 	req_num = (uint64_t *)((ptrdiff_t)pr + sizeof (ds_data_handle_t));
230 
231 	(void) pthread_mutex_lock(&pollbase.mt);
232 
233 	for (i = 0; i < pollbase.list_len; i++) {
234 		if (pollbase.list[i]->req_num == *req_num) {
235 			ASSERT(pollbase.list[i]->status == PENDING);
236 
237 			pollbase.list[i]->status = ARRIVED;
238 			pollbase.list[i]->fd = fd;
239 			pollbase.list[i]->datalen = payloadsize - prlen;
240 
241 			pollbase.pending_count--;
242 			(void) pthread_cond_broadcast(&pollbase.cv);
243 			break;
244 		}
245 	}
246 
247 	/*
248 	 * now wait for receiving thread to read in the data
249 	 */
250 	if (i < pollbase.list_len) {
251 		while (pollbase.list[i]->status == ARRIVED)
252 			(void) pthread_cond_wait(&pollbase.cv, &pollbase.mt);
253 	}
254 
255 	(void) pthread_mutex_unlock(&pollbase.mt);
256 
257 	return (0);
258 }
259 
260 
261 /*
262  * note that this function is meant to handle only DS_DATA messages
263  */
264 static int
265 poller_recv_data(struct ldom_hdl *lhp, uint64_t req_num, int index,
266 		void **resp, size_t *resplen)
267 {
268 	struct timespec twait;
269 	int ier;
270 
271 	ier = 0;
272 	twait.tv_sec = time(NULL) + lhp->lsinfo->cv_twait;
273 	twait.tv_nsec = 0;
274 
275 	(void) pthread_mutex_lock(&pollbase.mt);
276 
277 	ASSERT(pollbase.list[index]->req_num == req_num);
278 
279 	while (pollbase.list[index]->status == PENDING &&
280 	    pollbase.doreset == 0 && ier == 0)
281 		ier = pthread_cond_timedwait(&pollbase.cv, &pollbase.mt,
282 		    &twait);
283 
284 	if (ier == 0) {
285 		if (pollbase.doreset == 0) {
286 			ASSERT(pollbase.list[index]->status == ARRIVED);
287 
288 			/*
289 			 * need to add req_num to beginning of resp
290 			 */
291 			*resplen = pollbase.list[index]->datalen +
292 			    sizeof (uint64_t);
293 			*resp = lhp->allocp(*resplen);
294 			*((uint64_t *)*resp) = req_num;
295 
296 			if (read_stream(pollbase.list[index]->fd,
297 			    (void *)((ptrdiff_t)*resp + sizeof (uint64_t)),
298 			    *resplen - sizeof (uint64_t)) != 0)
299 				ier = ETIMEDOUT;
300 
301 			pollbase.list[index]->status = UNUSED;
302 			pollbase.list[index]->req_num = 0;
303 			(void) pthread_cond_broadcast(&pollbase.cv);
304 		} else {
305 			if (--(pollbase.pending_count) == 0)
306 				(void) pthread_cond_broadcast(&pollbase.cv);
307 		}
308 	}
309 
310 	(void) pthread_mutex_unlock(&pollbase.mt);
311 
312 	ASSERT(ier == 0 || ier == ETIMEDOUT);
313 
314 	return (ier);
315 }
316 
317 
318 static void
319 poller_add_client(void)
320 {
321 	(void) pthread_mutex_lock(&pollbase.mt);
322 	pollbase.nclients++;
323 	(void) pthread_mutex_unlock(&pollbase.mt);
324 }
325 
326 
327 static void
328 poller_remove_client(void)
329 {
330 	(void) pthread_mutex_lock(&pollbase.mt);
331 	pollbase.nclients--;
332 	ASSERT(pollbase.nclients >= 0);
333 	(void) pthread_mutex_unlock(&pollbase.mt);
334 }
335 
336 
337 static int
338 poller_add_pending(struct ldom_hdl *lhp, uint64_t req_num)
339 {
340 	int newlen, index, i, j;
341 
342 	(void) pthread_mutex_lock(&pollbase.mt);
343 	pollbase.pending_count++;
344 
345 	for (j = 0, index = -1; j < 2 && index == -1; j++) {
346 		for (i = 0; i < pollbase.list_len; i++) {
347 			if (pollbase.list[i]->status == UNUSED) {
348 				pollbase.list[i]->status = PENDING;
349 				pollbase.list[i]->req_num = req_num;
350 				pollbase.list[i]->datalen = 0;
351 				index = i;
352 				break;
353 			}
354 		}
355 
356 		if (index == -1) {
357 			struct listdata_s **newlist, **oldlist;
358 
359 			/*
360 			 * get to this point if list is not long enough.
361 			 * check for a runaway list.  since requests are
362 			 * synchronous (clients send a request and need to
363 			 * wait for the result before returning) the size
364 			 * of the list cannot be much more than the number
365 			 * of clients.
366 			 */
367 			ASSERT(pollbase.list_len < pollbase.nclients + 1);
368 
369 			newlen = pollbase.list_len + 5;
370 			newlist = lhp->allocp(newlen *
371 			    sizeof (struct listdata_s));
372 
373 			for (i = 0; i < pollbase.list_len; i++)
374 				newlist[i] = pollbase.list[i];
375 
376 			oldlist = pollbase.list;
377 			pollbase.list = newlist;
378 			lhp->freep(oldlist, pollbase.list_len *
379 			    sizeof (struct listdata_s));
380 
381 			for (i = pollbase.list_len; i < newlen; i++) {
382 				pollbase.list[i] =
383 				    lhp->allocp(sizeof (struct listdata_s));
384 				pollbase.list[i]->status = UNUSED;
385 			}
386 
387 			pollbase.list_len = newlen;
388 		}
389 	}
390 
391 	(void) pthread_mutex_unlock(&pollbase.mt);
392 	ASSERT(index != -1);
393 
394 	return (index);
395 }
396 
397 
398 static void
399 poller_delete_pending(uint64_t req_num, int index)
400 {
401 	(void) pthread_mutex_lock(&pollbase.mt);
402 
403 	ASSERT(pollbase.list[index]->req_num == req_num);
404 	pollbase.list[index]->status = UNUSED;
405 
406 	if (--(pollbase.pending_count) == 0 && pollbase.doreset == 1)
407 		(void) pthread_cond_broadcast(&pollbase.cv);
408 
409 	(void) pthread_mutex_unlock(&pollbase.mt);
410 }
411 
412 
413 static void
414 poller_shutdown(void)
415 {
416 	(void) pthread_mutex_lock(&pollbase.mt);
417 
418 	pollbase.doexit = 1;
419 
420 	(void) pthread_mutex_unlock(&pollbase.mt);
421 }
422 
423 
424 /*
425  * perform the polling of incoming messages.  manage any resets (usually
426  * due to one end of the connection being closed) as well as exit
427  * conditions.
428  */
429 static void *
430 poller_loop(void *arg)
431 {
432 	struct ldmsvcs_info *lsp;
433 	pollfd_t pollfd;
434 	int ier;
435 
436 	lsp = (struct ldmsvcs_info *)arg;
437 
438 	for (;;) {
439 		(void) pthread_mutex_lock(&pollbase.mt);
440 
441 		if (pollbase.doexit) {
442 			(void) pthread_mutex_unlock(&pollbase.mt);
443 			break;
444 		}
445 
446 		if (pollbase.doreset) {
447 			int i;
448 
449 			while (pollbase.pending_count > 0)
450 				(void) pthread_cond_wait(&pollbase.cv,
451 				    &pollbase.mt);
452 
453 			ASSERT(pollbase.pending_count == 0);
454 			for (i = 0; i < pollbase.list_len; i++)
455 				pollbase.list[i]->status = UNUSED;
456 
457 			pollbase.doreset = 0;
458 		}
459 		(void) pthread_mutex_unlock(&pollbase.mt);
460 
461 		if ((ier = channel_openreset(lsp)) == 1) {
462 			continue;
463 		} else if (ier == 2) {
464 			/*
465 			 * start exit preparations
466 			 */
467 			poller_shutdown();
468 			continue;
469 		}
470 
471 		pollfd.events = POLLIN;
472 		pollfd.revents = 0;
473 		pollfd.fd = lsp->fds_chan.fd;
474 
475 		if (poll(&pollfd, 1, -1) <= 0 || read_msg(lsp) != 0) {
476 			/*
477 			 * read error and/or fd got closed
478 			 */
479 			(void) pthread_mutex_lock(&pollbase.mt);
480 			pollbase.doreset = 1;
481 			(void) pthread_mutex_unlock(&pollbase.mt);
482 
483 			channel_close(lsp);
484 		}
485 	}
486 
487 	return (NULL);
488 }
489 
490 
491 /*
492  * create the polling thread
493  */
494 static int
495 poller_init(struct ldmsvcs_info *lsp)
496 {
497 	int rc = 0;
498 
499 	(void) pthread_mutex_lock(&pollbase.mt);
500 
501 	if (pollbase.polling_tid == 0) {
502 		pthread_attr_t attr;
503 
504 		/*
505 		 * create polling thread for receiving messages
506 		 */
507 		(void) pthread_attr_init(&attr);
508 		(void) pthread_attr_setdetachstate(&attr,
509 		    PTHREAD_CREATE_DETACHED);
510 
511 		if (pthread_create(&pollbase.polling_tid, &attr,
512 		    poller_loop, lsp) != 0)
513 			rc = 1;
514 
515 		(void) pthread_attr_destroy(&attr);
516 	}
517 
518 	(void) pthread_mutex_unlock(&pollbase.mt);
519 
520 	return (rc);
521 }
522 
523 
524 /*
525  * utilities for message handlers
526  */
527 static int
528 fds_send(struct ldmsvcs_info *lsp, void *msg, size_t msglen)
529 {
530 	static pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER;
531 
532 	(void) pthread_mutex_lock(&mt);
533 
534 	if (write(lsp->fds_chan.fd, msg, msglen) != msglen) {
535 		channel_close(lsp);
536 		(void) pthread_mutex_unlock(&mt);
537 		return (ETIMEDOUT);
538 	}
539 
540 	(void) pthread_mutex_unlock(&mt);
541 	return (0);
542 }
543 
544 
545 /*
546  * Find the max and min version supported
547  */
548 static void
549 fds_min_max_versions(uint16_t *min_major, uint16_t *max_major)
550 {
551 	int i;
552 
553 	*min_major = ds_vers[0].major;
554 	*max_major = *min_major;
555 
556 	for (i = 1; i < DS_NUM_VER; i++) {
557 		if (ds_vers[i].major < *min_major)
558 			*min_major = ds_vers[i].major;
559 
560 		if (ds_vers[i].major > *max_major)
561 			*max_major = ds_vers[i].major;
562 	}
563 }
564 
565 /*
566  * check whether the major and minor numbers requested by remote ds client
567  * can be satisfied.  if the requested major is supported, true is
568  * returned, and the agreed minor is returned in new_minor.  if the
569  * requested major is not supported, the routine returns false, and the
570  * closest major is returned in *new_major, upon which the ds client should
571  * renegotiate.  the closest major is the just lower that the requested
572  * major number.
573  */
574 static boolean_t
575 fds_negotiate_version(uint16_t req_major, uint16_t *new_majorp,
576     uint16_t *new_minorp)
577 {
578 	int i = 0;
579 	uint16_t major, lower_major;
580 	uint16_t min_major, max_major;
581 	boolean_t found_match = B_FALSE;
582 
583 	fds_min_max_versions(&min_major, &max_major);
584 
585 	/*
586 	 * if the minimum version supported is greater than the version
587 	 * requested, return the lowest version supported
588 	 */
589 	if (min_major > req_major) {
590 		*new_majorp = min_major;
591 		return (B_FALSE);
592 	}
593 
594 	/*
595 	 * if the largest version supported is lower than the version
596 	 * requested, return the largest version supported
597 	 */
598 	if (max_major < req_major) {
599 		*new_majorp = max_major;
600 		return (B_FALSE);
601 	}
602 
603 	/*
604 	 * now we know that the requested version lies between the min and
605 	 * max versions supported.  check if the requested major can be
606 	 * found in supported versions.
607 	 */
608 	lower_major = min_major;
609 	for (i = 0; i < DS_NUM_VER; i++) {
610 		major = ds_vers[i].major;
611 		if (major == req_major) {
612 			found_match = B_TRUE;
613 			*new_minorp = ds_vers[i].minor;
614 			*new_majorp = major;
615 			break;
616 		} else if ((major < req_major) && (major > lower_major))
617 			lower_major = major;
618 	}
619 
620 	/*
621 	 * If  no match is found, return the closest available number
622 	 */
623 	if (!found_match)
624 		*new_majorp = lower_major;
625 
626 	return (found_match);
627 }
628 
629 
630 /*
631  * return 0 if service is added; 1 if service is a duplicate
632  */
633 static int
634 fds_svc_add(struct ldmsvcs_info *lsp, ds_reg_req_t *req, int minor)
635 {
636 	fds_svc_t *svc;
637 	int i, rc;
638 
639 	svc = NULL;
640 	for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) {
641 		if (strcmp(lsp->fmas_svcs.tbl[i]->name, req->svc_id) == 0) {
642 			svc = lsp->fmas_svcs.tbl[i];
643 			break;
644 		}
645 	}
646 
647 	if (svc == NULL)
648 		return (0);	/* we don't need this service */
649 
650 	(void) pthread_mutex_lock(&lsp->fmas_svcs.mt);
651 
652 	/*
653 	 * duplicate registration is OK --- we retain the previous entry
654 	 * (which has not been unregistered anyway)
655 	 */
656 	if (svc->state == DS_SVC_ACTIVE) {
657 		rc = 1;
658 	} else {
659 		svc->state = DS_SVC_ACTIVE;
660 		svc->hdl = req->svc_handle;
661 		svc->ver.major = req->major_vers;
662 		svc->ver.minor = minor;
663 
664 		rc = 0;
665 		(void) pthread_cond_broadcast(&lsp->fmas_svcs.cv);
666 	}
667 
668 	(void) pthread_mutex_unlock(&lsp->fmas_svcs.mt);
669 
670 	return (rc);
671 }
672 
673 
674 static void
675 fds_svc_reset(struct ldmsvcs_info *lsp, int index)
676 {
677 	int i, start, end;
678 
679 	if (index >= 0) {
680 		start = index;
681 		end = index + 1;
682 	} else {
683 		start = 0;
684 		end = lsp->fmas_svcs.nsvcs;
685 	}
686 
687 	(void) pthread_mutex_lock(&lsp->fmas_svcs.mt);
688 
689 	for (i = start; i < end; i++) {
690 		lsp->fmas_svcs.tbl[i]->hdl = 0;
691 		lsp->fmas_svcs.tbl[i]->state = DS_SVC_INVAL;
692 		lsp->fmas_svcs.tbl[i]->ver.major =
693 		    ds_vers[DS_NUM_VER - 1].major;
694 		lsp->fmas_svcs.tbl[i]->ver.minor =
695 		    ds_vers[DS_NUM_VER - 1].minor;
696 	}
697 
698 	(void) pthread_mutex_unlock(&lsp->fmas_svcs.mt);
699 }
700 
701 
702 static int
703 fds_svc_remove(struct ldmsvcs_info *lsp, ds_svc_hdl_t svc_handle)
704 {
705 	int i;
706 
707 	for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) {
708 		if (lsp->fmas_svcs.tbl[i]->hdl == svc_handle) {
709 			fds_svc_reset(lsp, i);
710 			return (0);
711 		}
712 	}
713 
714 	return (1);
715 }
716 
717 
718 /*
719  * message handlers
720  */
721 /*ARGSUSED*/
722 static void
723 ds_handle_msg_noop(struct ldmsvcs_info *lsp, void *buf, size_t len)
724 {
725 }
726 
727 static void
728 ds_handle_init_req(struct ldmsvcs_info *lsp, void *buf, size_t len)
729 {
730 	ds_init_req_t *req;
731 	uint16_t new_major, new_minor;
732 	size_t msglen;
733 
734 	req = (ds_init_req_t *)buf;
735 
736 	/* sanity check the incoming message */
737 	if (len != sizeof (ds_init_req_t)) {
738 		channel_close(lsp);
739 		return;
740 	}
741 
742 	/*
743 	 * Check version info. ACK only if the major numbers exactly
744 	 * match. The service entity can retry with a new minor
745 	 * based on the response sent as part of the NACK.
746 	 */
747 	if (fds_negotiate_version(req->major_vers, &new_major, &new_minor)) {
748 		ds_hdr_t *H;
749 		ds_init_ack_t *R;
750 
751 		msglen = sizeof (ds_hdr_t) + sizeof (ds_init_ack_t);
752 		H = alloca(msglen);
753 		R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
754 
755 		H->msg_type = DS_INIT_ACK;
756 		H->payload_len = sizeof (ds_init_ack_t);
757 		R->minor_vers = MIN(new_minor, req->minor_vers);
758 
759 		if (fds_send(lsp, H, msglen) != 0)
760 			return;
761 
762 		(void) pthread_mutex_lock(&lsp->mt);
763 		ASSERT(lsp->fds_chan.state == CHANNEL_OPEN);
764 		lsp->fds_chan.state = CHANNEL_READY;
765 
766 		/*
767 		 * Now the channel is ready after the handshake completes.
768 		 * Reset the timeout to a smaller value for receiving messages
769 		 * from the domain services.
770 		 */
771 		lsp->cv_twait = get_smf_int_val(LDM_RUNNING_TO_PROP_NM,
772 		    0, LDM_TIMEOUT_CEILING, LDM_RUNNING_WAIT_TIME);
773 
774 		(void) pthread_mutex_unlock(&lsp->mt);
775 	} else {
776 		ds_hdr_t *H;
777 		ds_init_nack_t *R;
778 
779 		msglen = sizeof (ds_hdr_t) + sizeof (ds_init_nack_t);
780 		H = alloca(msglen);
781 		R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
782 
783 		H->msg_type = DS_INIT_NACK;
784 		H->payload_len = sizeof (ds_init_nack_t);
785 		R->major_vers = new_major;
786 
787 		(void) fds_send(lsp, H, msglen);
788 		/*
789 		 * do not update state; remote end may attempt to initiate
790 		 * connection with a different version
791 		 */
792 	}
793 }
794 
795 
796 /*ARGSUSED*/
797 static void
798 ds_handle_reg_req(struct ldmsvcs_info *lsp, void *buf, size_t len)
799 {
800 	ds_reg_req_t *req;
801 	char *msg;
802 	uint16_t new_major, new_minor;
803 	size_t msglen;
804 	int dup_svcreg = 0;
805 
806 	req = (ds_reg_req_t *)buf;
807 	msg = (char *)req->svc_id;
808 
809 	/*
810 	 * Service must be NULL terminated
811 	 */
812 	if (req->svc_id == NULL || strlen(req->svc_id) == 0 ||
813 	    msg[strlen(req->svc_id)] != '\0') {
814 		channel_close(lsp);
815 		return;
816 	}
817 
818 	if (fds_negotiate_version(req->major_vers, &new_major, &new_minor) &&
819 	    (dup_svcreg = fds_svc_add(lsp, req,
820 	    MIN(new_minor, req->minor_vers))) == 0) {
821 
822 		/*
823 		 * Check version info. ACK only if the major numbers
824 		 * exactly match. The service entity can retry with a new
825 		 * minor based on the response sent as part of the NACK.
826 		 */
827 		ds_hdr_t *H;
828 		ds_reg_ack_t *R;
829 
830 		msglen = sizeof (ds_hdr_t) + sizeof (ds_reg_ack_t);
831 		H = alloca(msglen);
832 		bzero(H, msglen);
833 		R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
834 
835 		H->msg_type = DS_REG_ACK;
836 		H->payload_len = sizeof (ds_reg_ack_t);
837 		R->svc_handle = req->svc_handle;
838 		R->minor_vers = MIN(new_minor, req->minor_vers);
839 
840 		(void) fds_send(lsp, H, msglen);
841 	} else {
842 		ds_hdr_t *H;
843 		ds_reg_nack_t *R;
844 
845 		msglen = sizeof (ds_hdr_t) + sizeof (ds_reg_nack_t);
846 		H = alloca(msglen);
847 		bzero(H, msglen);
848 		R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
849 
850 		H->msg_type = DS_REG_NACK;
851 		H->payload_len = sizeof (ds_reg_nack_t);
852 		R->svc_handle = req->svc_handle;
853 		R->major_vers = new_major;
854 
855 		if (dup_svcreg)
856 			R->result = DS_REG_DUP;
857 		else
858 			R->result = DS_REG_VER_NACK;
859 
860 		(void) fds_send(lsp, H, msglen);
861 	}
862 }
863 
864 
865 /*ARGSUSED*/
866 static void
867 ds_handle_unreg(struct ldmsvcs_info *lsp, void *buf, size_t len)
868 {
869 	ds_unreg_req_t *req;
870 	size_t msglen;
871 
872 	req = (ds_unreg_req_t *)buf;
873 
874 	if (fds_svc_remove(lsp, req->svc_handle) == 0) {
875 		ds_hdr_t *H;
876 		ds_unreg_ack_t *R;
877 
878 		msglen = sizeof (ds_hdr_t) + sizeof (ds_unreg_ack_t);
879 		H = alloca(msglen);
880 		R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
881 
882 		H->msg_type = DS_REG_ACK;
883 		H->payload_len = sizeof (ds_unreg_ack_t);
884 		R->svc_handle = req->svc_handle;
885 
886 		(void) fds_send(lsp, H, msglen);
887 	} else {
888 		ds_hdr_t *H;
889 		ds_unreg_nack_t *R;
890 
891 		msglen = sizeof (ds_hdr_t) + sizeof (ds_unreg_nack_t);
892 		H = alloca(msglen);
893 		R = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
894 
895 		H->msg_type = DS_REG_NACK;
896 		H->payload_len = sizeof (ds_unreg_nack_t);
897 		R->svc_handle = req->svc_handle;
898 
899 		(void) fds_send(lsp, H, msglen);
900 	}
901 }
902 
903 
904 /*
905  * Message handler lookup table (v1.0 only for now) Future
906  * versions can add their own lookup table.
907  */
908 typedef void (*ds_msg_handler_t)(struct ldmsvcs_info *lsp,
909 				void *buf, size_t len);
910 
911 static const ds_msg_handler_t ds_msg_handlers[] = {
912 	ds_handle_init_req,		/* DS_INIT_REQ */
913 	ds_handle_msg_noop,		/* DS_INIT_ACK */
914 	ds_handle_msg_noop,		/* DS_INIT_NACK */
915 	ds_handle_reg_req,		/* DS_REG_REQ */
916 	ds_handle_msg_noop,		/* DS_REG_ACK */
917 	ds_handle_msg_noop,		/* DS_REG_NACK */
918 	ds_handle_unreg,		/* DS_UNREG */
919 	ds_handle_msg_noop,		/* DS_UNREG_ACK */
920 	ds_handle_msg_noop,		/* DS_UNREG_NACK */
921 	ds_handle_msg_noop,		/* DS_DATA */
922 	ds_handle_msg_noop		/* DS_NACK */
923 };
924 
925 
926 /*
927  * message and service internal functions
928  */
929 static void
930 fds_svc_alloc(struct ldom_hdl *lhp, struct ldmsvcs_info *lsp)
931 {
932 	int i;
933 	char *name[] = { "fma-phys-cpu-service", "fma-phys-mem-service",
934 			"fma-pri-service", NULL };
935 
936 	(void) pthread_mutex_init(&lsp->fmas_svcs.mt, NULL);
937 	(void) pthread_cond_init(&lsp->fmas_svcs.cv, NULL);
938 
939 	for (lsp->fmas_svcs.nsvcs = 0; name[lsp->fmas_svcs.nsvcs] != NULL;
940 	    lsp->fmas_svcs.nsvcs++)
941 		;
942 
943 	lsp->fmas_svcs.tbl = (fds_svc_t **)lhp->allocp(sizeof (fds_svc_t *) *
944 	    lsp->fmas_svcs.nsvcs);
945 
946 	for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) {
947 		lsp->fmas_svcs.tbl[i] =
948 		    (fds_svc_t *)lhp->allocp(sizeof (fds_svc_t));
949 		bzero(lsp->fmas_svcs.tbl[i], sizeof (fds_svc_t));
950 		lsp->fmas_svcs.tbl[i]->name = name[i];
951 	}
952 }
953 
954 
955 static fds_svc_t *
956 fds_svc_lookup(struct ldmsvcs_info *lsp, char *name)
957 {
958 	struct timespec twait;
959 	fds_svc_t *svc;
960 	int i, ier;
961 
962 	if (pthread_mutex_lock(&lsp->fmas_svcs.mt) == EINVAL)
963 		return (NULL);	/* uninitialized or destroyed mutex */
964 
965 	svc = NULL;
966 	for (i = 0; i < lsp->fmas_svcs.nsvcs; i++) {
967 		if (strcmp(lsp->fmas_svcs.tbl[i]->name, name) == 0) {
968 			svc = lsp->fmas_svcs.tbl[i];
969 			break;
970 		}
971 	}
972 
973 	ASSERT(svc != NULL);
974 
975 	ier = 0;
976 	twait.tv_sec = time(NULL) + lsp->cv_twait;
977 	twait.tv_nsec = 0;
978 
979 	while (svc->state != DS_SVC_ACTIVE && ier == 0 &&
980 	    lsp->fds_chan.state != CHANNEL_UNUSABLE)
981 		ier = pthread_cond_timedwait(&lsp->fmas_svcs.cv,
982 		    &lsp->fmas_svcs.mt, &twait);
983 
984 	(void) pthread_mutex_unlock(&lsp->fmas_svcs.mt);
985 
986 	if (ier == 0)
987 		return (svc);
988 	else
989 		return (NULL);
990 }
991 
992 
993 static uint64_t
994 fds_svc_req_num(void)
995 {
996 	static uint64_t req_num = 1;
997 
998 	return (req_num++);
999 }
1000 
1001 
1002 /*
1003  * return 0 if successful, 1 if otherwise
1004  */
1005 static int
1006 read_msg(struct ldmsvcs_info *lsp)
1007 {
1008 	ds_hdr_t header;
1009 	void *msg_buf;
1010 
1011 	/*
1012 	 * read the header
1013 	 */
1014 	if (read_stream(lsp->fds_chan.fd, &header, sizeof (ds_hdr_t)) != 0)
1015 		return (1);
1016 
1017 	if (header.msg_type >=
1018 	    sizeof (ds_msg_handlers) / sizeof (ds_msg_handler_t))
1019 		return (1);
1020 
1021 	/*
1022 	 * handle data as a special case
1023 	 */
1024 	if (header.msg_type == 9)
1025 		return (poller_handle_data(lsp->fds_chan.fd,
1026 		    header.payload_len));
1027 
1028 	/*
1029 	 * all other types of messages should be small
1030 	 */
1031 	ASSERT(header.payload_len < 1024);
1032 	msg_buf = alloca(header.payload_len);
1033 
1034 	/*
1035 	 * read the payload
1036 	 */
1037 	if (read_stream(lsp->fds_chan.fd, msg_buf, header.payload_len) != 0)
1038 		return (1);
1039 
1040 	(*ds_msg_handlers[header.msg_type])(lsp, msg_buf, header.payload_len);
1041 
1042 	return (0);
1043 }
1044 
1045 
1046 /*
1047  * return values:
1048  *  0 - success
1049  *  1 - problem with opening the channel
1050  *  2 - channed not opened; request to exit has been detected
1051  */
1052 static int
1053 channel_openreset(struct ldmsvcs_info *lsp)
1054 {
1055 	int ier;
1056 
1057 	ier = pthread_mutex_lock(&lsp->mt);
1058 
1059 	if (ier == EINVAL || lsp->fds_chan.state == CHANNEL_EXIT ||
1060 	    lsp->fds_chan.state == CHANNEL_UNUSABLE) {
1061 		(void) pthread_mutex_unlock(&lsp->mt);
1062 		return (2);
1063 	}
1064 
1065 	if (lsp->fds_chan.state == CHANNEL_UNINITIALIZED ||
1066 	    lsp->fds_chan.state == CHANNEL_CLOSED) {
1067 		(void) pthread_cond_broadcast(&lsp->cv);
1068 
1069 		if ((lsp->fds_chan.fd = open(FDS_VLDC, O_RDWR)) < 0) {
1070 			lsp->fds_chan.state = CHANNEL_UNUSABLE;
1071 			lsp->cv_twait = get_smf_int_val(LDM_RUNNING_TO_PROP_NM,
1072 			    0, LDM_TIMEOUT_CEILING, LDM_RUNNING_WAIT_TIME);
1073 			(void) pthread_mutex_unlock(&lsp->mt);
1074 			(void) pthread_cond_broadcast(&lsp->fmas_svcs.cv);
1075 
1076 			return (2);
1077 		} else {
1078 			vldc_opt_op_t op;
1079 
1080 			op.op_sel = VLDC_OP_SET;
1081 			op.opt_sel = VLDC_OPT_MODE;
1082 			op.opt_val = LDC_MODE_RELIABLE;
1083 
1084 			if (ioctl(lsp->fds_chan.fd, VLDC_IOCTL_OPT_OP,
1085 			    &op) != 0) {
1086 				(void) close(lsp->fds_chan.fd);
1087 				(void) pthread_mutex_unlock(&lsp->mt);
1088 				return (1);
1089 			}
1090 		}
1091 		lsp->fds_chan.state = CHANNEL_OPEN;
1092 	}
1093 
1094 	if (lsp->fds_chan.state == CHANNEL_OPEN) {
1095 		/*
1096 		 * reset various channel parameters
1097 		 */
1098 		lsp->fds_chan.ver.major = 0;
1099 		lsp->fds_chan.ver.minor = 0;
1100 		fds_svc_reset(lsp, -1);
1101 	}
1102 	(void) pthread_mutex_unlock(&lsp->mt);
1103 
1104 	return (0);
1105 }
1106 
1107 
1108 static void
1109 channel_fini(void)
1110 {
1111 	struct ldmsvcs_info *lsp;
1112 
1113 	/*
1114 	 * End the poller thread
1115 	 */
1116 	poller_shutdown();
1117 
1118 	if ((lsp = channel_init(NULL)) == NULL)
1119 		return;
1120 
1121 	(void) pthread_mutex_lock(&lsp->mt);
1122 
1123 	lsp->fds_chan.state = CHANNEL_EXIT;
1124 	(void) close(lsp->fds_chan.fd);
1125 
1126 	(void) pthread_mutex_unlock(&lsp->mt);
1127 }
1128 
1129 
1130 static struct ldmsvcs_info *
1131 channel_init(struct ldom_hdl *lhp)
1132 {
1133 	static pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER;
1134 	static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
1135 	static struct ldmsvcs_info *root = NULL;
1136 	static int busy_init = 0;
1137 
1138 	struct timespec twait;
1139 	int expired;
1140 
1141 	(void) pthread_mutex_lock(&mt);
1142 
1143 	while (busy_init == 1)
1144 		(void) pthread_cond_wait(&cv, &mt);
1145 
1146 	if (root != NULL || (lhp == NULL && root == NULL)) {
1147 		(void) pthread_mutex_unlock(&mt);
1148 		return (root);
1149 	}
1150 
1151 	/*
1152 	 * get to this point if we need to open the channel
1153 	 */
1154 	busy_init = 1;
1155 	(void) pthread_mutex_unlock(&mt);
1156 
1157 	root = (struct ldmsvcs_info *)
1158 	    lhp->allocp(sizeof (struct ldmsvcs_info));
1159 	bzero(root, sizeof (struct ldmsvcs_info));
1160 
1161 	root->fds_chan.state = CHANNEL_UNINITIALIZED;
1162 	root->cv_twait = get_smf_int_val(LDM_INIT_TO_PROP_NM,
1163 	    0, LDM_TIMEOUT_CEILING, LDM_INIT_WAIT_TIME);
1164 
1165 	if (pthread_mutex_init(&root->mt, NULL) != 0 ||
1166 	    pthread_cond_init(&root->cv, NULL) != 0) {
1167 		lhp->freep(root, sizeof (struct ldmsvcs_info));
1168 		return (NULL);
1169 	}
1170 
1171 	fds_svc_alloc(lhp, root);
1172 	fds_svc_reset(root, -1);
1173 
1174 	(void) poller_init(root);
1175 
1176 	expired = 0;
1177 	twait.tv_sec = time(NULL) + 10;
1178 	twait.tv_nsec = 0;
1179 
1180 	(void) pthread_mutex_lock(&root->mt);
1181 
1182 	/*
1183 	 * wait for channel to become uninitialized.  this should be quick.
1184 	 */
1185 	while (root->fds_chan.state == CHANNEL_UNINITIALIZED && expired == 0)
1186 		expired = pthread_cond_timedwait(&root->cv, &root->mt, &twait);
1187 
1188 	if (root->fds_chan.state == CHANNEL_UNUSABLE)
1189 		expired = 1;
1190 
1191 	(void) pthread_mutex_unlock(&root->mt);
1192 
1193 	(void) pthread_mutex_lock(&mt);
1194 	busy_init = 0;
1195 	(void) pthread_mutex_unlock(&mt);
1196 	(void) pthread_cond_broadcast(&cv);
1197 
1198 	(void) atexit(channel_fini);
1199 
1200 	if (expired == 0)
1201 		return (root);
1202 	else
1203 		return (NULL);
1204 }
1205 
1206 
1207 static int
1208 sendrecv(struct ldom_hdl *lhp, uint64_t req_num,
1209 	void *msg, size_t msglen, ds_svc_hdl_t *svc_hdl, char *svcname,
1210 	void **resp, size_t *resplen)
1211 {
1212 	struct ldmsvcs_info *lsp;
1213 	fds_svc_t *svc;
1214 	int maxretries, index, i, ier;
1215 
1216 	lsp = lhp->lsinfo;
1217 	i = 0;
1218 	maxretries = 1;
1219 
1220 	do {
1221 		/*
1222 		 * if any of the calls in this loop fail, retry some number
1223 		 * of times before giving up.
1224 		 */
1225 		if ((svc = fds_svc_lookup(lsp, svcname)) == NULL) {
1226 			(void) pthread_mutex_lock(&lsp->mt);
1227 
1228 			if (lsp->fds_chan.state != CHANNEL_READY)
1229 				ier = ETIMEDOUT;	/* channel not ready */
1230 			else
1231 				ier = ENOTSUP;		/* service not ready */
1232 
1233 			(void) pthread_mutex_unlock(&lsp->mt);
1234 
1235 			continue;
1236 		} else {
1237 			ier = 0;
1238 			*svc_hdl = svc->hdl;
1239 		}
1240 
1241 		index = poller_add_pending(lhp, req_num);
1242 
1243 		if ((ier = fds_send(lsp, msg, msglen)) != 0 ||
1244 		    (ier = poller_recv_data(lhp, req_num, index, resp,
1245 		    resplen)) != 0)
1246 			poller_delete_pending(req_num, index);
1247 
1248 	} while (i++ < maxretries && ier != 0);
1249 
1250 	ASSERT(ier == 0 || ier == ETIMEDOUT || ier == ENOTSUP);
1251 
1252 	return (ier);
1253 }
1254 
1255 
1256 /*
1257  * input:
1258  *   msg_type - requested operation: FMA_CPU_REQ_STATUS or FMA_CPU_REQ_OFFLINE
1259  *   cpuid - physical cpu id
1260  *
1261  * normal return values:
1262  *   P_OFFLINE - cpu is offline
1263  *   P_ONLINE - cpu is online
1264  *
1265  * abnormal return values:
1266  *   ETIMEDOUT - LDOM manager is not responding
1267  *   ENOTSUP - LDOM service for cpu offlining/status is not available
1268  *   ENOMSG - got an unexpected response from the LDOM cpu service
1269  */
1270 static int
1271 cpu_request(struct ldom_hdl *lhp, uint32_t msg_type, uint32_t cpuid)
1272 {
1273 	ds_hdr_t *H;
1274 	ds_data_handle_t *D;
1275 	fma_cpu_service_req_t *R;
1276 
1277 	char *svcname = "fma-phys-cpu-service";
1278 	fma_cpu_resp_t *respmsg;
1279 	void *resp;
1280 	size_t resplen, reqmsglen;
1281 	int rc;
1282 
1283 	if (lhp->lsinfo == NULL)
1284 		return (ENOMSG);
1285 
1286 	reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) +
1287 	    sizeof (fma_cpu_service_req_t);
1288 
1289 	H = lhp->allocp(reqmsglen);
1290 	D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
1291 	R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t));
1292 
1293 	H->msg_type = DS_DATA;
1294 	H->payload_len = sizeof (ds_data_handle_t) +
1295 	    sizeof (fma_cpu_service_req_t);
1296 
1297 	R->req_num = fds_svc_req_num();
1298 	R->msg_type = msg_type;
1299 	R->cpu_id = cpuid;
1300 
1301 	if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen,
1302 	    &D->svc_handle, svcname, &resp, &resplen)) != 0) {
1303 		lhp->freep(H, reqmsglen);
1304 		return (rc);
1305 	}
1306 
1307 	lhp->freep(H, reqmsglen);
1308 
1309 	ASSERT(resplen == sizeof (fma_cpu_resp_t));
1310 	respmsg = (fma_cpu_resp_t *)resp;
1311 
1312 	rc = ENOMSG;
1313 	if (respmsg->result == FMA_CPU_RESP_OK) {
1314 		if (respmsg->status == FMA_CPU_STAT_ONLINE)
1315 			rc = P_ONLINE;
1316 		else if (respmsg->status == FMA_CPU_STAT_OFFLINE)
1317 			rc = P_OFFLINE;
1318 	} else {
1319 		if (msg_type == FMA_CPU_REQ_OFFLINE &&
1320 		    respmsg->status == FMA_CPU_STAT_OFFLINE)
1321 			rc = P_OFFLINE;
1322 	}
1323 
1324 	lhp->freep(resp, resplen);
1325 
1326 	return (rc);
1327 }
1328 
1329 
1330 /*
1331  * input:
1332  *   msg_type - requested operation: FMA_MEM_REQ_STATUS or FMA_MEM_REQ_RETIRE
1333  *   pa - starting address of memory page
1334  *   pgsize - memory page size in bytes
1335  *
1336  * normal return values for msg_type == FMA_MEM_REQ_STATUS:
1337  *   0 - page is retired
1338  *   EAGAIN - page is scheduled for retirement
1339  *   EIO - page not scheduled for retirement
1340  *   EINVAL - error
1341  *
1342  * normal return values for msg_type == FMA_MEM_REQ_RETIRE:
1343  *   0 - success in retiring page
1344  *   EIO - page is already retired
1345  *   EAGAIN - page is scheduled for retirement
1346  *   EINVAL - error
1347  *
1348  * abnormal return values (regardless of msg_type)
1349  *   ETIMEDOUT - LDOM manager is not responding
1350  *   ENOTSUP - LDOM service for cpu offlining/status is not available
1351  *   ENOMSG - got an unexpected response from the LDOM cpu service
1352  */
1353 static int
1354 mem_request(struct ldom_hdl *lhp, uint32_t msg_type, uint64_t pa,
1355 	    uint64_t pgsize)
1356 {
1357 	ds_hdr_t *H;
1358 	ds_data_handle_t *D;
1359 	fma_mem_service_req_t *R;
1360 
1361 	char *svcname = "fma-phys-mem-service";
1362 	fma_mem_resp_t *respmsg;
1363 	void *resp;
1364 	size_t resplen, reqmsglen;
1365 	int rc;
1366 
1367 	if (lhp->lsinfo == NULL)
1368 		return (ENOMSG);
1369 
1370 	reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) +
1371 	    sizeof (fma_mem_service_req_t);
1372 
1373 	H = lhp->allocp(reqmsglen);
1374 	bzero(H, reqmsglen);
1375 	D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
1376 	R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t));
1377 
1378 	H->msg_type = DS_DATA;
1379 	H->payload_len = sizeof (ds_data_handle_t) +
1380 	    sizeof (fma_mem_service_req_t);
1381 
1382 	R->req_num = fds_svc_req_num();
1383 	R->msg_type = msg_type;
1384 	R->real_addr = pa;
1385 	R->length = pgsize;
1386 
1387 	if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen,
1388 	    &D->svc_handle, svcname, &resp, &resplen)) != 0) {
1389 		lhp->freep(H, reqmsglen);
1390 		return (rc);
1391 	}
1392 
1393 	lhp->freep(H, reqmsglen);
1394 
1395 	ASSERT(resplen == sizeof (fma_mem_resp_t));
1396 	respmsg = (fma_mem_resp_t *)resp;
1397 
1398 	rc = ENOMSG;
1399 	if (msg_type == FMA_MEM_REQ_STATUS) {
1400 		if (respmsg->result == FMA_MEM_RESP_OK) {
1401 			if (respmsg->status == FMA_MEM_STAT_RETIRED)
1402 				rc = 0;		/* page is retired */
1403 			else if (respmsg->status == FMA_MEM_STAT_NOTRETIRED)
1404 				rc = EIO;	/* page is not scheduled */
1405 		} else if (respmsg->result == FMA_MEM_RESP_FAILURE) {
1406 			if (respmsg->status == FMA_MEM_STAT_NOTRETIRED)
1407 				rc = EAGAIN;	/* page is scheduled */
1408 			else if (respmsg->status == FMA_MEM_STAT_ILLEGAL)
1409 				rc = EINVAL;
1410 		}
1411 	} else if (msg_type == FMA_MEM_REQ_RETIRE) {
1412 		if (respmsg->result == FMA_MEM_RESP_OK) {
1413 			if (respmsg->status == FMA_MEM_STAT_RETIRED)
1414 				rc = 0;		/* is successfully retired */
1415 		} else if (respmsg->result == FMA_MEM_RESP_FAILURE) {
1416 			if (respmsg->status == FMA_MEM_STAT_RETIRED)
1417 				rc = EIO;	/* is already retired */
1418 			else if (respmsg->status == FMA_MEM_STAT_NOTRETIRED)
1419 				rc = EAGAIN;	/* is scheduled to retire */
1420 			else if (respmsg->status == FMA_MEM_STAT_ILLEGAL)
1421 				rc = EINVAL;
1422 		}
1423 	} else if (msg_type == FMA_MEM_REQ_RESURRECT) {
1424 		if (respmsg->result == FMA_MEM_RESP_OK) {
1425 			if (respmsg->status == FMA_MEM_STAT_NOTRETIRED)
1426 				rc = 0;		/* is successfully unretired */
1427 		} if (respmsg->result == FMA_MEM_RESP_FAILURE) {
1428 			if (respmsg->status == FMA_MEM_STAT_RETIRED)
1429 				rc = EAGAIN; 	/* page couldn't be locked */
1430 			else if (respmsg->status == FMA_MEM_STAT_NOTRETIRED)
1431 				rc = EIO;	/* page isn't retired already */
1432 			else if (respmsg->status == FMA_MEM_STAT_ILLEGAL)
1433 				rc = EINVAL;
1434 		}
1435 	}
1436 
1437 	lhp->freep(resp, resplen);
1438 
1439 	return (rc);
1440 }
1441 
1442 
1443 /*
1444  * APIs
1445  */
1446 int
1447 ldmsvcs_check_channel(void)
1448 {
1449 	struct stat buf;
1450 
1451 	if (stat(FDS_VLDC, &buf) == 0)
1452 		return (0);	/* vldc exists */
1453 	else if (errno == ENOENT || errno == ENOTDIR)
1454 		return (1);	/* vldc does not exist */
1455 	else
1456 		return (-1);	/* miscellaneous error */
1457 }
1458 
1459 
1460 /*ARGSUSED*/
1461 void
1462 ldmsvcs_init(struct ldom_hdl *lhp)
1463 {
1464 	if (ldmsvcs_check_channel() != 0)
1465 		return;
1466 
1467 	lhp->lsinfo = channel_init(lhp);
1468 	poller_add_client();
1469 }
1470 
1471 
1472 /*ARGSUSED*/
1473 void
1474 ldmsvcs_fini(struct ldom_hdl *lhp)
1475 {
1476 	if (ldmsvcs_check_channel() != 0)
1477 		return;
1478 
1479 	poller_remove_client();
1480 }
1481 
1482 
1483 /*ARGSUSED*/
1484 ssize_t
1485 ldmsvcs_get_core_md(struct ldom_hdl *lhp, uint64_t **buf)
1486 {
1487 	ds_hdr_t *H;
1488 	ds_data_handle_t *D;
1489 	fma_req_pri_t *R;
1490 
1491 	char *svcname = "fma-pri-service";
1492 	void *resp;
1493 	size_t resplen, reqmsglen;
1494 	ssize_t buflen;
1495 	int rc;
1496 
1497 	if (lhp->lsinfo == NULL)
1498 		return (-1);
1499 
1500 	reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) +
1501 	    sizeof (fma_req_pri_t);
1502 
1503 	H = lhp->allocp(reqmsglen);
1504 	D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
1505 	R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t));
1506 
1507 	H->msg_type = DS_DATA;
1508 	H->payload_len = sizeof (ds_data_handle_t) +
1509 	    sizeof (fma_req_pri_t);
1510 
1511 	R->req_num = fds_svc_req_num();
1512 
1513 	if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen,
1514 	    &D->svc_handle, svcname, &resp, &resplen)) != 0) {
1515 		lhp->freep(H, reqmsglen);
1516 		errno = rc;
1517 		return (-1);
1518 	}
1519 
1520 	lhp->freep(H, reqmsglen);
1521 
1522 	/*
1523 	 * resp should contain the req_num immediately followed by the PRI
1524 	 * (the latter may or may not be present).  unfortunately, the
1525 	 * current compiler flags cause a warning for the following
1526 	 * definition
1527 	 *
1528 	 * typedef struct {
1529 	 *    uint64_t req_num;
1530 	 *    uint8_t pri[];
1531 	 *  } fma_pri_resp_t;
1532 	 *
1533 	 * so we do not use the struct here.
1534 	 */
1535 	if (resplen <= sizeof (uint64_t)) {
1536 		lhp->freep(resp, resplen);
1537 		if (resplen == sizeof (uint64_t))
1538 			return (0);
1539 		else
1540 			return (-1);
1541 	}
1542 
1543 	buflen = resplen - sizeof (uint64_t);
1544 	*buf = lhp->allocp(buflen);
1545 
1546 	bcopy((void *)((ptrdiff_t)resp + sizeof (uint64_t)), *buf, buflen);
1547 	lhp->freep(resp, resplen);
1548 
1549 	return (buflen);
1550 }
1551 
1552 
1553 /*
1554  * see cpu_request() for a description of return values
1555  */
1556 int
1557 ldmsvcs_cpu_req_status(struct ldom_hdl *lhp, uint32_t cpuid)
1558 {
1559 	return (cpu_request(lhp, FMA_CPU_REQ_STATUS, cpuid));
1560 }
1561 
1562 
1563 int
1564 ldmsvcs_cpu_req_offline(struct ldom_hdl *lhp, uint32_t cpuid)
1565 {
1566 	return (cpu_request(lhp, FMA_CPU_REQ_OFFLINE, cpuid));
1567 }
1568 
1569 int
1570 ldmsvcs_cpu_req_online(struct ldom_hdl *lhp, uint32_t cpuid)
1571 {
1572 	return (cpu_request(lhp, FMA_CPU_REQ_ONLINE, cpuid));
1573 }
1574 
1575 /*
1576  * see mem_request() for a description of return values
1577  */
1578 int
1579 ldmsvcs_mem_req_status(struct ldom_hdl *lhp, uint64_t pa)
1580 {
1581 	return (mem_request(lhp, FMA_MEM_REQ_STATUS, pa, getpagesize()));
1582 }
1583 
1584 int
1585 ldmsvcs_mem_req_retire(struct ldom_hdl *lhp, uint64_t pa)
1586 {
1587 	return (mem_request(lhp, FMA_MEM_REQ_RETIRE, pa, getpagesize()));
1588 }
1589 
1590 int
1591 ldmsvcs_mem_req_unretire(struct ldom_hdl *lhp, uint64_t pa)
1592 {
1593 	return (mem_request(lhp, FMA_MEM_REQ_RESURRECT, pa, getpagesize()));
1594 }
1595 
1596 /* end file */
1597