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