xref: /titanic_41/usr/src/lib/fm/libldom/sparc/ldom.c (revision 2654012f83cec5dc15b61dfe3e4a4915f186e7a6)
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 <stdio.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <strings.h>
31 #include <fcntl.h>
32 #include <pthread.h>
33 #include <errno.h>
34 #include <libnvpair.h>
35 #include <dlfcn.h>
36 #include <link.h>
37 #include <assert.h>
38 
39 #include <fm/libtopo.h>
40 #include <sys/processor.h>
41 #include <sys/stat.h>
42 #include <sys/mdesc.h>
43 #include <sys/param.h>
44 #include <sys/systeminfo.h>
45 #include <sys/mem.h>
46 #include <sys/bl.h>
47 #include <sys/fm/protocol.h>
48 #include <fm/fmd_fmri.h>
49 #include <fm/fmd_agent.h>
50 #include <sys/pri.h>
51 
52 #include "ldom.h"
53 #include "ldom_alloc.h"
54 #include "ldmsvcs_utils.h"
55 #include "ldom_xmpp_client.h"
56 
57 #define	MD_STR_PLATFORM		"platform"
58 #define	MD_STR_DOM_CAPABLE	"domaining-enabled"
59 #define	MD_STR_IODEVICE		"iodevice"
60 #define	MD_STR_NAME		"name"
61 #define	MD_STR_DEVICE_TYPE	"device-type"
62 #define	MD_STR_CFGHDL		"cfg-handle"
63 #define	MD_STR_PCIEX		"pciex"
64 #define	MD_STR_PCI		"pci"
65 #define	MD_STR_NIU		"niu"
66 
67 static int ldom_ldmd_is_up = 0; /* assume stays up if ever seen up */
68 
69 static void *ldom_dl_hp = (void *)NULL;
70 static const char *ldom_dl_path = "libpri.so.1";
71 static int ldom_dl_mode = (RTLD_NOW | RTLD_LOCAL);
72 
73 static pthread_mutex_t ldom_pri_lock = PTHREAD_MUTEX_INITIALIZER;
74 static int ldom_pri_ref_cnt = 0; /* num of outstanding ldom_pri_init()s */
75 static int ldom_pri_init_done = 0; /* bool for real pri_init() done */
76 static int (*ldom_pri_fp_init)(void) = (int (*)(void))NULL;
77 static void (*ldom_pri_fp_fini)(void) = (void (*)(void))NULL;
78 static ssize_t (*ldom_pri_fp_get)(uint8_t wait, uint64_t *token, uint64_t **buf,
79 	void *(*allocp)(size_t), void (*freep)(void *, size_t)) =
80 	(ssize_t (*)(uint8_t wait, uint64_t *token, uint64_t **buf,
81 	void *(*allocp)(size_t), void (*freep)(void *, size_t)))NULL;
82 
83 static void
84 ldom_pri_config(void)
85 {
86 	char isa[MAXNAMELEN];	/* used to see if machine is sun4v */
87 
88 	if (sysinfo(SI_MACHINE, isa, MAXNAMELEN) < 0)
89 		return;
90 	if (strcmp(isa, "sun4v") != 0)
91 		return;
92 	if ((ldom_dl_hp = dlopen(ldom_dl_path, ldom_dl_mode)) == NULL)
93 		return;
94 
95 	ldom_pri_fp_init = (int (*)(void))dlsym(ldom_dl_hp, "pri_init");
96 	ldom_pri_fp_fini = (void (*)(void))dlsym(ldom_dl_hp, "pri_fini");
97 	ldom_pri_fp_get = (ssize_t (*)(uint8_t wait, uint64_t *token,
98 	    uint64_t **buf, void *(*allocp)(size_t),
99 	    void (*freep)(void *, size_t)))dlsym(ldom_dl_hp, "pri_get");
100 }
101 
102 static void
103 ldom_pri_unconfig(void)
104 {
105 	if (ldom_dl_hp == NULL)
106 		return;
107 
108 	ldom_pri_fp_init = (int (*)(void))NULL;
109 	ldom_pri_fp_fini = (void (*)(void))NULL;
110 	ldom_pri_fp_get = (ssize_t (*)(uint8_t wait, uint64_t *token,
111 	    uint64_t **buf, void *(*allocp)(size_t),
112 	    void (*freep)(void *, size_t)))NULL;
113 	(void) dlclose(ldom_dl_hp);
114 	ldom_dl_hp = (void *)NULL;
115 }
116 
117 /*
118  * ldom_pri_lock is assumed already held by anyone accessing ldom_pri_ref_cnt
119  */
120 
121 static int
122 ldom_pri_init(void)
123 {
124 	if (ldom_pri_ref_cnt == 0) {
125 		ldom_pri_config();
126 		/*
127 		 * ldom_pri_init() is called before we know whether we
128 		 * have LDOMS FW or not; defer calling pri_init() via
129 		 * ldom_pri_fp_init until the first time we try to
130 		 * actually get a PRI
131 		 */
132 	}
133 	ldom_pri_ref_cnt++;
134 
135 	assert(ldom_pri_ref_cnt > 0);
136 
137 	return (0);
138 }
139 
140 static void
141 ldom_pri_fini(void)
142 {
143 	assert(ldom_pri_ref_cnt > 0);
144 
145 	ldom_pri_ref_cnt--;
146 	if (ldom_pri_ref_cnt == 0) {
147 		if (ldom_pri_init_done && (ldom_pri_fp_fini != NULL)) {
148 			(*ldom_pri_fp_fini)();
149 			ldom_pri_init_done = 0;
150 		}
151 		ldom_pri_unconfig();
152 	}
153 }
154 
155 static ssize_t
156 ldom_pri_get(uint8_t wait, uint64_t *token, uint64_t **buf,
157 		void *(*allocp)(size_t), void (*freep)(void *, size_t))
158 {
159 	assert(ldom_pri_ref_cnt > 0);
160 
161 	if ((!ldom_pri_init_done) && (ldom_pri_fp_init != NULL)) {
162 		if ((*ldom_pri_fp_init)() < 0)
163 			return (-1);
164 		ldom_pri_init_done = 1;
165 	}
166 
167 	if (ldom_pri_fp_get != NULL)
168 		return ((*ldom_pri_fp_get)(wait, token, buf, allocp, freep));
169 	else
170 		return (-1);
171 }
172 
173 static ssize_t
174 get_local_core_md(ldom_hdl_t *lhp, uint64_t **buf)
175 {
176 	int fh;
177 	size_t size;
178 	uint64_t *bufp;
179 
180 	if ((fh = open("/devices/pseudo/mdesc@0:mdesc", O_RDONLY, 0)) < 0)
181 		return (-1);
182 
183 	if (ioctl(fh, MDESCIOCGSZ, &size) < 0) {
184 		(void) close(fh);
185 		return (-1);
186 	}
187 
188 	bufp = (uint64_t *)lhp->allocp(size);
189 
190 	if (read(fh, bufp, size) < 0) {
191 		lhp->freep(bufp, size);
192 		(void) close(fh);
193 		return (-1);
194 	}
195 	(void) close(fh);
196 
197 	*buf = bufp;
198 
199 	return ((ssize_t)size);
200 }
201 
202 
203 static int
204 get_local_md_prop_value(ldom_hdl_t *lhp, char *node, char *prop, uint64_t *val)
205 {
206 	int rc = 1;
207 	uint64_t *bufp;
208 	ssize_t bufsiz;
209 
210 	if ((bufsiz = get_local_core_md(lhp, &bufp)) > 0) {
211 		md_t *mdp;
212 
213 		if (mdp = md_init_intern(bufp, lhp->allocp, lhp->freep)) {
214 			int num_nodes;
215 			mde_cookie_t *listp;
216 
217 			num_nodes = md_node_count(mdp);
218 			listp = lhp->allocp(sizeof (mde_cookie_t) * num_nodes);
219 
220 			if (md_scan_dag(mdp, MDE_INVAL_ELEM_COOKIE,
221 			    md_find_name(mdp, node),
222 			    md_find_name(mdp, "fwd"), listp) > 0 &&
223 			    md_get_prop_val(mdp, listp[0], prop, val) >= 0) {
224 				/* found the property */
225 				rc = 0;
226 			}
227 
228 			lhp->freep(listp, sizeof (mde_cookie_t) * num_nodes);
229 			(void) md_fini(mdp);
230 		}
231 		lhp->freep(bufp, bufsiz);
232 	}
233 	return (rc);
234 }
235 
236 /*
237  * search the machine description for a "pid" entry (physical cpuid) and
238  * return the corresponding "id" entry (virtual cpuid).
239  * return -1 if not found.
240  * if the pid property does not exist in a cpu node, assume pid = id.
241  */
242 static processorid_t
243 cpu_phys2virt(ldom_hdl_t *lhp, uint32_t cpuid)
244 {
245 	char isa[MAXNAMELEN];
246 	md_t *mdp;
247 	mde_cookie_t *listp;
248 	ssize_t bufsize;
249 	processorid_t vid;
250 	uint64_t *bufp;
251 	uint64_t pval, pid, id;
252 	int num_nodes, ncpus, i;
253 
254 	(void) sysinfo(SI_MACHINE, isa, MAXNAMELEN);
255 
256 	if (strcmp(isa, "sun4v") != 0)
257 		return ((processorid_t)cpuid);
258 
259 	/*
260 	 * convert the physical cpuid to a virtual cpuid
261 	 */
262 	if ((bufsize = get_local_core_md(lhp, &bufp)) < 1)
263 		return (-1);
264 
265 	if ((mdp = md_init_intern(bufp, lhp->allocp, lhp->freep)) == NULL ||
266 	    (num_nodes = md_node_count(mdp)) < 1) {
267 		lhp->freep(bufp, bufsize);
268 		return (-1);
269 	}
270 
271 	listp = (mde_cookie_t *)lhp->allocp(sizeof (mde_cookie_t) * num_nodes);
272 	ncpus = md_scan_dag(mdp, MDE_INVAL_ELEM_COOKIE,
273 	    md_find_name(mdp, "cpu"), md_find_name(mdp, "fwd"), listp);
274 
275 	vid = -1;
276 	for (i = 0; i < ncpus; i++) {
277 		if (md_get_prop_val(mdp, listp[i], "id", &pval) < 0)
278 			pval = (uint64_t)-1;
279 		id = pval;
280 
281 		/* if pid does not exist, assume pid=id */
282 		if (md_get_prop_val(mdp, listp[i], "pid", &pval) < 0)
283 			pval = id;
284 		pid = pval;
285 
286 		if (pid == (uint64_t)cpuid) {
287 			/* Found the entry */
288 			vid = (processorid_t)id;
289 			break;
290 		}
291 	}
292 
293 	lhp->freep(listp, sizeof (mde_cookie_t) * num_nodes);
294 	(void) md_fini(mdp);
295 	lhp->freep(bufp, bufsize);
296 
297 	return (vid);
298 }
299 
300 static int
301 get_type(ldom_hdl_t *lhp, uint32_t *type)
302 {
303 	int num_nodes, cnt, i, rc;
304 	char *p;
305 	mde_cookie_t *listp;
306 	md_t *mdp;
307 	uint64_t domain_capable;
308 	uint64_t *bufp;
309 	ssize_t bufsize;
310 
311 	*type = 0;
312 
313 	/* legacy system */
314 	if (get_local_md_prop_value(lhp, MD_STR_PLATFORM, MD_STR_DOM_CAPABLE,
315 	    &domain_capable) != 0) {
316 		*type = LDOM_TYPE_LEGACY;
317 		return (0);
318 	}
319 
320 	/*
321 	 * LDOMS capable FW is installed; it should be ok to
322 	 * try to communicate with ldmd
323 	 */
324 	if ((rc = ldmsvcs_check_channel()) == 0) {
325 		/*
326 		 * control ldom
327 		 * ldmfma channel between FMA and ldmd only exists
328 		 * on the control domain.
329 		 */
330 		*type |= LDOM_TYPE_CONTROL;
331 	} else if (rc == -1) {
332 		return (rc);
333 	}
334 
335 	/*
336 	 * root domain and io domain
337 	 */
338 	if ((bufsize = get_local_core_md(lhp, &bufp)) < 1)
339 		return (-1);
340 	if ((mdp = md_init_intern(bufp, lhp->allocp, lhp->freep)) == NULL) {
341 		lhp->freep(bufp, bufsize);
342 		return (-1);
343 	}
344 	if ((num_nodes = md_node_count(mdp)) < 1) {
345 		lhp->freep(bufp, bufsize);
346 		(void) md_fini(mdp);
347 		return (-1);
348 	}
349 
350 	/* Search for the root complex and niu nodes */
351 	listp = lhp->allocp(sizeof (mde_cookie_t) * num_nodes);
352 	cnt = md_scan_dag(mdp, MDE_INVAL_ELEM_COOKIE,
353 	    md_find_name(mdp, MD_STR_IODEVICE), md_find_name(mdp, "fwd"),
354 	    listp);
355 	for (i = 0, p = NULL; i < cnt; i++) {
356 		if ((md_get_prop_str(mdp, listp[i], MD_STR_DEVICE_TYPE, &p)
357 		    == 0) &&
358 		    (p != NULL) && (strcmp(p, MD_STR_PCIEX) == 0)) {
359 			*type |= LDOM_TYPE_ROOT;
360 			break;
361 		}
362 	}
363 	for (i = 0, p = NULL; i < cnt; i++) {
364 		if ((md_get_prop_str(mdp, listp[i], MD_STR_NAME, &p) == 0) &&
365 		    (p != NULL) && (strcmp(p, MD_STR_NIU) == 0)) {
366 			*type |= LDOM_TYPE_IO;
367 			break;
368 		}
369 	}
370 	lhp->freep(listp, sizeof (mde_cookie_t) * num_nodes);
371 	(void) md_fini(mdp);
372 	lhp->freep(bufp, bufsize);
373 
374 	return (0);
375 }
376 
377 int
378 ldom_get_type(ldom_hdl_t *lhp, uint32_t *type)
379 {
380 	static pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER;
381 	static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
382 	static uint32_t ltype = 0;
383 	static int busy_init = 0;
384 
385 	int rc = 0;
386 
387 	(void) pthread_mutex_lock(&mt);
388 
389 	while (busy_init == 1)
390 		(void) pthread_cond_wait(&cv, &mt);
391 
392 	if (VALID_LDOM_TYPE(ltype) != 0) {
393 		*type = ltype;
394 		(void) pthread_mutex_unlock(&mt);
395 		return (0);
396 	}
397 
398 	/*
399 	 * get to this point if the ldom_type has not yet been determined
400 	 */
401 	busy_init = 1;
402 	(void) pthread_mutex_unlock(&mt);
403 
404 	rc = get_type(lhp, &ltype);
405 	if (rc == 0) {
406 		*type = ltype;
407 	}
408 
409 	(void) pthread_mutex_lock(&mt);
410 	busy_init = 0;
411 	(void) pthread_mutex_unlock(&mt);
412 
413 	(void) pthread_cond_broadcast(&cv);
414 
415 	return (rc);
416 }
417 
418 int
419 ldom_fmri_status(ldom_hdl_t *lhp, nvlist_t *nvl)
420 {
421 	char *name;
422 	int ret = ENOTSUP;
423 
424 	if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &name) != 0)
425 		return (EINVAL);
426 
427 	/*
428 	 * ldom_ldmd_is_up can only be true if a pri can be obtained from ldmd.
429 	 */
430 	if (!ldom_ldmd_is_up) {
431 		/* Zeus is unavail; use local routines for status/retire */
432 
433 		if (strcmp(name, FM_FMRI_SCHEME_CPU) == 0) {
434 			processorid_t vid;
435 			uint32_t cpuid;
436 
437 			if (nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid)
438 			    == 0 && (vid = cpu_phys2virt(lhp, cpuid)) != -1)
439 				return (p_online(vid, P_STATUS));
440 		} else if (strcmp(name, FM_FMRI_SCHEME_MEM) == 0) {
441 			fmd_agent_hdl_t *hdl;
442 			int err;
443 			if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) == NULL) {
444 				err = errno;
445 			} else {
446 				err = fmd_agent_page_isretired(hdl, nvl);
447 				if (err == FMD_AGENT_RETIRE_DONE)
448 					err = 0;
449 				else
450 					err = fmd_agent_errno(hdl);
451 				fmd_agent_close(hdl);
452 			}
453 			return (err);
454 		}
455 
456 		return (EINVAL);
457 	} else {
458 		/* Zeus is avail; use Zeus for status/retire */
459 
460 		if (strcmp(name, FM_FMRI_SCHEME_CPU) == 0) {
461 			uint32_t cpuid;
462 
463 			if (nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID,
464 			    &cpuid) == 0)
465 				ret = ldmsvcs_cpu_req_status(lhp, cpuid);
466 		} else if (strcmp(name, FM_FMRI_SCHEME_MEM) == 0) {
467 			uint64_t pa;
468 
469 			if (nvlist_lookup_uint64(nvl, FM_FMRI_MEM_PHYSADDR,
470 			    &pa) == 0)
471 				ret = ldmsvcs_mem_req_status(lhp, pa);
472 			else
473 				ret = EINVAL;
474 		}
475 		return (ret);
476 	}
477 }
478 
479 
480 int
481 ldom_fmri_retire(ldom_hdl_t *lhp, nvlist_t *nvl)
482 {
483 	char *name;
484 	int ret = ENOTSUP;
485 
486 	if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &name) != 0)
487 		return (EINVAL);
488 
489 	/*
490 	 * ldom_ldmd_is_up can only be true if a pri can be obtained from ldmd.
491 	 */
492 	if (!ldom_ldmd_is_up) {
493 		/* Zeus is unavail; use local routines for status/retire */
494 
495 		if (strcmp(name, FM_FMRI_SCHEME_CPU) == 0) {
496 			processorid_t vid;
497 			uint32_t cpuid;
498 
499 			if (nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid)
500 			    == 0 && (vid = cpu_phys2virt(lhp, cpuid)) != -1)
501 				return (p_online(vid, P_FAULTED));
502 		} else if (strcmp(name, FM_FMRI_SCHEME_MEM) == 0) {
503 			fmd_agent_hdl_t *hdl;
504 			int err;
505 			if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) == NULL) {
506 				err = errno;
507 			} else {
508 				err = fmd_agent_page_retire(hdl, nvl);
509 				if (err == FMD_AGENT_RETIRE_DONE)
510 					err = 0;
511 				else
512 					err = fmd_agent_errno(hdl);
513 				fmd_agent_close(hdl);
514 			}
515 			return (err);
516 		}
517 
518 		return (EINVAL);
519 	} else {
520 		/* Zeus is avail; use Zeus for status/retire */
521 
522 		if (strcmp(name, FM_FMRI_SCHEME_CPU) == 0) {
523 			uint32_t cpuid;
524 
525 			if (nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID,
526 			    &cpuid) == 0)
527 				ret = ldmsvcs_cpu_req_offline(lhp, cpuid);
528 		} else if (strcmp(name, FM_FMRI_SCHEME_MEM) == 0) {
529 			uint64_t pa;
530 
531 			if (nvlist_lookup_uint64(nvl, FM_FMRI_MEM_PHYSADDR,
532 			    &pa) == 0)
533 				ret = ldmsvcs_mem_req_retire(lhp, pa);
534 			else
535 				ret = EINVAL;
536 		}
537 		return (ret);
538 	}
539 }
540 
541 int
542 ldom_fmri_unretire(ldom_hdl_t *lhp, nvlist_t *nvl)
543 {
544 	char *name;
545 	int ret = ENOTSUP;
546 
547 	if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &name) != 0)
548 		return (EINVAL);
549 
550 	/*
551 	 * ldom_ldmd_is_up can only be true if a pri can be obtained from ldmd.
552 	 */
553 	if (!ldom_ldmd_is_up) {
554 		/* Zeus is unavail; use local routines for status/retire */
555 
556 		if (strcmp(name, FM_FMRI_SCHEME_CPU) == 0) {
557 			processorid_t vid;
558 			uint32_t cpuid;
559 
560 			if (nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid)
561 			    == 0 && (vid = cpu_phys2virt(lhp, cpuid)) != -1)
562 				return (p_online(vid, P_ONLINE));
563 		} else if (strcmp(name, FM_FMRI_SCHEME_MEM) == 0) {
564 			fmd_agent_hdl_t *hdl;
565 			int err;
566 			if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) == NULL) {
567 				err = errno;
568 			} else {
569 				err = fmd_agent_page_unretire(hdl, nvl);
570 				if (err == FMD_AGENT_RETIRE_DONE)
571 					err = 0;
572 				else
573 					err = fmd_agent_errno(hdl);
574 				fmd_agent_close(hdl);
575 			}
576 			return (err);
577 		}
578 
579 		return (EINVAL);
580 	} else {
581 		/* Zeus is avail; use Zeus for status/retire */
582 
583 		if (strcmp(name, FM_FMRI_SCHEME_CPU) == 0) {
584 			uint32_t cpuid;
585 
586 			if (nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID,
587 			    &cpuid) == 0)
588 				ret = ldmsvcs_cpu_req_online(lhp, cpuid);
589 		} else if (strcmp(name, FM_FMRI_SCHEME_MEM) == 0) {
590 			uint64_t pa;
591 
592 			if (nvlist_lookup_uint64(nvl, FM_FMRI_MEM_PHYSADDR,
593 			    &pa) == 0)
594 				ret = ldmsvcs_mem_req_unretire(lhp, pa);
595 			else
596 				ret = EINVAL;
597 		}
598 		return (ret);
599 	}
600 }
601 
602 static int
603 fmri_blacklist(ldom_hdl_t *lhp, nvlist_t *nvl, int cmd)
604 {
605 	char *name;
606 	uint32_t type = 0;
607 
608 	if ((ldom_get_type(lhp, &type) != 0) ||
609 	    ((type & LDOM_TYPE_LEGACY) == 0))
610 		return (0);
611 
612 	if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &name) != 0)
613 		return (EINVAL);
614 
615 	if (strcmp(name, FM_FMRI_SCHEME_CPU) == 0) {
616 		bl_req_t blr;
617 		char *class;
618 		int fd, rc, err;
619 
620 		if ((nvlist_lookup_string(nvl, FM_CLASS, &class) != 0) ||
621 		    (class == NULL) || (*class == '\0'))
622 			return (EINVAL);
623 
624 		if ((fd = open("/dev/bl", O_RDONLY)) < 0)
625 			return (EIO);
626 
627 		if (nvlist_size(nvl, &blr.bl_fmrisz, NV_ENCODE_NATIVE) != 0 ||
628 		    blr.bl_fmrisz == 0 ||
629 		    (blr.bl_fmri = (caddr_t)lhp->allocp(blr.bl_fmrisz)) ==
630 		    NULL) {
631 			(void) close(fd);
632 			return (EINVAL);
633 		}
634 
635 		blr.bl_class = class;
636 
637 		rc = ioctl(fd, cmd, &blr);
638 		err = errno;
639 
640 		lhp->freep((void *)&blr.bl_fmri, blr.bl_fmrisz);
641 		(void) close(fd);
642 
643 		if (rc < 0 && err != ENOTSUP) {
644 			errno = err;
645 			return (-1);
646 		}
647 	}
648 
649 	return (0);
650 }
651 
652 /*
653  * blacklist cpus in a non-LDOMS environment
654  */
655 int
656 ldom_fmri_blacklist(ldom_hdl_t *lhp, nvlist_t *nvl)
657 {
658 	return (fmri_blacklist(lhp, nvl, BLIOC_INSERT));
659 }
660 
661 /*
662  * unblacklist cpus
663  */
664 int
665 ldom_fmri_unblacklist(ldom_hdl_t *lhp, nvlist_t *nvl)
666 {
667 	return (fmri_blacklist(lhp, nvl, BLIOC_DELETE));
668 }
669 
670 
671 ssize_t
672 ldom_get_local_md(ldom_hdl_t *lhp, uint64_t **buf)
673 {
674 	return (get_local_core_md(lhp, buf));
675 }
676 
677 ssize_t
678 ldom_get_core_md(ldom_hdl_t *lhp, uint64_t **buf)
679 {
680 	ssize_t		rv;	/* return value */
681 	uint64_t	tok;	/* opaque PRI token */
682 	uint32_t	type = 0;
683 
684 	(void) ldom_get_type(lhp, &type);
685 	if (VALID_LDOM_TYPE(type) == 0) {
686 		return (-1);
687 	}
688 	if ((type & LDOM_TYPE_CONTROL) != 0) {
689 		/* Get the pri from Zeus first. If failed, get it from libpri */
690 		if ((rv = ldmsvcs_get_core_md(lhp, buf)) < 1) {
691 			(void) pthread_mutex_lock(&ldom_pri_lock);
692 			rv = ldom_pri_get(PRI_GET, &tok,
693 			    buf, lhp->allocp, lhp->freep);
694 			(void) pthread_mutex_unlock(&ldom_pri_lock);
695 		} else {
696 			ldom_ldmd_is_up = 1;
697 			xmpp_start();
698 		}
699 	} else {
700 		/* get the local MD */
701 		rv = get_local_core_md(lhp, buf);
702 	}
703 
704 	return (rv);
705 }
706 
707 int
708 ldom_find_id(ldom_hdl_t *lhp, uint64_t addr, ldom_rsrc_t rsrc,
709     uint64_t *virt_addr, char *name, int name_size, uint64_t *did)
710 {
711 	uint32_t type = 0;
712 
713 	(void) ldom_get_type(lhp, &type);
714 	if ((type & LDOM_TYPE_CONTROL) == 0) {
715 		return (ENOTSUP);
716 	}
717 	if (!ldom_ldmd_is_up) {
718 		return (EAGAIN);
719 	}
720 	return (ldmsvcs_io_req_id(lhp, addr, rsrc, virt_addr,
721 	    name, name_size, did));
722 }
723 
724 int
725 ldom_register_event(ldom_hdl_t *lhp, ldom_reg_cb_t cb, ldom_cb_arg_t data)
726 {
727 	uint32_t type = 0;
728 
729 	(void) ldom_get_type(lhp, &type);
730 	if ((type & LDOM_TYPE_CONTROL) == 0) {
731 		return (ENOTSUP);
732 	}
733 
734 	return (xmpp_add_client(lhp, cb, data));
735 }
736 
737 int
738 ldom_unregister_event(ldom_hdl_t *lhp)
739 {
740 	uint32_t type = 0;
741 
742 	(void) ldom_get_type(lhp, &type);
743 	if ((type & LDOM_TYPE_CONTROL) == 0) {
744 		return (ENOTSUP);
745 	}
746 
747 	return (xmpp_remove_client(lhp));
748 }
749 
750 /*
751  * ldom_init()
752  * Description:
753  *     Return a libldom handle to the caller for uniquely identify the session
754  *     betweem the caller and the libldom.so. The handle is used in
755  *     subsequent calls into the libldom.so
756  *
757  *     If the caller does not provide a alloc()/free(), the libldom uses its
758  *     own functions.
759  */
760 ldom_hdl_t *
761 ldom_init(void *(*allocp)(size_t size),
762 	void (*freep)(void *addr, size_t size))
763 {
764 	struct ldom_hdl *lhp;
765 
766 	if (allocp == NULL && freep == NULL) {
767 		allocp = ldom_alloc;
768 		freep = ldom_free;
769 	} else if (allocp == NULL || freep == NULL) {
770 		/* missing alloc or free functions */
771 		return (NULL);
772 	}
773 
774 	(void) pthread_mutex_lock(&ldom_pri_lock);
775 
776 	if (ldom_pri_init() < 0) {
777 		(void) pthread_mutex_unlock(&ldom_pri_lock);
778 		return (NULL);
779 	}
780 
781 	if ((lhp = allocp(sizeof (struct ldom_hdl))) == NULL) {
782 		ldom_pri_fini();
783 		(void) pthread_mutex_unlock(&ldom_pri_lock);
784 		return (NULL);
785 	}
786 
787 	(void) pthread_mutex_unlock(&ldom_pri_lock);
788 
789 	lhp->allocp = allocp;
790 	lhp->freep = freep;
791 
792 	ldmsvcs_init(lhp);
793 
794 	return (lhp);
795 }
796 
797 
798 void
799 ldom_fini(ldom_hdl_t *lhp)
800 {
801 	if (lhp == NULL)
802 		return;
803 
804 	(void) xmpp_remove_client(lhp);
805 	ldmsvcs_fini(lhp);
806 	lhp->freep(lhp, sizeof (struct ldom_hdl));
807 
808 	(void) pthread_mutex_lock(&ldom_pri_lock);
809 
810 	ldom_pri_fini();
811 
812 	(void) pthread_mutex_unlock(&ldom_pri_lock);
813 }
814 
815 /* end file */
816