xref: /illumos-gate/usr/src/lib/fm/topo/libtopo/common/topo_xml.c (revision 9adf2ea6d6cc9c5ea216e001c804a4beda729c2a)
17aec1d6eScindi /*
27aec1d6eScindi  * CDDL HEADER START
37aec1d6eScindi  *
47aec1d6eScindi  * The contents of this file are subject to the terms of the
57aec1d6eScindi  * Common Development and Distribution License (the "License").
67aec1d6eScindi  * You may not use this file except in compliance with the License.
77aec1d6eScindi  *
87aec1d6eScindi  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97aec1d6eScindi  * or http://www.opensolaris.org/os/licensing.
107aec1d6eScindi  * See the License for the specific language governing permissions
117aec1d6eScindi  * and limitations under the License.
127aec1d6eScindi  *
137aec1d6eScindi  * When distributing Covered Code, include this CDDL HEADER in each
147aec1d6eScindi  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157aec1d6eScindi  * If applicable, add the following below this CDDL HEADER, with the
167aec1d6eScindi  * fields enclosed by brackets "[]" replaced with your own identifying
177aec1d6eScindi  * information: Portions Copyright [yyyy] [name of copyright owner]
187aec1d6eScindi  *
197aec1d6eScindi  * CDDL HEADER END
207aec1d6eScindi  */
217aec1d6eScindi 
227aec1d6eScindi /*
23af218de5SRobert Johnston  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
243c6ffbabSRob Johnston  * Copyright 2020 Joyent, Inc.
257aec1d6eScindi  */
267aec1d6eScindi 
277aec1d6eScindi #include <libxml/parser.h>
287aec1d6eScindi #include <libxml/xinclude.h>
297aec1d6eScindi #include <sys/fm/protocol.h>
307aec1d6eScindi #include <assert.h>
317aec1d6eScindi #include <string.h>
327aec1d6eScindi #include <strings.h>
337aec1d6eScindi #include <ctype.h>
347aec1d6eScindi #include <errno.h>
357aec1d6eScindi #include <limits.h>
367aec1d6eScindi #include <fm/libtopo.h>
377aec1d6eScindi #include <unistd.h>
387aec1d6eScindi #include <sys/stat.h>
397aec1d6eScindi #include <fcntl.h>
404557a2a1Srobj #include <topo_file.h>
417aec1d6eScindi #include <topo_mod.h>
427aec1d6eScindi #include <topo_subr.h>
437aec1d6eScindi #include <topo_alloc.h>
447aec1d6eScindi #include <topo_parse.h>
457aec1d6eScindi #include <topo_error.h>
467aec1d6eScindi 
472eeaed14Srobj static tf_rdata_t *topo_xml_walk(topo_mod_t *, tf_info_t *, xmlNodePtr,
482eeaed14Srobj     tnode_t *);
492eeaed14Srobj static tf_edata_t *enum_attributes_process(topo_mod_t *, xmlNodePtr);
502eeaed14Srobj static int enum_run(topo_mod_t *, tf_rdata_t *);
51825ba0f2Srobj static int fac_enum_run(topo_mod_t *, tnode_t *, const char *);
52825ba0f2Srobj static int fac_process(topo_mod_t *, xmlNodePtr, tf_rdata_t *, tnode_t *);
53825ba0f2Srobj static int fac_enum_process(topo_mod_t *, xmlNodePtr, tnode_t *);
542eeaed14Srobj static int decorate_nodes(topo_mod_t *, tf_rdata_t *, xmlNodePtr, tnode_t *,
552eeaed14Srobj     tf_pad_t **);
567aec1d6eScindi 
574557a2a1Srobj 
587aec1d6eScindi int
xmlattr_to_stab(topo_mod_t * mp,xmlNodePtr n,const char * stabname,topo_stability_t * rs)590eb822a1Scindi xmlattr_to_stab(topo_mod_t *mp, xmlNodePtr n, const char *stabname,
600eb822a1Scindi     topo_stability_t *rs)
617aec1d6eScindi {
627aec1d6eScindi 	xmlChar *str;
637aec1d6eScindi 	int rv = 0;
647aec1d6eScindi 
657aec1d6eScindi 	if (n == NULL) {
667aec1d6eScindi 		/* If there is no Stability defined, we default to private */
677aec1d6eScindi 		*rs = TOPO_STABILITY_PRIVATE;
687aec1d6eScindi 		return (0);
697aec1d6eScindi 	}
700eb822a1Scindi 	if ((str = xmlGetProp(n, (xmlChar *)stabname)) == NULL) {
710eb822a1Scindi 		topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
720eb822a1Scindi 		    "attribute to stability:\n");
737aec1d6eScindi 		return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
740eb822a1Scindi 	}
750eb822a1Scindi 
767aec1d6eScindi 	if (xmlStrcmp(str, (xmlChar *)Internal) == 0) {
777aec1d6eScindi 		*rs = TOPO_STABILITY_INTERNAL;
787aec1d6eScindi 	} else if (xmlStrcmp(str, (xmlChar *)Private) == 0) {
797aec1d6eScindi 		*rs = TOPO_STABILITY_PRIVATE;
807aec1d6eScindi 	} else if (xmlStrcmp(str, (xmlChar *)Obsolete) == 0) {
817aec1d6eScindi 		*rs = TOPO_STABILITY_OBSOLETE;
827aec1d6eScindi 	} else if (xmlStrcmp(str, (xmlChar *)External) == 0) {
837aec1d6eScindi 		*rs = TOPO_STABILITY_EXTERNAL;
847aec1d6eScindi 	} else if (xmlStrcmp(str, (xmlChar *)Unstable) == 0) {
857aec1d6eScindi 		*rs = TOPO_STABILITY_UNSTABLE;
867aec1d6eScindi 	} else if (xmlStrcmp(str, (xmlChar *)Evolving) == 0) {
877aec1d6eScindi 		*rs = TOPO_STABILITY_EVOLVING;
887aec1d6eScindi 	} else if (xmlStrcmp(str, (xmlChar *)Stable) == 0) {
897aec1d6eScindi 		*rs = TOPO_STABILITY_STABLE;
907aec1d6eScindi 	} else if (xmlStrcmp(str, (xmlChar *)Standard) == 0) {
917aec1d6eScindi 		*rs = TOPO_STABILITY_STANDARD;
927aec1d6eScindi 	} else {
937aec1d6eScindi 		xmlFree(str);
947aec1d6eScindi 		return (topo_mod_seterrno(mp, ETOPO_PRSR_BADSTAB));
957aec1d6eScindi 	}
967aec1d6eScindi 	xmlFree(str);
977aec1d6eScindi 	return (rv);
987aec1d6eScindi }
997aec1d6eScindi 
1007aec1d6eScindi int
xmlattr_to_int(topo_mod_t * mp,xmlNodePtr n,const char * propname,uint64_t * value)1017aec1d6eScindi xmlattr_to_int(topo_mod_t *mp,
1027aec1d6eScindi     xmlNodePtr n, const char *propname, uint64_t *value)
1037aec1d6eScindi {
1047aec1d6eScindi 	xmlChar *str;
1057aec1d6eScindi 	xmlChar *estr;
1067aec1d6eScindi 
107c5591576SRob Johnston 	if ((str = xmlGetProp(n, (xmlChar *)propname)) == NULL) {
108c5591576SRob Johnston 		topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
109c5591576SRob Johnston 		    "%s: failed to lookup %s attribute", __func__, propname);
1107aec1d6eScindi 		return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
111c5591576SRob Johnston 	}
112ebee07ffSRob Johnston 	errno = 0;
113ebee07ffSRob Johnston 	*value = strtoull((char *)str, (char **)&estr, 0);
114ebee07ffSRob Johnston 	if (errno != 0 || *estr != '\0') {
1157aec1d6eScindi 		/* no conversion was done */
1167aec1d6eScindi 		xmlFree(str);
117c5591576SRob Johnston 		topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
118c5591576SRob Johnston 		    "%s: failed to convert %s attribute", __func__, propname);
1197aec1d6eScindi 		return (topo_mod_seterrno(mp, ETOPO_PRSR_BADNUM));
1207aec1d6eScindi 	}
1217aec1d6eScindi 	xmlFree(str);
1227aec1d6eScindi 	return (0);
1237aec1d6eScindi }
1247aec1d6eScindi 
125c184cb88SRob Johnston int
xmlattr_to_double(topo_mod_t * mp,xmlNodePtr n,const char * propname,double * value)126c184cb88SRob Johnston xmlattr_to_double(topo_mod_t *mp,
127c184cb88SRob Johnston     xmlNodePtr n, const char *propname, double *value)
128c184cb88SRob Johnston {
129c184cb88SRob Johnston 	xmlChar *str;
130c184cb88SRob Johnston 	xmlChar *estr;
131c184cb88SRob Johnston 
132c184cb88SRob Johnston 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
133c184cb88SRob Johnston 	    "xmlattr_to_double(propname=%s)\n", propname);
134c184cb88SRob Johnston 	if ((str = xmlGetProp(n, (xmlChar *)propname)) == NULL)
135c184cb88SRob Johnston 		return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
136ebee07ffSRob Johnston 
137ebee07ffSRob Johnston 	errno = 0;
138ebee07ffSRob Johnston 	*value = strtold((char *)str, (char **)&estr);
139ebee07ffSRob Johnston 	if (errno != 0 || *estr != '\0') {
140c184cb88SRob Johnston 		/* full or partial conversion failure */
141c184cb88SRob Johnston 		xmlFree(str);
142c184cb88SRob Johnston 		return (topo_mod_seterrno(mp, ETOPO_PRSR_BADNUM));
143c184cb88SRob Johnston 	}
144c184cb88SRob Johnston 	xmlFree(str);
145c184cb88SRob Johnston 	return (0);
146c184cb88SRob Johnston }
147c184cb88SRob Johnston 
1487aec1d6eScindi static int
xmlattr_to_fmri(topo_mod_t * mp,xmlNodePtr xn,const char * propname,nvlist_t ** rnvl)1497aec1d6eScindi xmlattr_to_fmri(topo_mod_t *mp,
1507aec1d6eScindi     xmlNodePtr xn, const char *propname, nvlist_t **rnvl)
1517aec1d6eScindi {
1527aec1d6eScindi 	xmlChar *str;
1537aec1d6eScindi 
154825ba0f2Srobj 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "xmlattr_to_fmri(propname=%s)\n",
155825ba0f2Srobj 	    propname);
1567aec1d6eScindi 	if ((str = xmlGetProp(xn, (xmlChar *)propname)) == NULL)
1577aec1d6eScindi 		return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
158c6765aabSeschrock 	if (topo_mod_str2nvl(mp, (const char *)str, rnvl) < 0) {
159c6765aabSeschrock 		xmlFree(str);
1607aec1d6eScindi 		return (-1);
161c6765aabSeschrock 	}
1627aec1d6eScindi 	xmlFree(str);
1637aec1d6eScindi 	return (0);
1647aec1d6eScindi }
1657aec1d6eScindi 
1667aec1d6eScindi static topo_type_t
xmlattr_to_type(topo_mod_t * mp,xmlNodePtr xn,xmlChar * attr)1674557a2a1Srobj xmlattr_to_type(topo_mod_t *mp, xmlNodePtr xn, xmlChar *attr)
1687aec1d6eScindi {
1697aec1d6eScindi 	topo_type_t rv;
1707aec1d6eScindi 	xmlChar *str;
1714557a2a1Srobj 	if ((str = xmlGetProp(xn, (xmlChar *)attr)) == NULL) {
1724557a2a1Srobj 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "%s attribute missing",
1734557a2a1Srobj 		    attr);
1747aec1d6eScindi 		(void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
1757aec1d6eScindi 		return (TOPO_TYPE_INVALID);
1767aec1d6eScindi 	}
1777aec1d6eScindi 	if (xmlStrcmp(str, (xmlChar *)Int32) == 0) {
1787aec1d6eScindi 		rv = TOPO_TYPE_INT32;
1797aec1d6eScindi 	} else if (xmlStrcmp(str, (xmlChar *)UInt32) == 0) {
1807aec1d6eScindi 		rv = TOPO_TYPE_UINT32;
1817aec1d6eScindi 	} else if (xmlStrcmp(str, (xmlChar *)Int64) == 0) {
1827aec1d6eScindi 		rv = TOPO_TYPE_INT64;
1837aec1d6eScindi 	} else if (xmlStrcmp(str, (xmlChar *)UInt64) == 0) {
1847aec1d6eScindi 		rv = TOPO_TYPE_UINT64;
1857aec1d6eScindi 	} else if (xmlStrcmp(str, (xmlChar *)FMRI) == 0) {
1867aec1d6eScindi 		rv = TOPO_TYPE_FMRI;
1877aec1d6eScindi 	} else if (xmlStrcmp(str, (xmlChar *)String) == 0) {
1887aec1d6eScindi 		rv = TOPO_TYPE_STRING;
189c184cb88SRob Johnston 	} else if (xmlStrcmp(str, (xmlChar *)Double) == 0) {
190c184cb88SRob Johnston 		rv = TOPO_TYPE_DOUBLE;
19188045cffSRobert Johnston 	} else if (xmlStrcmp(str, (xmlChar *)Int32_Arr) == 0) {
19288045cffSRobert Johnston 		rv = TOPO_TYPE_INT32_ARRAY;
19388045cffSRobert Johnston 	} else if (xmlStrcmp(str, (xmlChar *)UInt32_Arr) == 0) {
19488045cffSRobert Johnston 		rv = TOPO_TYPE_UINT32_ARRAY;
19588045cffSRobert Johnston 	} else if (xmlStrcmp(str, (xmlChar *)Int64_Arr) == 0) {
19688045cffSRobert Johnston 		rv = TOPO_TYPE_INT64_ARRAY;
19788045cffSRobert Johnston 	} else if (xmlStrcmp(str, (xmlChar *)UInt64_Arr) == 0) {
19888045cffSRobert Johnston 		rv = TOPO_TYPE_UINT64_ARRAY;
19988045cffSRobert Johnston 	} else if (xmlStrcmp(str, (xmlChar *)String_Arr) == 0) {
20088045cffSRobert Johnston 		rv = TOPO_TYPE_STRING_ARRAY;
20188045cffSRobert Johnston 	} else if (xmlStrcmp(str, (xmlChar *)FMRI_Arr) == 0) {
20288045cffSRobert Johnston 		rv = TOPO_TYPE_FMRI_ARRAY;
2037aec1d6eScindi 	} else {
2040eb822a1Scindi 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
205738c43b5SEric Schrock 		    "Unrecognized type attribute value '%s'.\n", str);
2067aec1d6eScindi 		(void) topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE);
207738c43b5SEric Schrock 		xmlFree(str);
2087aec1d6eScindi 		return (TOPO_TYPE_INVALID);
2097aec1d6eScindi 	}
2107aec1d6eScindi 	xmlFree(str);
2117aec1d6eScindi 	return (rv);
2127aec1d6eScindi }
2137aec1d6eScindi 
2147aec1d6eScindi static int
xlate_common(topo_mod_t * mp,xmlNodePtr xn,topo_type_t ptype,nvlist_t * nvl,const char * name)2154557a2a1Srobj xlate_common(topo_mod_t *mp, xmlNodePtr xn, topo_type_t ptype, nvlist_t *nvl,
2164557a2a1Srobj     const char *name)
2174557a2a1Srobj {
21844d6604fSRobert Mustacchi 	int rv = 0;
2194557a2a1Srobj 	uint64_t ui;
220c184cb88SRob Johnston 	double dbl;
22188045cffSRobert Johnston 	uint_t i = 0, nelems = 0;
2224557a2a1Srobj 	nvlist_t *fmri;
2234557a2a1Srobj 	xmlChar *str;
22488045cffSRobert Johnston 	char **strarrbuf;
22588045cffSRobert Johnston 	void *arrbuf;
22688045cffSRobert Johnston 	nvlist_t **nvlarrbuf;
22788045cffSRobert Johnston 	xmlNodePtr cn;
2284557a2a1Srobj 
22988045cffSRobert Johnston 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "xlate_common(name=%s)\n", name);
2304557a2a1Srobj 	switch (ptype) {
2314557a2a1Srobj 	case TOPO_TYPE_INT32:
2324557a2a1Srobj 		if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
2334557a2a1Srobj 			return (-1);
2344557a2a1Srobj 		rv = nvlist_add_int32(nvl, name, (int32_t)ui);
2354557a2a1Srobj 		break;
2364557a2a1Srobj 	case TOPO_TYPE_UINT32:
2374557a2a1Srobj 		if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
2384557a2a1Srobj 			return (-1);
2394557a2a1Srobj 		rv = nvlist_add_uint32(nvl, name, (uint32_t)ui);
2404557a2a1Srobj 		break;
2414557a2a1Srobj 	case TOPO_TYPE_INT64:
2424557a2a1Srobj 		if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
2434557a2a1Srobj 			return (-1);
2444557a2a1Srobj 		rv = nvlist_add_int64(nvl, name, (int64_t)ui);
2454557a2a1Srobj 		break;
2464557a2a1Srobj 	case TOPO_TYPE_UINT64:
2474557a2a1Srobj 		if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
2484557a2a1Srobj 			return (-1);
2494557a2a1Srobj 		rv = nvlist_add_uint64(nvl, name, ui);
2504557a2a1Srobj 		break;
251c184cb88SRob Johnston 	case TOPO_TYPE_DOUBLE:
252c184cb88SRob Johnston 		if (xmlattr_to_double(mp, xn, Value, &dbl) < 0)
253c184cb88SRob Johnston 			return (-1);
254c184cb88SRob Johnston 		rv = nvlist_add_double(nvl, name, dbl);
255c184cb88SRob Johnston 		break;
2564557a2a1Srobj 	case TOPO_TYPE_FMRI:
2574557a2a1Srobj 		if (xmlattr_to_fmri(mp, xn, Value, &fmri) < 0)
2584557a2a1Srobj 			return (-1);
2594557a2a1Srobj 		rv = nvlist_add_nvlist(nvl, name, fmri);
2604557a2a1Srobj 		nvlist_free(fmri);
2614557a2a1Srobj 		break;
2624557a2a1Srobj 	case TOPO_TYPE_STRING:
2634557a2a1Srobj 		if ((str = xmlGetProp(xn, (xmlChar *)Value)) == NULL)
2644557a2a1Srobj 			return (-1);
2654557a2a1Srobj 		rv = nvlist_add_string(nvl, name, (char *)str);
2664557a2a1Srobj 		xmlFree(str);
2674557a2a1Srobj 		break;
26888045cffSRobert Johnston 	case TOPO_TYPE_INT32_ARRAY:
26988045cffSRobert Johnston 	case TOPO_TYPE_UINT32_ARRAY:
27088045cffSRobert Johnston 	case TOPO_TYPE_INT64_ARRAY:
27188045cffSRobert Johnston 	case TOPO_TYPE_UINT64_ARRAY:
27288045cffSRobert Johnston 	case TOPO_TYPE_STRING_ARRAY:
27388045cffSRobert Johnston 	case TOPO_TYPE_FMRI_ARRAY:
27488045cffSRobert Johnston 		for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next)
27588045cffSRobert Johnston 			if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
27688045cffSRobert Johnston 			    (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0))
27788045cffSRobert Johnston 				nelems++;
27888045cffSRobert Johnston 
27988045cffSRobert Johnston 		if (nelems < 1) {
28088045cffSRobert Johnston 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "No <propitem> "
28128e90476SBen Sims 			    "or <argitem> elements found for array val");
28288045cffSRobert Johnston 			return (-1);
28388045cffSRobert Johnston 		}
28488045cffSRobert Johnston 		break;
2854557a2a1Srobj 	default:
2864557a2a1Srobj 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
28788045cffSRobert Johnston 		    "Unrecognized type attribute (ptype = %d)\n", ptype);
2884557a2a1Srobj 		return (topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE));
2894557a2a1Srobj 	}
29088045cffSRobert Johnston 
29188045cffSRobert Johnston 	switch (ptype) {
29288045cffSRobert Johnston 	case TOPO_TYPE_INT32_ARRAY:
29328e90476SBen Sims 		if ((arrbuf = topo_mod_alloc(mp, (nelems * sizeof (int32_t))))
29428e90476SBen Sims 		    == NULL)
29528e90476SBen Sims 			return (topo_mod_seterrno(mp, ETOPO_NOMEM));
29688045cffSRobert Johnston 		for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
29788045cffSRobert Johnston 			if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
29888045cffSRobert Johnston 			    (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
29988045cffSRobert Johnston 
300ebee07ffSRob Johnston 				if (xmlattr_to_int(mp, cn, Value, &ui) < 0)
30188045cffSRobert Johnston 					return (-1);
302ebee07ffSRob Johnston 				((int32_t *)arrbuf)[i++] = (int32_t)ui;
30388045cffSRobert Johnston 			}
30488045cffSRobert Johnston 		}
30588045cffSRobert Johnston 
30688045cffSRobert Johnston 		rv = nvlist_add_int32_array(nvl, name, (int32_t *)arrbuf,
30788045cffSRobert Johnston 		    nelems);
30828e90476SBen Sims 		topo_mod_free(mp, arrbuf, (nelems * sizeof (int32_t)));
30988045cffSRobert Johnston 		break;
31088045cffSRobert Johnston 	case TOPO_TYPE_UINT32_ARRAY:
31128e90476SBen Sims 		if ((arrbuf = topo_mod_alloc(mp, (nelems * sizeof (uint32_t))))
31228e90476SBen Sims 		    == NULL)
31328e90476SBen Sims 			return (topo_mod_seterrno(mp, ETOPO_NOMEM));
31488045cffSRobert Johnston 		for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
31588045cffSRobert Johnston 			if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
31688045cffSRobert Johnston 			    (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
31788045cffSRobert Johnston 
318ebee07ffSRob Johnston 				if (xmlattr_to_int(mp, cn, Value, &ui) < 0)
31988045cffSRobert Johnston 					return (-1);
320ebee07ffSRob Johnston 				((uint32_t *)arrbuf)[i++] = (uint32_t)ui;
32188045cffSRobert Johnston 			}
32288045cffSRobert Johnston 		}
32388045cffSRobert Johnston 
32488045cffSRobert Johnston 		rv = nvlist_add_uint32_array(nvl, name, (uint32_t *)arrbuf,
32588045cffSRobert Johnston 		    nelems);
32628e90476SBen Sims 		topo_mod_free(mp, arrbuf, (nelems * sizeof (uint32_t)));
32788045cffSRobert Johnston 		break;
32888045cffSRobert Johnston 	case TOPO_TYPE_INT64_ARRAY:
32928e90476SBen Sims 		if ((arrbuf = topo_mod_alloc(mp, (nelems * sizeof (int64_t))))
33028e90476SBen Sims 		    == NULL)
33128e90476SBen Sims 			return (topo_mod_seterrno(mp, ETOPO_NOMEM));
33288045cffSRobert Johnston 		for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
33388045cffSRobert Johnston 			if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
33488045cffSRobert Johnston 			    (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
33588045cffSRobert Johnston 
336ebee07ffSRob Johnston 				if (xmlattr_to_int(mp, cn, Value, &ui) < 0)
33788045cffSRobert Johnston 					return (-1);
338ebee07ffSRob Johnston 				((int64_t *)arrbuf)[i++] = (int64_t)ui;
33988045cffSRobert Johnston 			}
34088045cffSRobert Johnston 		}
34188045cffSRobert Johnston 
34288045cffSRobert Johnston 		rv = nvlist_add_int64_array(nvl, name, (int64_t *)arrbuf,
34388045cffSRobert Johnston 		    nelems);
34428e90476SBen Sims 		topo_mod_free(mp, arrbuf, (nelems * sizeof (int64_t)));
34588045cffSRobert Johnston 		break;
34688045cffSRobert Johnston 	case TOPO_TYPE_UINT64_ARRAY:
34728e90476SBen Sims 		if ((arrbuf = topo_mod_alloc(mp, (nelems * sizeof (uint64_t))))
34828e90476SBen Sims 		    == NULL)
34928e90476SBen Sims 			return (topo_mod_seterrno(mp, ETOPO_NOMEM));
35088045cffSRobert Johnston 		for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
35188045cffSRobert Johnston 			if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
35288045cffSRobert Johnston 			    (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
35388045cffSRobert Johnston 
354ebee07ffSRob Johnston 				if (xmlattr_to_int(mp, cn, Value, &ui) < 0)
35588045cffSRobert Johnston 					return (-1);
356ebee07ffSRob Johnston 				((uint64_t *)arrbuf)[i++] = ui;
35788045cffSRobert Johnston 			}
35888045cffSRobert Johnston 		}
35988045cffSRobert Johnston 
36088045cffSRobert Johnston 		rv = nvlist_add_uint64_array(nvl, name, arrbuf,
36188045cffSRobert Johnston 		    nelems);
36228e90476SBen Sims 		topo_mod_free(mp, arrbuf, (nelems * sizeof (uint64_t)));
36388045cffSRobert Johnston 		break;
36488045cffSRobert Johnston 	case TOPO_TYPE_STRING_ARRAY:
36528e90476SBen Sims 		if ((strarrbuf = topo_mod_alloc(mp, (nelems * sizeof (char *))))
36628e90476SBen Sims 		    == NULL)
36728e90476SBen Sims 			return (topo_mod_seterrno(mp, ETOPO_NOMEM));
36888045cffSRobert Johnston 		for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
36988045cffSRobert Johnston 			if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
37088045cffSRobert Johnston 			    (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
37188045cffSRobert Johnston 
37288045cffSRobert Johnston 				if ((str = xmlGetProp(cn, (xmlChar *)Value))
37388045cffSRobert Johnston 				    == NULL)
37488045cffSRobert Johnston 					return (-1);
37588045cffSRobert Johnston 
37688045cffSRobert Johnston 				strarrbuf[i++] =
37788045cffSRobert Johnston 				    topo_mod_strdup(mp, (const char *)str);
37888045cffSRobert Johnston 				xmlFree(str);
37988045cffSRobert Johnston 			}
38088045cffSRobert Johnston 		}
38188045cffSRobert Johnston 
38288045cffSRobert Johnston 		rv = nvlist_add_string_array(nvl, name, strarrbuf, nelems);
383e2336878SRob Johnston 		topo_mod_strfreev(mp, strarrbuf, nelems);
38488045cffSRobert Johnston 		break;
38588045cffSRobert Johnston 	case TOPO_TYPE_FMRI_ARRAY:
38628e90476SBen Sims 		if ((nvlarrbuf = topo_mod_alloc(mp, (nelems *
38728e90476SBen Sims 		    sizeof (nvlist_t *)))) == NULL)
38828e90476SBen Sims 			return (topo_mod_seterrno(mp, ETOPO_NOMEM));
38988045cffSRobert Johnston 		for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
39088045cffSRobert Johnston 			if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
39188045cffSRobert Johnston 			    (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
39288045cffSRobert Johnston 
39328e90476SBen Sims 				if ((str = xmlGetProp(cn, (xmlChar *)Value))
39488045cffSRobert Johnston 				    == NULL)
39588045cffSRobert Johnston 					return (-1);
39688045cffSRobert Johnston 
39788045cffSRobert Johnston 				if (topo_mod_str2nvl(mp, (const char *)str,
39888045cffSRobert Johnston 				    &(nvlarrbuf[i++])) < 0) {
39988045cffSRobert Johnston 					xmlFree(str);
40088045cffSRobert Johnston 					return (-1);
40188045cffSRobert Johnston 				}
40288045cffSRobert Johnston 				xmlFree(str);
40388045cffSRobert Johnston 			}
40488045cffSRobert Johnston 		}
40588045cffSRobert Johnston 
40688045cffSRobert Johnston 		rv = nvlist_add_nvlist_array(nvl, name, nvlarrbuf,
40788045cffSRobert Johnston 		    nelems);
40828e90476SBen Sims 		topo_mod_free(mp, nvlarrbuf, (nelems * sizeof (nvlist_t *)));
40988045cffSRobert Johnston 		break;
41044d6604fSRobert Mustacchi 	default:
41144d6604fSRobert Mustacchi 		/*
41244d6604fSRobert Mustacchi 		 * Invalid types were handled in the switch statement above
41344d6604fSRobert Mustacchi 		 * this. Items in this case don't need additional processing.
41444d6604fSRobert Mustacchi 		 */
41544d6604fSRobert Mustacchi 		break;
41688045cffSRobert Johnston 	}
41788045cffSRobert Johnston 
4184557a2a1Srobj 	if (rv != 0) {
4194557a2a1Srobj 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
4204557a2a1Srobj 		    "Nvlist construction failed.\n");
4214557a2a1Srobj 		return (topo_mod_seterrno(mp, ETOPO_NOMEM));
4224557a2a1Srobj 	} else
4234557a2a1Srobj 		return (0);
4244557a2a1Srobj }
4254557a2a1Srobj 
4264557a2a1Srobj static int
xmlprop_xlate(topo_mod_t * mp,xmlNodePtr xn,nvlist_t * nvl)4277aec1d6eScindi xmlprop_xlate(topo_mod_t *mp, xmlNodePtr xn, nvlist_t *nvl)
4287aec1d6eScindi {
4297aec1d6eScindi 	topo_type_t ptype;
4307aec1d6eScindi 	xmlChar *str;
4317aec1d6eScindi 
4324557a2a1Srobj 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "xmlprop_xlate\n");
4337aec1d6eScindi 	if ((str = xmlGetProp(xn, (xmlChar *)Immutable)) != NULL) {
4347aec1d6eScindi 		if (xmlStrcmp(str, (xmlChar *)False) == 0)
4350eb822a1Scindi 			(void) nvlist_add_boolean_value(nvl, INV_IMMUTE,
4360eb822a1Scindi 			    B_FALSE);
4377aec1d6eScindi 		else
4380eb822a1Scindi 			(void) nvlist_add_boolean_value(nvl, INV_IMMUTE,
4390eb822a1Scindi 			    B_TRUE);
4407aec1d6eScindi 		xmlFree(str);
4410eb822a1Scindi 	} else {
4420eb822a1Scindi 		(void) nvlist_add_boolean_value(nvl, INV_IMMUTE, B_TRUE);
4437aec1d6eScindi 	}
4440eb822a1Scindi 
4454557a2a1Srobj 	if ((ptype = xmlattr_to_type(mp, xn, (xmlChar *)Type))
4464557a2a1Srobj 	    == TOPO_TYPE_INVALID)
4477aec1d6eScindi 		return (-1);
4484557a2a1Srobj 
4494557a2a1Srobj 	if (nvlist_add_int32(nvl, INV_PVALTYPE, ptype) != 0)
4507aec1d6eScindi 		return (-1);
4514557a2a1Srobj 
4524557a2a1Srobj 	return (xlate_common(mp, xn, ptype, nvl, INV_PVAL));
4537aec1d6eScindi }
4547aec1d6eScindi 
4557aec1d6eScindi static int
dependent_create(topo_mod_t * mp,tf_info_t * xinfo,tf_pad_t * pad,xmlNodePtr dxn,tnode_t * ptn)4567aec1d6eScindi dependent_create(topo_mod_t *mp,
4577aec1d6eScindi     tf_info_t *xinfo, tf_pad_t *pad, xmlNodePtr dxn, tnode_t *ptn)
4587aec1d6eScindi {
4597aec1d6eScindi 	tf_rdata_t *rp, *pp, *np;
4607aec1d6eScindi 	xmlChar *grptype;
4617aec1d6eScindi 	int sibs = 0;
4627aec1d6eScindi 
4634557a2a1Srobj 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "dependent_create\n");
4647aec1d6eScindi 	if ((grptype = xmlGetProp(dxn, (xmlChar *)Grouping)) == NULL) {
4650eb822a1Scindi 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
4660eb822a1Scindi 		    "Dependents missing grouping attribute");
4677aec1d6eScindi 		return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
4687aec1d6eScindi 	}
4697aec1d6eScindi 
4707aec1d6eScindi 	pp = NULL;
4717aec1d6eScindi 	if (xmlStrcmp(grptype, (xmlChar *)Siblings) == 0) {
4727aec1d6eScindi 		rp = pad->tpad_sibs;
4737aec1d6eScindi 		sibs++;
4747aec1d6eScindi 	} else if (xmlStrcmp(grptype, (xmlChar *)Children) == 0) {
4757aec1d6eScindi 		rp = pad->tpad_child;
4767aec1d6eScindi 	} else {
4770eb822a1Scindi 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
4787aec1d6eScindi 		    "Dependents have bogus grouping attribute");
4797aec1d6eScindi 		xmlFree(grptype);
4807aec1d6eScindi 		return (topo_mod_seterrno(mp, ETOPO_PRSR_BADGRP));
4817aec1d6eScindi 	}
4827aec1d6eScindi 	xmlFree(grptype);
4837aec1d6eScindi 	/* Add processed dependents to the tail of the list */
4847aec1d6eScindi 	while (rp != NULL) {
4857aec1d6eScindi 		pp = rp;
4867aec1d6eScindi 		rp = rp->rd_next;
4877aec1d6eScindi 	}
4887aec1d6eScindi 	if ((np = topo_xml_walk(mp, xinfo, dxn, ptn)) == NULL) {
4890eb822a1Scindi 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
4907aec1d6eScindi 		    "error within dependent .xml topology: "
4917aec1d6eScindi 		    "%s\n", topo_strerror(topo_mod_errno(mp)));
4927aec1d6eScindi 		return (-1);
4937aec1d6eScindi 	}
4947aec1d6eScindi 	if (pp != NULL)
4957aec1d6eScindi 		pp->rd_next = np;
4967aec1d6eScindi 	else if (sibs == 1)
4977aec1d6eScindi 		pad->tpad_sibs = np;
4987aec1d6eScindi 	else
4997aec1d6eScindi 		pad->tpad_child = np;
5007aec1d6eScindi 	return (0);
5017aec1d6eScindi }
5027aec1d6eScindi 
5037aec1d6eScindi static int
dependents_create(topo_mod_t * mp,tf_info_t * xinfo,tf_pad_t * pad,xmlNodePtr pxn,tnode_t * ptn)5047aec1d6eScindi dependents_create(topo_mod_t *mp,
5057aec1d6eScindi     tf_info_t *xinfo, tf_pad_t *pad, xmlNodePtr pxn, tnode_t *ptn)
5067aec1d6eScindi {
5077aec1d6eScindi 	xmlNodePtr cn;
5087aec1d6eScindi 
5094557a2a1Srobj 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "dependents_create\n");
5107aec1d6eScindi 	for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
5117aec1d6eScindi 		if (xmlStrcmp(cn->name, (xmlChar *)Dependents) == 0) {
5127aec1d6eScindi 			if (dependent_create(mp, xinfo, pad, cn, ptn) < 0)
5137aec1d6eScindi 				return (-1);
5147aec1d6eScindi 		}
5157aec1d6eScindi 	}
5167aec1d6eScindi 	return (0);
5177aec1d6eScindi }
5187aec1d6eScindi 
5197aec1d6eScindi static int
prop_create(topo_mod_t * mp,nvlist_t * pfmri,tnode_t * ptn,const char * gnm,const char * pnm,topo_type_t ptype,int flag)5207aec1d6eScindi prop_create(topo_mod_t *mp,
5217aec1d6eScindi     nvlist_t *pfmri, tnode_t *ptn, const char *gnm, const char *pnm,
5227aec1d6eScindi     topo_type_t ptype, int flag)
5237aec1d6eScindi {
52488045cffSRobert Johnston 	nvlist_t *fmri, **fmriarr;
52588045cffSRobert Johnston 	uint32_t ui32, *ui32arr;
52688045cffSRobert Johnston 	uint64_t ui64, *ui64arr;
52788045cffSRobert Johnston 	int32_t i32, *i32arr;
52888045cffSRobert Johnston 	int64_t i64, *i64arr;
529c184cb88SRob Johnston 	double dbl;
53088045cffSRobert Johnston 	uint_t nelem;
53188045cffSRobert Johnston 	char *str, **strarr;
5327aec1d6eScindi 	int err, e;
5337aec1d6eScindi 
534825ba0f2Srobj 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "prop_create(pgrp = %s, "
535825ba0f2Srobj 	    "prop = %s)\n", gnm, pnm);
5367aec1d6eScindi 	switch (ptype) {
5377aec1d6eScindi 	case TOPO_TYPE_INT32:
5387aec1d6eScindi 		e = nvlist_lookup_int32(pfmri, INV_PVAL, &i32);
5397aec1d6eScindi 		break;
5407aec1d6eScindi 	case TOPO_TYPE_UINT32:
5417aec1d6eScindi 		e = nvlist_lookup_uint32(pfmri, INV_PVAL, &ui32);
5427aec1d6eScindi 		break;
5437aec1d6eScindi 	case TOPO_TYPE_INT64:
5447aec1d6eScindi 		e = nvlist_lookup_int64(pfmri, INV_PVAL, &i64);
5457aec1d6eScindi 		break;
5467aec1d6eScindi 	case TOPO_TYPE_UINT64:
5477aec1d6eScindi 		e = nvlist_lookup_uint64(pfmri, INV_PVAL, &ui64);
5487aec1d6eScindi 		break;
549c184cb88SRob Johnston 	case TOPO_TYPE_DOUBLE:
550c184cb88SRob Johnston 		e = nvlist_lookup_double(pfmri, INV_PVAL, &dbl);
551c184cb88SRob Johnston 		break;
5527aec1d6eScindi 	case TOPO_TYPE_FMRI:
5537aec1d6eScindi 		e = nvlist_lookup_nvlist(pfmri, INV_PVAL, &fmri);
5547aec1d6eScindi 		break;
5557aec1d6eScindi 	case TOPO_TYPE_STRING:
5567aec1d6eScindi 		e = nvlist_lookup_string(pfmri, INV_PVAL, &str);
5577aec1d6eScindi 		break;
55888045cffSRobert Johnston 	case TOPO_TYPE_INT32_ARRAY:
55988045cffSRobert Johnston 		e = nvlist_lookup_int32_array(pfmri, INV_PVAL, &i32arr, &nelem);
56088045cffSRobert Johnston 		break;
56188045cffSRobert Johnston 	case TOPO_TYPE_UINT32_ARRAY:
56288045cffSRobert Johnston 		e = nvlist_lookup_uint32_array(pfmri, INV_PVAL, &ui32arr,
56388045cffSRobert Johnston 		    &nelem);
56488045cffSRobert Johnston 		break;
56588045cffSRobert Johnston 	case TOPO_TYPE_INT64_ARRAY:
56688045cffSRobert Johnston 		e = nvlist_lookup_int64_array(pfmri, INV_PVAL, &i64arr,
56788045cffSRobert Johnston 		    &nelem);
56888045cffSRobert Johnston 		break;
56988045cffSRobert Johnston 	case TOPO_TYPE_UINT64_ARRAY:
57088045cffSRobert Johnston 		e = nvlist_lookup_uint64_array(pfmri, INV_PVAL, &ui64arr,
57188045cffSRobert Johnston 		    &nelem);
57288045cffSRobert Johnston 		break;
57388045cffSRobert Johnston 	case TOPO_TYPE_STRING_ARRAY:
57488045cffSRobert Johnston 		e = nvlist_lookup_string_array(pfmri, INV_PVAL, &strarr,
57588045cffSRobert Johnston 		    &nelem);
57688045cffSRobert Johnston 		break;
57788045cffSRobert Johnston 	case TOPO_TYPE_FMRI_ARRAY:
57888045cffSRobert Johnston 		e = nvlist_lookup_nvlist_array(pfmri, INV_PVAL, &fmriarr,
57988045cffSRobert Johnston 		    &nelem);
58088045cffSRobert Johnston 		break;
5817aec1d6eScindi 	default:
5827aec1d6eScindi 		e = ETOPO_PRSR_BADTYPE;
58344d6604fSRobert Mustacchi 		break;
5847aec1d6eScindi 	}
5857aec1d6eScindi 	if (e != 0) {
5860eb822a1Scindi 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
5874557a2a1Srobj 		    "prop_create: prop value lookup failed.\n");
5887aec1d6eScindi 		return (topo_mod_seterrno(mp, e));
5897aec1d6eScindi 	}
5907aec1d6eScindi 	switch (ptype) {
5917aec1d6eScindi 	case TOPO_TYPE_INT32:
5927aec1d6eScindi 		e = topo_prop_set_int32(ptn, gnm, pnm, flag, i32, &err);
5937aec1d6eScindi 		break;
5947aec1d6eScindi 	case TOPO_TYPE_UINT32:
5957aec1d6eScindi 		e = topo_prop_set_uint32(ptn, gnm, pnm, flag, ui32, &err);
5967aec1d6eScindi 		break;
5977aec1d6eScindi 	case TOPO_TYPE_INT64:
5987aec1d6eScindi 		e = topo_prop_set_int64(ptn, gnm, pnm, flag, i64, &err);
5997aec1d6eScindi 		break;
6007aec1d6eScindi 	case TOPO_TYPE_UINT64:
6017aec1d6eScindi 		e = topo_prop_set_uint64(ptn, gnm, pnm, flag, ui64, &err);
6027aec1d6eScindi 		break;
603c184cb88SRob Johnston 	case TOPO_TYPE_DOUBLE:
604c184cb88SRob Johnston 		e = topo_prop_set_double(ptn, gnm, pnm, flag, dbl, &err);
605c184cb88SRob Johnston 		break;
6067aec1d6eScindi 	case TOPO_TYPE_FMRI:
6077aec1d6eScindi 		e = topo_prop_set_fmri(ptn, gnm, pnm, flag, fmri, &err);
6087aec1d6eScindi 		break;
6097aec1d6eScindi 	case TOPO_TYPE_STRING:
6107aec1d6eScindi 		e = topo_prop_set_string(ptn, gnm, pnm, flag, str, &err);
6117aec1d6eScindi 		break;
61288045cffSRobert Johnston 	case TOPO_TYPE_INT32_ARRAY:
61388045cffSRobert Johnston 		e = topo_prop_set_int32_array(ptn, gnm, pnm, flag, i32arr,
61488045cffSRobert Johnston 		    nelem, &err);
61588045cffSRobert Johnston 		break;
61688045cffSRobert Johnston 	case TOPO_TYPE_UINT32_ARRAY:
61788045cffSRobert Johnston 		e = topo_prop_set_uint32_array(ptn, gnm, pnm, flag, ui32arr,
61888045cffSRobert Johnston 		    nelem, &err);
61988045cffSRobert Johnston 		break;
62088045cffSRobert Johnston 	case TOPO_TYPE_INT64_ARRAY:
62188045cffSRobert Johnston 		e = topo_prop_set_int64_array(ptn, gnm, pnm, flag, i64arr,
62288045cffSRobert Johnston 		    nelem, &err);
62388045cffSRobert Johnston 		break;
62488045cffSRobert Johnston 	case TOPO_TYPE_UINT64_ARRAY:
62588045cffSRobert Johnston 		e = topo_prop_set_uint64_array(ptn, gnm, pnm, flag, ui64arr,
62688045cffSRobert Johnston 		    nelem, &err);
62788045cffSRobert Johnston 		break;
62888045cffSRobert Johnston 	case TOPO_TYPE_STRING_ARRAY:
62988045cffSRobert Johnston 		e = topo_prop_set_string_array(ptn, gnm, pnm, flag,
63088045cffSRobert Johnston 		    (const char **)strarr, nelem, &err);
63188045cffSRobert Johnston 		break;
63288045cffSRobert Johnston 	case TOPO_TYPE_FMRI_ARRAY:
63388045cffSRobert Johnston 		e = topo_prop_set_fmri_array(ptn, gnm, pnm, flag,
63488045cffSRobert Johnston 		    (const nvlist_t **)fmriarr, nelem, &err);
63588045cffSRobert Johnston 		break;
63644d6604fSRobert Mustacchi 	default:
63744d6604fSRobert Mustacchi 		e = ETOPO_PRSR_BADTYPE;
63844d6604fSRobert Mustacchi 		break;
6397aec1d6eScindi 	}
6400eb822a1Scindi 	if (e != 0 && err != ETOPO_PROP_DEFD) {
6410eb822a1Scindi 
6420eb822a1Scindi 		/*
6430eb822a1Scindi 		 * Some properties may have already been set
6440eb822a1Scindi 		 * in topo_node_bind() or topo_prop_inherit if we are
6450eb822a1Scindi 		 * enumerating from a static .xml file
6460eb822a1Scindi 		 */
6470eb822a1Scindi 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "prop set "
6480eb822a1Scindi 		    "failed %s/%s:%s\n", gnm, pnm, topo_strerror(err));
6497aec1d6eScindi 		return (topo_mod_seterrno(mp, err));
6507aec1d6eScindi 	}
6517aec1d6eScindi 	return (0);
6527aec1d6eScindi }
6537aec1d6eScindi 
6547aec1d6eScindi static int
props_create(topo_mod_t * mp,tnode_t * ptn,const char * gnm,nvlist_t ** props,int nprops)6557aec1d6eScindi props_create(topo_mod_t *mp,
6567aec1d6eScindi     tnode_t *ptn, const char *gnm, nvlist_t **props, int nprops)
6577aec1d6eScindi {
6587aec1d6eScindi 	topo_type_t ptype;
6597aec1d6eScindi 	boolean_t pim;
6607aec1d6eScindi 	char *pnm;
6617aec1d6eScindi 	int32_t i32;
6627aec1d6eScindi 	int flag;
6637aec1d6eScindi 	int pn;
6647aec1d6eScindi 	int e;
6657aec1d6eScindi 
666825ba0f2Srobj 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "props_create(pgrp = %s)\n",
667825ba0f2Srobj 	    gnm);
6687aec1d6eScindi 	for (pn = 0; pn < nprops; pn++) {
6697aec1d6eScindi 		e = nvlist_lookup_string(props[pn], INV_PNAME, &pnm);
6707aec1d6eScindi 		if (e != 0) {
6710eb822a1Scindi 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
6727aec1d6eScindi 			    "props create lookup (%s) failure: %s",
6734557a2a1Srobj 			    INV_PNAME, strerror(e));
6747aec1d6eScindi 			return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
6757aec1d6eScindi 		}
6767aec1d6eScindi 		e = nvlist_lookup_boolean_value(props[pn], INV_IMMUTE, &pim);
6777aec1d6eScindi 		if (e != 0) {
6780eb822a1Scindi 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
6797aec1d6eScindi 			    "props create lookup (%s) failure: %s",
6804557a2a1Srobj 			    INV_IMMUTE, strerror(e));
6817aec1d6eScindi 			return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
6827aec1d6eScindi 		}
6837aec1d6eScindi 		flag = (pim == B_TRUE) ?
6840eb822a1Scindi 		    TOPO_PROP_IMMUTABLE : TOPO_PROP_MUTABLE;
6857aec1d6eScindi 
6867aec1d6eScindi 		e = nvlist_lookup_int32(props[pn], INV_PVALTYPE, &i32);
6877aec1d6eScindi 		if (e != 0) {
6880eb822a1Scindi 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
6897aec1d6eScindi 			    "props create lookup (%s) failure: %s",
6904557a2a1Srobj 			    INV_PVALTYPE, strerror(e));
6917aec1d6eScindi 			return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
6927aec1d6eScindi 		}
6937aec1d6eScindi 		ptype = (topo_type_t)i32;
6947aec1d6eScindi 		if (prop_create(mp, props[pn], ptn, gnm, pnm, ptype, flag) < 0)
6957aec1d6eScindi 			return (-1);
6967aec1d6eScindi 	}
6977aec1d6eScindi 	return (0);
6987aec1d6eScindi }
6997aec1d6eScindi 
7007aec1d6eScindi static int
pgroups_create(topo_mod_t * mp,tf_pad_t * pad,tnode_t * ptn)7017aec1d6eScindi pgroups_create(topo_mod_t *mp, tf_pad_t *pad, tnode_t *ptn)
7027aec1d6eScindi {
7030eb822a1Scindi 	topo_pgroup_info_t pgi;
7047aec1d6eScindi 	nvlist_t **props;
7057aec1d6eScindi 	char *gnm;
7060eb822a1Scindi 	char *nmstab, *dstab;
7077aec1d6eScindi 	uint32_t rnprops, nprops;
7080eb822a1Scindi 	uint32_t gv;
7097aec1d6eScindi 	int pg;
7107aec1d6eScindi 	int e;
7117aec1d6eScindi 
712825ba0f2Srobj 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroups_create: %s=%d\n",
713825ba0f2Srobj 	    topo_node_name(ptn), topo_node_instance(ptn));
7147aec1d6eScindi 	for (pg = 0; pg < pad->tpad_pgcnt; pg++) {
7157aec1d6eScindi 		e = nvlist_lookup_string(pad->tpad_pgs[pg],
7167aec1d6eScindi 		    INV_PGRP_NAME, &gnm);
7177aec1d6eScindi 		if (e != 0) {
7180eb822a1Scindi 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
7194557a2a1Srobj 			    "pad lookup (%s) failed (%s).\n",
7204557a2a1Srobj 			    INV_PGRP_NAME, strerror(errno));
7217aec1d6eScindi 			return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
7227aec1d6eScindi 		}
7230eb822a1Scindi 		e = nvlist_lookup_string(pad->tpad_pgs[pg],
7240eb822a1Scindi 		    INV_PGRP_NMSTAB, &nmstab);
7257aec1d6eScindi 		if (e != 0) {
7260eb822a1Scindi 			if (e != ENOENT) {
7270eb822a1Scindi 				topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
7280eb822a1Scindi 				    "pad lookup (%s) "
7290eb822a1Scindi 				    "failed.\n", INV_PGRP_NMSTAB);
7300eb822a1Scindi 				return (topo_mod_seterrno(mp,
7310eb822a1Scindi 				    ETOPO_PRSR_NVPROP));
7320eb822a1Scindi 			} else {
7330eb822a1Scindi 				nmstab = TOPO_STABSTR_PRIVATE;
7340eb822a1Scindi 			}
7350eb822a1Scindi 		}
7360eb822a1Scindi 		e = nvlist_lookup_string(pad->tpad_pgs[pg],
7370eb822a1Scindi 		    INV_PGRP_DSTAB, &dstab);
7380eb822a1Scindi 		if (e != 0) {
7390eb822a1Scindi 			if (e != ENOENT) {
7400eb822a1Scindi 				topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
7410eb822a1Scindi 				    "pad lookup (%s) failed.\n",
7420eb822a1Scindi 				    INV_PGRP_DSTAB);
7430eb822a1Scindi 				return (topo_mod_seterrno(mp,
7440eb822a1Scindi 				    ETOPO_PRSR_NVPROP));
7450eb822a1Scindi 			} else {
7460eb822a1Scindi 				dstab = TOPO_STABSTR_PRIVATE;
7470eb822a1Scindi 			}
7480eb822a1Scindi 		}
7490eb822a1Scindi 		e = nvlist_lookup_uint32(pad->tpad_pgs[pg],
7500eb822a1Scindi 		    INV_PGRP_VER, &gv);
7510eb822a1Scindi 		if (e != 0) {
7520eb822a1Scindi 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
7530eb822a1Scindi 			    "pad lookup (%s) failed.\n",
7540eb822a1Scindi 			    INV_PGRP_VER);
7557aec1d6eScindi 			return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
7567aec1d6eScindi 		}
7570eb822a1Scindi 		pgi.tpi_name = gnm;
7580eb822a1Scindi 		pgi.tpi_namestab = topo_name2stability(nmstab);
7590eb822a1Scindi 		pgi.tpi_datastab = topo_name2stability(dstab);
7600eb822a1Scindi 		pgi.tpi_version = gv;
7610eb822a1Scindi 		if (topo_pgroup_create(ptn, &pgi, &e) != 0) {
7627aec1d6eScindi 			if (e != ETOPO_PROP_DEFD) {
7630eb822a1Scindi 				topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
7647aec1d6eScindi 				    "pgroups create failure: %s\n",
7657aec1d6eScindi 				    topo_strerror(e));
7667aec1d6eScindi 				return (-1);
7677aec1d6eScindi 			}
7687aec1d6eScindi 		}
7697aec1d6eScindi 		e = nvlist_lookup_uint32(pad->tpad_pgs[pg],
7707aec1d6eScindi 		    INV_PGRP_NPROP, &rnprops);
7714557a2a1Srobj 		/*
7724557a2a1Srobj 		 * The number of properties could be zero if the property
7734557a2a1Srobj 		 * group only contains propmethod declarations
7744557a2a1Srobj 		 */
7754557a2a1Srobj 		if (rnprops > 0) {
7767aec1d6eScindi 			e |= nvlist_lookup_nvlist_array(pad->tpad_pgs[pg],
7777aec1d6eScindi 			    INV_PGRP_ALLPROPS, &props, &nprops);
7787aec1d6eScindi 			if (rnprops != nprops) {
7790eb822a1Scindi 				topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
7800eb822a1Scindi 				    "recorded number of props %d does not "
7817aec1d6eScindi 				    "match number of props recorded %d.\n",
7827aec1d6eScindi 				    rnprops, nprops);
7837aec1d6eScindi 			}
7847aec1d6eScindi 			if (props_create(mp, ptn, gnm, props, nprops) < 0)
7857aec1d6eScindi 				return (-1);
7867aec1d6eScindi 		}
7874557a2a1Srobj 	}
7887aec1d6eScindi 	return (0);
7897aec1d6eScindi }
7907aec1d6eScindi 
7917aec1d6eScindi static nvlist_t *
pval_record(topo_mod_t * mp,xmlNodePtr xn)7927aec1d6eScindi pval_record(topo_mod_t *mp, xmlNodePtr xn)
7937aec1d6eScindi {
7947aec1d6eScindi 	nvlist_t *pnvl = NULL;
7957aec1d6eScindi 	xmlChar *pname;
7967aec1d6eScindi 
7974557a2a1Srobj 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pval_record\n");
7987aec1d6eScindi 	if ((pname = xmlGetProp(xn, (xmlChar *)Name)) == NULL) {
7990eb822a1Scindi 		topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
8000eb822a1Scindi 		    "propval lacks a name\n");
8017aec1d6eScindi 		(void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
8027aec1d6eScindi 		return (NULL);
8037aec1d6eScindi 	}
8047aec1d6eScindi 	if (topo_mod_nvalloc(mp, &pnvl, NV_UNIQUE_NAME) < 0) {
8057aec1d6eScindi 		xmlFree(pname);
8067aec1d6eScindi 		return (NULL);
8077aec1d6eScindi 	}
8087aec1d6eScindi 	if (nvlist_add_string(pnvl, INV_PNAME, (char *)pname) < 0) {
8097aec1d6eScindi 		xmlFree(pname);
8107aec1d6eScindi 		nvlist_free(pnvl);
8117aec1d6eScindi 		return (NULL);
8127aec1d6eScindi 	}
8137aec1d6eScindi 	xmlFree(pname);
8147aec1d6eScindi 	/* FMXXX stability of the property name */
8157aec1d6eScindi 
8167aec1d6eScindi 	if (xmlprop_xlate(mp, xn, pnvl) < 0) {
8177aec1d6eScindi 		nvlist_free(pnvl);
8187aec1d6eScindi 		return (NULL);
8197aec1d6eScindi 	}
8207aec1d6eScindi 	return (pnvl);
8217aec1d6eScindi }
8227aec1d6eScindi 
8234557a2a1Srobj 
8244557a2a1Srobj struct propmeth_data {
8254557a2a1Srobj 	const char *pg_name;
8264557a2a1Srobj 	const char *prop_name;
8274557a2a1Srobj 	topo_type_t prop_type;
8284557a2a1Srobj 	const char *meth_name;
8294557a2a1Srobj 	topo_version_t meth_ver;
8304557a2a1Srobj 	nvlist_t *arg_nvl;
8314557a2a1Srobj };
8324557a2a1Srobj 
8337aec1d6eScindi static int
register_method(topo_mod_t * mp,tnode_t * ptn,struct propmeth_data * meth)8344557a2a1Srobj register_method(topo_mod_t *mp, tnode_t *ptn, struct propmeth_data *meth)
8354557a2a1Srobj {
8364557a2a1Srobj 	int err;
8374557a2a1Srobj 
8384557a2a1Srobj 	if (topo_prop_method_version_register(ptn, meth->pg_name,
8394557a2a1Srobj 	    meth->prop_name, meth->prop_type, meth->meth_name, meth->meth_ver,
8404557a2a1Srobj 	    meth->arg_nvl, &err) != 0) {
8414557a2a1Srobj 
8424557a2a1Srobj 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "failed to register "
8432eeaed14Srobj 		    "propmethod %s for property \"%s\" in propgrp %s on node "
8442eeaed14Srobj 		    "%s=%d (%s)\n",
8452eeaed14Srobj 		    meth->meth_name, meth->prop_name, meth->pg_name,
8464557a2a1Srobj 		    topo_node_name(ptn), topo_node_instance(ptn),
8474557a2a1Srobj 		    topo_strerror(err));
8484557a2a1Srobj 		return (-1);
8494557a2a1Srobj 	}
8504557a2a1Srobj 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
8514557a2a1Srobj 	    "registered method %s on %s=%d\n",
8524557a2a1Srobj 	    meth->meth_name, topo_node_name(ptn), topo_node_instance(ptn));
8534557a2a1Srobj 
8544557a2a1Srobj 	return (0);
8554557a2a1Srobj }
8564557a2a1Srobj 
8574557a2a1Srobj static int
pmeth_record(topo_mod_t * mp,const char * pg_name,xmlNodePtr xn,tnode_t * tn,const char * rname,const char * ppgrp_name)8584557a2a1Srobj pmeth_record(topo_mod_t *mp, const char *pg_name, xmlNodePtr xn, tnode_t *tn,
8594557a2a1Srobj     const char *rname, const char *ppgrp_name)
8604557a2a1Srobj {
8614557a2a1Srobj 	nvlist_t *arg_nvl = NULL;
8624557a2a1Srobj 	xmlNodePtr cn;
8634557a2a1Srobj 	xmlChar *meth_name = NULL, *prop_name = NULL;
8644557a2a1Srobj 	xmlChar *arg_name = NULL;
865e5dcf7beSRobert Johnston 	uint64_t meth_ver, is_mutable = 0, is_nonvolatile = 0;
8664557a2a1Srobj 	topo_type_t prop_type;
8674557a2a1Srobj 	struct propmeth_data meth;
868825ba0f2Srobj 	int ret = 0, err;
8694557a2a1Srobj 	topo_type_t ptype;
8704557a2a1Srobj 	tnode_t *tmp;
8714557a2a1Srobj 
872825ba0f2Srobj 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pmeth_record: %s=%d "
873825ba0f2Srobj 	    "(pgrp=%s)\n", topo_node_name(tn), topo_node_instance(tn), pg_name);
8744557a2a1Srobj 
8754557a2a1Srobj 	/*
8764557a2a1Srobj 	 * Get propmethod attribute values
8774557a2a1Srobj 	 */
8784557a2a1Srobj 	if ((meth_name = xmlGetProp(xn, (xmlChar *)Name)) == NULL) {
8794557a2a1Srobj 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
8804557a2a1Srobj 		    "propmethod element lacks a name attribute\n");
8814557a2a1Srobj 		return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
8824557a2a1Srobj 	}
8834557a2a1Srobj 	if (xmlattr_to_int(mp, xn, Version, &meth_ver) < 0) {
8844557a2a1Srobj 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
8854557a2a1Srobj 		    "propmethod element lacks version attribute\n");
8864557a2a1Srobj 		ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
8874557a2a1Srobj 		goto pmr_done;
8884557a2a1Srobj 	}
889825ba0f2Srobj 	/*
890e5dcf7beSRobert Johnston 	 * The "mutable" and "nonvoltile" attributes are optional.  If not
891e5dcf7beSRobert Johnston 	 * specified we default to false (0)
892825ba0f2Srobj 	 */
893825ba0f2Srobj 	(void) xmlattr_to_int(mp, xn, Mutable, &is_mutable);
894e5dcf7beSRobert Johnston 	(void) xmlattr_to_int(mp, xn, Nonvolatile, &is_nonvolatile);
895825ba0f2Srobj 
8964557a2a1Srobj 	if ((prop_name = xmlGetProp(xn, (xmlChar *)Propname)) == NULL) {
8974557a2a1Srobj 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
8984557a2a1Srobj 		    "propmethod element lacks propname attribute\n");
8994557a2a1Srobj 		ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
9004557a2a1Srobj 		goto pmr_done;
9014557a2a1Srobj 	}
9024557a2a1Srobj 	if ((prop_type = xmlattr_to_type(mp, xn, (xmlChar *)Proptype))
9034557a2a1Srobj 	    == TOPO_TYPE_INVALID) {
9044557a2a1Srobj 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
9054557a2a1Srobj 		    "error decoding proptype attribute\n");
9064557a2a1Srobj 		ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
9074557a2a1Srobj 		goto pmr_done;
9084557a2a1Srobj 	}
9094557a2a1Srobj 
9104557a2a1Srobj 	/*
9114557a2a1Srobj 	 * Allocate method argument nvlist
9124557a2a1Srobj 	 */
9134557a2a1Srobj 	if (topo_mod_nvalloc(mp, &arg_nvl, NV_UNIQUE_NAME) < 0) {
9144557a2a1Srobj 		ret = topo_mod_seterrno(mp, ETOPO_NOMEM);
9154557a2a1Srobj 		goto pmr_done;
9164557a2a1Srobj 	}
9174557a2a1Srobj 
9184557a2a1Srobj 	/*
9194557a2a1Srobj 	 * Iterate through the argval nodes and build the argval nvlist
9204557a2a1Srobj 	 */
9214557a2a1Srobj 	for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
9224557a2a1Srobj 		if (xmlStrcmp(cn->name, (xmlChar *)Argval) == 0) {
9234557a2a1Srobj 			topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
9244557a2a1Srobj 			    "found argval element\n");
9254557a2a1Srobj 			if ((arg_name = xmlGetProp(cn, (xmlChar *)Name))
9264557a2a1Srobj 			    == NULL) {
9274557a2a1Srobj 				topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
9284557a2a1Srobj 				    "argval element lacks a name attribute\n");
9294557a2a1Srobj 				ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
9304557a2a1Srobj 				goto pmr_done;
9314557a2a1Srobj 			}
9324557a2a1Srobj 			if ((ptype = xmlattr_to_type(mp, cn, (xmlChar *)Type))
9334557a2a1Srobj 			    == TOPO_TYPE_INVALID) {
9344557a2a1Srobj 				ret = topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE);
9354557a2a1Srobj 				xmlFree(arg_name);
9364557a2a1Srobj 				break;
9374557a2a1Srobj 			}
9384557a2a1Srobj 			if (xlate_common(mp, cn, ptype, arg_nvl,
9394557a2a1Srobj 			    (const char *)arg_name) != 0) {
9404557a2a1Srobj 				ret = topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE);
9414557a2a1Srobj 				xmlFree(arg_name);
9424557a2a1Srobj 				break;
9434557a2a1Srobj 			}
9444557a2a1Srobj 		}
9454557a2a1Srobj 		if (arg_name) {
9464557a2a1Srobj 			xmlFree(arg_name);
9474557a2a1Srobj 			arg_name = NULL;
9484557a2a1Srobj 		}
9494557a2a1Srobj 	}
9504557a2a1Srobj 
9514557a2a1Srobj 	if (ret != 0)
9524557a2a1Srobj 		goto pmr_done;
9534557a2a1Srobj 
9544557a2a1Srobj 	/*
9554557a2a1Srobj 	 * Register the prop method for all of the nodes in our range
9564557a2a1Srobj 	 */
9574557a2a1Srobj 	meth.pg_name = (const char *)pg_name;
9584557a2a1Srobj 	meth.prop_name = (const char *)prop_name;
9594557a2a1Srobj 	meth.prop_type = prop_type;
9604557a2a1Srobj 	meth.meth_name = (const char *)meth_name;
9614557a2a1Srobj 	meth.meth_ver = meth_ver;
9624557a2a1Srobj 	meth.arg_nvl = arg_nvl;
9634557a2a1Srobj 
9644557a2a1Srobj 	/*
9654557a2a1Srobj 	 * If the propgroup element is under a range element, we'll apply
9664557a2a1Srobj 	 * the method to all of the topo nodes at this level with the same
9674557a2a1Srobj 	 * range name.
9684557a2a1Srobj 	 *
9694557a2a1Srobj 	 * Otherwise, if the propgroup element is under a node element
9704557a2a1Srobj 	 * then we'll simply register the method for this node.
9714557a2a1Srobj 	 */
9724557a2a1Srobj 	if (strcmp(ppgrp_name, Range) == 0) {
9734557a2a1Srobj 		for (tmp = tn; tmp != NULL; tmp = topo_child_next(NULL, tmp)) {
974825ba0f2Srobj 			if (strcmp(rname, topo_node_name(tmp)) == 0) {
9754557a2a1Srobj 				if (register_method(mp, tmp, &meth) != 0) {
9764557a2a1Srobj 					ret = topo_mod_seterrno(mp,
9774557a2a1Srobj 					    ETOPO_PRSR_REGMETH);
9784557a2a1Srobj 					goto pmr_done;
9794557a2a1Srobj 				}
980825ba0f2Srobj 				if (is_mutable) {
981825ba0f2Srobj 					if (topo_prop_setmutable(tmp,
982825ba0f2Srobj 					    meth.pg_name, meth.prop_name, &err)
983825ba0f2Srobj 					    != 0) {
984825ba0f2Srobj 						ret = topo_mod_seterrno(mp,
985825ba0f2Srobj 						    ETOPO_PRSR_REGMETH);
986825ba0f2Srobj 						goto pmr_done;
987825ba0f2Srobj 					}
988825ba0f2Srobj 				}
989e5dcf7beSRobert Johnston 				if (is_nonvolatile) {
990e5dcf7beSRobert Johnston 					if (topo_prop_setnonvolatile(tmp,
991e5dcf7beSRobert Johnston 					    meth.pg_name, meth.prop_name, &err)
992e5dcf7beSRobert Johnston 					    != 0) {
993e5dcf7beSRobert Johnston 						ret = topo_mod_seterrno(mp,
994e5dcf7beSRobert Johnston 						    ETOPO_PRSR_REGMETH);
995e5dcf7beSRobert Johnston 						goto pmr_done;
996e5dcf7beSRobert Johnston 					}
997e5dcf7beSRobert Johnston 				}
998825ba0f2Srobj 			}
9994557a2a1Srobj 		}
10004557a2a1Srobj 	} else {
10014557a2a1Srobj 		if (register_method(mp, tn, &meth) != 0) {
10024557a2a1Srobj 			ret = topo_mod_seterrno(mp, ETOPO_PRSR_REGMETH);
10034557a2a1Srobj 			goto pmr_done;
10044557a2a1Srobj 		}
1005825ba0f2Srobj 		if (is_mutable) {
1006825ba0f2Srobj 			if (topo_prop_setmutable(tn, meth.pg_name,
1007825ba0f2Srobj 			    meth.prop_name, &err) != 0) {
1008825ba0f2Srobj 				ret = topo_mod_seterrno(mp,
1009825ba0f2Srobj 				    ETOPO_PRSR_REGMETH);
1010825ba0f2Srobj 				goto pmr_done;
1011825ba0f2Srobj 			}
1012825ba0f2Srobj 		}
1013e5dcf7beSRobert Johnston 		if (is_nonvolatile) {
1014e5dcf7beSRobert Johnston 			if (topo_prop_setnonvolatile(tn, meth.pg_name,
1015e5dcf7beSRobert Johnston 			    meth.prop_name, &err) != 0) {
1016e5dcf7beSRobert Johnston 				ret = topo_mod_seterrno(mp,
1017e5dcf7beSRobert Johnston 				    ETOPO_PRSR_REGMETH);
1018e5dcf7beSRobert Johnston 				goto pmr_done;
1019e5dcf7beSRobert Johnston 			}
1020e5dcf7beSRobert Johnston 		}
10214557a2a1Srobj 	}
10224557a2a1Srobj 
10234557a2a1Srobj pmr_done:
10244557a2a1Srobj 	if (meth_name)
10254557a2a1Srobj 		xmlFree(meth_name);
10264557a2a1Srobj 	if (prop_name)
10274557a2a1Srobj 		xmlFree(prop_name);
10284557a2a1Srobj 	nvlist_free(arg_nvl);
10294557a2a1Srobj 	return (ret);
10304557a2a1Srobj }
10314557a2a1Srobj 
10324557a2a1Srobj 
10334557a2a1Srobj static int
pgroup_record(topo_mod_t * mp,xmlNodePtr pxn,tnode_t * tn,const char * rname,tf_pad_t * rpad,int pi,const char * ppgrp_name)10344557a2a1Srobj pgroup_record(topo_mod_t *mp, xmlNodePtr pxn, tnode_t *tn, const char *rname,
10354557a2a1Srobj     tf_pad_t *rpad, int pi, const char *ppgrp_name)
10367aec1d6eScindi {
10370eb822a1Scindi 	topo_stability_t nmstab, dstab;
10380eb822a1Scindi 	uint64_t ver;
10397aec1d6eScindi 	xmlNodePtr cn;
10407aec1d6eScindi 	xmlChar *name;
10417aec1d6eScindi 	nvlist_t **apl = NULL;
10427aec1d6eScindi 	nvlist_t *pgnvl = NULL;
10437aec1d6eScindi 	int pcnt = 0;
10447aec1d6eScindi 	int ai = 0;
10457aec1d6eScindi 	int e;
10467aec1d6eScindi 
10474557a2a1Srobj 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroup_record\n");
10487aec1d6eScindi 	if ((name = xmlGetProp(pxn, (xmlChar *)Name)) == NULL) {
10490eb822a1Scindi 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
10500eb822a1Scindi 		    "propgroup lacks a name\n");
10517aec1d6eScindi 		return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
10527aec1d6eScindi 	}
10530eb822a1Scindi 	if (xmlattr_to_int(mp, pxn, Version, &ver) < 0) {
10540eb822a1Scindi 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
10550eb822a1Scindi 		    "propgroup lacks a version\n");
10560eb822a1Scindi 		return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
10570eb822a1Scindi 	}
10580eb822a1Scindi 	if (xmlattr_to_stab(mp, pxn, Namestab, &nmstab) < 0) {
10590eb822a1Scindi 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
10600eb822a1Scindi 		    "propgroup lacks name-stability\n");
10610eb822a1Scindi 		return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
10620eb822a1Scindi 	}
10630eb822a1Scindi 	if (xmlattr_to_stab(mp, pxn, Datastab, &dstab) < 0) {
10640eb822a1Scindi 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
10650eb822a1Scindi 		    "propgroup lacks data-stability\n");
10660eb822a1Scindi 		return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
10670eb822a1Scindi 	}
10680eb822a1Scindi 
10690eb822a1Scindi 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroup %s\n", (char *)name);
10707aec1d6eScindi 	for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
10717aec1d6eScindi 		if (xmlStrcmp(cn->name, (xmlChar *)Propval) == 0)
10727aec1d6eScindi 			pcnt++;
10737aec1d6eScindi 	}
10740eb822a1Scindi 
10757aec1d6eScindi 	if (topo_mod_nvalloc(mp, &pgnvl, NV_UNIQUE_NAME) < 0) {
10767aec1d6eScindi 		xmlFree(name);
10774557a2a1Srobj 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
10784557a2a1Srobj 		    "failed to allocate propgroup nvlist\n");
10794557a2a1Srobj 		return (topo_mod_seterrno(mp, ETOPO_NOMEM));
10807aec1d6eScindi 	}
10817aec1d6eScindi 
10827aec1d6eScindi 	e = nvlist_add_string(pgnvl, INV_PGRP_NAME, (char *)name);
10830eb822a1Scindi 	e |= nvlist_add_uint32(pgnvl, INV_PGRP_NMSTAB, nmstab);
10840eb822a1Scindi 	e |= nvlist_add_uint32(pgnvl, INV_PGRP_DSTAB, dstab);
10850eb822a1Scindi 	e |= nvlist_add_uint32(pgnvl, INV_PGRP_VER, ver);
10867aec1d6eScindi 	e |= nvlist_add_uint32(pgnvl, INV_PGRP_NPROP, pcnt);
10874557a2a1Srobj 	if (pcnt > 0)
10887aec1d6eScindi 		if (e != 0 ||
10894557a2a1Srobj 		    (apl = topo_mod_zalloc(mp, pcnt * sizeof (nvlist_t *)))
10904557a2a1Srobj 		    == NULL) {
10917aec1d6eScindi 			xmlFree(name);
10927aec1d6eScindi 			nvlist_free(pgnvl);
10934557a2a1Srobj 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
10944557a2a1Srobj 			    "failed to allocate nvlist array for properties"
10954557a2a1Srobj 			    "(e=%d)\n", e);
10964557a2a1Srobj 			return (topo_mod_seterrno(mp, ETOPO_NOMEM));
10977aec1d6eScindi 		}
10987aec1d6eScindi 	for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
10997aec1d6eScindi 		if (xmlStrcmp(cn->name, (xmlChar *)Propval) == 0) {
11007aec1d6eScindi 			if (ai < pcnt) {
11017aec1d6eScindi 				if ((apl[ai] = pval_record(mp, cn)) == NULL)
11027aec1d6eScindi 					break;
11037aec1d6eScindi 			}
11047aec1d6eScindi 			ai++;
11054557a2a1Srobj 		} else if (xmlStrcmp(cn->name, (xmlChar *)Prop_meth) == 0) {
11064557a2a1Srobj 			if (pmeth_record(mp, (const char *)name, cn, tn, rname,
11074557a2a1Srobj 			    ppgrp_name) < 0)
11084557a2a1Srobj 				break;
11097aec1d6eScindi 		}
11107aec1d6eScindi 	}
11117aec1d6eScindi 	xmlFree(name);
11124557a2a1Srobj 	if (pcnt > 0) {
11137aec1d6eScindi 		e |= (ai != pcnt);
11144557a2a1Srobj 		e |= nvlist_add_nvlist_array(pgnvl, INV_PGRP_ALLPROPS, apl,
11154557a2a1Srobj 		    pcnt);
11167aec1d6eScindi 		for (ai = 0; ai < pcnt; ai++)
11177aec1d6eScindi 			nvlist_free(apl[ai]);
11187aec1d6eScindi 		topo_mod_free(mp, apl, pcnt * sizeof (nvlist_t *));
11197aec1d6eScindi 		if (e != 0) {
11207aec1d6eScindi 			nvlist_free(pgnvl);
11217aec1d6eScindi 			return (-1);
11227aec1d6eScindi 		}
11234557a2a1Srobj 	}
11247aec1d6eScindi 	rpad->tpad_pgs[pi] = pgnvl;
11257aec1d6eScindi 	return (0);
11267aec1d6eScindi }
11277aec1d6eScindi 
11287aec1d6eScindi static int
pgroups_record(topo_mod_t * mp,xmlNodePtr pxn,tnode_t * tn,const char * rname,tf_pad_t * rpad,const char * ppgrp)11294557a2a1Srobj pgroups_record(topo_mod_t *mp, xmlNodePtr pxn, tnode_t *tn, const char *rname,
11304557a2a1Srobj     tf_pad_t *rpad, const char *ppgrp)
11317aec1d6eScindi {
11327aec1d6eScindi 	xmlNodePtr cn;
11337aec1d6eScindi 	int pi = 0;
11347aec1d6eScindi 
11354557a2a1Srobj 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroups_record: pxn->name=%s\n",
11364557a2a1Srobj 	    pxn->name);
11377aec1d6eScindi 	for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
11387aec1d6eScindi 		if (xmlStrcmp(cn->name, (xmlChar *)Propgrp) == 0) {
11394557a2a1Srobj 			if (pgroup_record(mp, cn, tn, rname, rpad, pi++, ppgrp)
11404557a2a1Srobj 			    < 0)
11417aec1d6eScindi 				return (-1);
11427aec1d6eScindi 		}
11437aec1d6eScindi 	}
11447aec1d6eScindi 	return (0);
11457aec1d6eScindi }
11467aec1d6eScindi 
11477aec1d6eScindi /*
11482eeaed14Srobj  * psn:	pointer to a "set" XML node
11492eeaed14Srobj  * key: string to search the set for
11504557a2a1Srobj  *
11512eeaed14Srobj  * returns: 1, if the set contains key
11524557a2a1Srobj  *          0, otherwise
11534557a2a1Srobj  */
11544557a2a1Srobj static int
set_contains(topo_mod_t * mp,char * key,char * set)11552eeaed14Srobj set_contains(topo_mod_t *mp, char *key, char *set)
11564557a2a1Srobj {
11574557a2a1Srobj 	char *prod;
11584557a2a1Srobj 	int rv = 0;
11594557a2a1Srobj 
11602eeaed14Srobj 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "set_contains(key = %s, "
11612eeaed14Srobj 	    "setlist = %s)\n", key, set);
11624557a2a1Srobj 
11634557a2a1Srobj 	prod = strtok((char *)set, "|");
11645108f83cSrobj 	if (prod && (strcmp(key, prod) == 0))
11654557a2a1Srobj 		return (1);
11664557a2a1Srobj 
11674557a2a1Srobj 	while ((prod = strtok(NULL, "|")))
11685108f83cSrobj 		if (strcmp(key, prod) == 0)
11694557a2a1Srobj 			return (1);
11704557a2a1Srobj 
11714557a2a1Srobj 	return (rv);
11724557a2a1Srobj }
11734557a2a1Srobj 
11744557a2a1Srobj 
11754557a2a1Srobj /*
11767aec1d6eScindi  * Process the property group and dependents xmlNode children of
11777aec1d6eScindi  * parent xmlNode pxn.
11787aec1d6eScindi  */
11797aec1d6eScindi static int
pad_process(topo_mod_t * mp,tf_rdata_t * rd,xmlNodePtr pxn,tnode_t * ptn,tf_pad_t ** rpad)11802eeaed14Srobj pad_process(topo_mod_t *mp, tf_rdata_t *rd, xmlNodePtr pxn, tnode_t *ptn,
11812eeaed14Srobj     tf_pad_t **rpad)
11827aec1d6eScindi {
1183*9adf2ea6SToomas Soome 	xmlNodePtr cn, gcn, psn = NULL, target;
118444d6604fSRobert Mustacchi 	/* Explicitly initialize ecn to help -Wmaybe-unit */
118544d6604fSRobert Mustacchi 	xmlNodePtr def_set = NULL, ecn = NULL;
1186825ba0f2Srobj 	tnode_t *ct;
11870eb822a1Scindi 	tf_pad_t *new = *rpad;
11882eeaed14Srobj 	tf_rdata_t tmp_rd;
11897aec1d6eScindi 	int pgcnt = 0;
11907aec1d6eScindi 	int dcnt = 0;
11912eeaed14Srobj 	int ecnt = 0;
1192af218de5SRobert Johnston 	int joined_set = 0, inst;
11934557a2a1Srobj 	xmlChar *set;
11944557a2a1Srobj 	char *key;
11957aec1d6eScindi 
11960eb822a1Scindi 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1197738c43b5SEric Schrock 	    "pad_process beneath %s=%d\n", topo_node_name(ptn),
1198738c43b5SEric Schrock 	    topo_node_instance(ptn));
11990eb822a1Scindi 	if (new == NULL) {
12007aec1d6eScindi 		for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
12014557a2a1Srobj 			topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
12024557a2a1Srobj 			    "cn->name is %s \n", (char *)cn->name);
12034557a2a1Srobj 			/*
12044557a2a1Srobj 			 * We're iterating through the XML children looking for
12052eeaed14Srobj 			 * four types of elements:
12064557a2a1Srobj 			 *   1) dependents elements
12074557a2a1Srobj 			 *   2) unconstrained pgroup elements
12082eeaed14Srobj 			 *   3) pgroup elements constrained by set elements
12092eeaed14Srobj 			 *   4) enum-method elements for the case that we want
12102eeaed14Srobj 			 *	to post-process a statically defined node
12114557a2a1Srobj 			 */
12127aec1d6eScindi 			if (xmlStrcmp(cn->name, (xmlChar *)Dependents) == 0)
12137aec1d6eScindi 				dcnt++;
12147aec1d6eScindi 			else if (xmlStrcmp(cn->name, (xmlChar *)Propgrp) == 0)
12157aec1d6eScindi 				pgcnt++;
12162eeaed14Srobj 			else if (xmlStrcmp(cn->name, (xmlChar *)Enum_meth)
12172eeaed14Srobj 			    == 0) {
12182eeaed14Srobj 				ecn = cn;
12192eeaed14Srobj 				ecnt++;
12202eeaed14Srobj 			} else if (xmlStrcmp(cn->name, (xmlChar *)Set) == 0) {
12212eeaed14Srobj 				if (joined_set)
12222eeaed14Srobj 					continue;
12232eeaed14Srobj 				set = xmlGetProp(cn, (xmlChar *)Setlist);
12244557a2a1Srobj 
12254557a2a1Srobj 				key = mp->tm_hdl->th_product;
12264557a2a1Srobj 
12274557a2a1Srobj 				/*
12282eeaed14Srobj 				 * If it's the default set then we'll store
12294557a2a1Srobj 				 * a pointer to it so that if none of the other
12302eeaed14Srobj 				 * sets apply to our product we can fall
12314557a2a1Srobj 				 * back to this one.
12324557a2a1Srobj 				 */
12334557a2a1Srobj 				if (strcmp((char *)set, "default") == 0)
12342eeaed14Srobj 					def_set = cn;
12352eeaed14Srobj 				else if (set_contains(mp, key, (char *)set)) {
12364557a2a1Srobj 					psn = cn;
12372eeaed14Srobj 					joined_set = 1;
12384557a2a1Srobj 					for (gcn = cn->xmlChildrenNode;
12394557a2a1Srobj 					    gcn != NULL; gcn = gcn->next) {
12404557a2a1Srobj 						if (xmlStrcmp(gcn->name,
12414557a2a1Srobj 						    (xmlChar *)Propgrp) == 0)
12424557a2a1Srobj 							pgcnt++;
12437aec1d6eScindi 					}
12444557a2a1Srobj 				}
12454557a2a1Srobj 				xmlFree(set);
12464557a2a1Srobj 			}
12474557a2a1Srobj 		}
12484557a2a1Srobj 		/*
12492eeaed14Srobj 		 * If we haven't found a set that contains our product AND
12502eeaed14Srobj 		 * a default set exists, then we'll process it.
12514557a2a1Srobj 		 */
12522eeaed14Srobj 		if (!joined_set && def_set) {
12534557a2a1Srobj 			topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
12542eeaed14Srobj 			    "Falling back to default set\n");
12552eeaed14Srobj 			joined_set = 1;
12562eeaed14Srobj 			psn = def_set;
12574557a2a1Srobj 			for (gcn = psn->xmlChildrenNode; gcn != NULL;
12584557a2a1Srobj 			    gcn = gcn->next) {
12594557a2a1Srobj 				if (xmlStrcmp(gcn->name, (xmlChar *)Propgrp)
12604557a2a1Srobj 				    == 0)
12614557a2a1Srobj 					pgcnt++;
12624557a2a1Srobj 			}
12634557a2a1Srobj 		}
12644557a2a1Srobj 		topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
12652eeaed14Srobj 		    "pad_process: dcnt=%d, pgcnt=%d, ecnt=%d, joined_set=%d\n",
12662eeaed14Srobj 		    dcnt, pgcnt, ecnt, joined_set);
12672eeaed14Srobj 		/*
12684557a2a1Srobj 		 * Here we allocate an element in an intermediate data structure
12694557a2a1Srobj 		 * which keeps track property groups and dependents of the range
12704557a2a1Srobj 		 * currently being processed.
12714557a2a1Srobj 		 *
12724557a2a1Srobj 		 * This structure is referenced in pgroups_record() to create
12734557a2a1Srobj 		 * the actual property groups in the topo tree
12744557a2a1Srobj 		 */
12750eb822a1Scindi 		if ((new = tf_pad_new(mp, pgcnt, dcnt)) == NULL)
12767aec1d6eScindi 			return (-1);
12770eb822a1Scindi 
12787aec1d6eScindi 		if (pgcnt > 0) {
12790eb822a1Scindi 			new->tpad_pgs =
12807aec1d6eScindi 			    topo_mod_zalloc(mp, pgcnt * sizeof (nvlist_t *));
12810eb822a1Scindi 			if (new->tpad_pgs == NULL) {
12820eb822a1Scindi 				tf_pad_free(mp, new);
12834557a2a1Srobj 				return (-1);
12847aec1d6eScindi 			}
1285d91236feSeschrock 		}
12864557a2a1Srobj 		/*
1287825ba0f2Srobj 		 * If the property groups are contained within a set
1288825ba0f2Srobj 		 * then they will be one level lower in the XML tree.
12894557a2a1Srobj 		 */
1290825ba0f2Srobj 		if (joined_set)
1291825ba0f2Srobj 			target = psn;
1292825ba0f2Srobj 		else
1293825ba0f2Srobj 			target = pxn;
1294825ba0f2Srobj 
1295825ba0f2Srobj 		/*
1296825ba0f2Srobj 		 * If there is no "node" element under the "range"
1297825ba0f2Srobj 		 * element, then we need to attach the facility node to
1298825ba0f2Srobj 		 * each node in this range.
1299825ba0f2Srobj 		 *
1300825ba0f2Srobj 		 * Otherwise we only attach it to the current node
1301825ba0f2Srobj 		 */
1302d91236feSeschrock 		if (xmlStrcmp(target->name, (xmlChar *)Range) == 0 ||
1303d91236feSeschrock 		    xmlStrcmp(target->name, (xmlChar *)Set) == 0) {
1304825ba0f2Srobj 			for (ct = topo_child_first(rd->rd_pn);
1305825ba0f2Srobj 			    ct != NULL;
1306825ba0f2Srobj 			    ct = topo_child_next(rd->rd_pn, ct)) {
1307825ba0f2Srobj 
1308825ba0f2Srobj 				if (strcmp(topo_node_name(ct),
1309825ba0f2Srobj 				    rd->rd_name) != 0)
1310825ba0f2Srobj 					continue;
1311825ba0f2Srobj 
1312af218de5SRobert Johnston 				inst = topo_node_instance(ct);
1313af218de5SRobert Johnston 				if (inst < rd->rd_min || inst > rd->rd_max)
1314af218de5SRobert Johnston 					continue;
1315af218de5SRobert Johnston 
1316d91236feSeschrock 				if (fac_enum_process(mp, target, ct) < 0)
1317825ba0f2Srobj 					return (-1);
1318825ba0f2Srobj 
1319825ba0f2Srobj 				if (fac_process(mp, target, rd, ct) < 0)
1320825ba0f2Srobj 					return (-1);
1321825ba0f2Srobj 			}
1322d91236feSeschrock 		} else {
1323825ba0f2Srobj 			if (fac_enum_process(mp, target, ptn) < 0)
1324825ba0f2Srobj 				return (-1);
1325825ba0f2Srobj 			if (fac_process(mp, target, rd, ptn) < 0)
1326825ba0f2Srobj 				return (-1);
1327d91236feSeschrock 		}
1328d91236feSeschrock 		if (pgcnt > 0 && pgroups_record(mp, target, ptn, rd->rd_name,
13292eeaed14Srobj 		    new, (const char *)pxn->name) < 0) {
13300eb822a1Scindi 			tf_pad_free(mp, new);
13314557a2a1Srobj 			return (-1);
13324557a2a1Srobj 		}
13330eb822a1Scindi 		*rpad = new;
13347aec1d6eScindi 	}
13357aec1d6eScindi 
13363c6ffbabSRob Johnston 	/*
13373c6ffbabSRob Johnston 	 * We need to process the property groups before enumerating any
13383c6ffbabSRob Johnston 	 * dependents as that enuemration can itself have dependencies on
13393c6ffbabSRob Johnston 	 * properties set on the parent node.
13403c6ffbabSRob Johnston 	 */
13410eb822a1Scindi 	if (new->tpad_pgcnt > 0)
13420eb822a1Scindi 		if (pgroups_create(mp, new, ptn) < 0)
13437aec1d6eScindi 			return (-1);
13444557a2a1Srobj 
1345ea6920ffSRobert Mustacchi 	/*
1346ea6920ffSRobert Mustacchi 	 * If an enum-method element was found, AND we're a child of a
1347ea6920ffSRobert Mustacchi 	 * node element, then we invoke the enumerator so that it can do
1348ea6920ffSRobert Mustacchi 	 * post-processing of the node.
1349ea6920ffSRobert Mustacchi 	 */
1350ea6920ffSRobert Mustacchi 	if (ecnt && (strcmp((const char *)pxn->name, Node) == 0)) {
1351ea6920ffSRobert Mustacchi 		if ((tmp_rd.rd_einfo = enum_attributes_process(mp, ecn))
1352ea6920ffSRobert Mustacchi 		    == NULL)
1353ea6920ffSRobert Mustacchi 			return (-1);
1354ea6920ffSRobert Mustacchi 		tmp_rd.rd_mod = mp;
1355ea6920ffSRobert Mustacchi 		tmp_rd.rd_name = rd->rd_name;
1356ea6920ffSRobert Mustacchi 		tmp_rd.rd_min = rd->rd_min;
1357ea6920ffSRobert Mustacchi 		tmp_rd.rd_max = rd->rd_max;
1358ea6920ffSRobert Mustacchi 		tmp_rd.rd_pn = ptn;
1359ea6920ffSRobert Mustacchi 		if (enum_run(mp, &tmp_rd) < 0) {
1360ea6920ffSRobert Mustacchi 			/*
1361ea6920ffSRobert Mustacchi 			 * Note the failure but continue on
1362ea6920ffSRobert Mustacchi 			 */
1363ea6920ffSRobert Mustacchi 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1364ea6920ffSRobert Mustacchi 			    "pad_process: enumeration failed.\n");
1365ea6920ffSRobert Mustacchi 		}
1366ea6920ffSRobert Mustacchi 		tf_edata_free(mp, tmp_rd.rd_einfo);
1367ea6920ffSRobert Mustacchi 	}
1368ea6920ffSRobert Mustacchi 
13693c6ffbabSRob Johnston 	if (new->tpad_dcnt > 0)
13703c6ffbabSRob Johnston 		if (dependents_create(mp, rd->rd_finfo, new, pxn, ptn) < 0)
13713c6ffbabSRob Johnston 			return (-1);
13723c6ffbabSRob Johnston 
13737aec1d6eScindi 	return (0);
13747aec1d6eScindi }
13757aec1d6eScindi 
13762eeaed14Srobj 
13777aec1d6eScindi static int
fac_enum_process(topo_mod_t * mp,xmlNodePtr pn,tnode_t * ptn)1378825ba0f2Srobj fac_enum_process(topo_mod_t *mp, xmlNodePtr pn, tnode_t *ptn)
1379825ba0f2Srobj {
1380825ba0f2Srobj 	xmlNodePtr cn;
1381825ba0f2Srobj 	xmlChar *fprov = NULL;
1382825ba0f2Srobj 	int rv = 0;
1383825ba0f2Srobj 
1384825ba0f2Srobj 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1385825ba0f2Srobj 	    "fac_enum_process() called for %s=%d\n", topo_node_name(ptn),
1386825ba0f2Srobj 	    topo_node_instance(ptn));
1387825ba0f2Srobj 
1388825ba0f2Srobj 	for (cn = pn->xmlChildrenNode; cn != NULL; cn = cn->next) {
1389825ba0f2Srobj 
1390825ba0f2Srobj 		if (xmlStrcmp(cn->name, (xmlChar *)"fac-enum") != 0)
1391825ba0f2Srobj 			continue;
1392825ba0f2Srobj 
1393825ba0f2Srobj 		if ((fprov = xmlGetProp(cn, (xmlChar *)Provider)) == NULL)
1394825ba0f2Srobj 			goto fenumdone;
1395825ba0f2Srobj 		/*
1396aed5247fSJoshua M. Clulow 		 * Invoke enum entry point in facility provider which will
1397aed5247fSJoshua M. Clulow 		 * cause the facility enumeration node method to be
1398aed5247fSJoshua M. Clulow 		 * registered.
1399825ba0f2Srobj 		 */
1400825ba0f2Srobj 		if (fac_enum_run(mp, ptn, (const char *)fprov) != 0) {
1401825ba0f2Srobj 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1402825ba0f2Srobj 			    "fac_enum_process: enum entry point failed!\n");
1403825ba0f2Srobj 			goto fenumdone;
1404825ba0f2Srobj 		}
1405825ba0f2Srobj 		xmlFree(fprov);
1406825ba0f2Srobj 	}
1407825ba0f2Srobj 	return (0);
1408825ba0f2Srobj fenumdone:
1409825ba0f2Srobj 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "fac-enum processing failed\n");
1410825ba0f2Srobj 
1411825ba0f2Srobj 	if (fprov != NULL)
1412825ba0f2Srobj 		xmlFree(fprov);
1413825ba0f2Srobj 
1414825ba0f2Srobj 	return (rv);
1415825ba0f2Srobj }
1416825ba0f2Srobj 
1417825ba0f2Srobj 
1418825ba0f2Srobj static int
fac_process(topo_mod_t * mp,xmlNodePtr pn,tf_rdata_t * rd,tnode_t * ptn)1419825ba0f2Srobj fac_process(topo_mod_t *mp, xmlNodePtr pn, tf_rdata_t *rd, tnode_t *ptn)
1420825ba0f2Srobj {
1421825ba0f2Srobj 	xmlNodePtr cn;
1422825ba0f2Srobj 	xmlChar *fname = NULL, *ftype = NULL, *provider = NULL;
1423825ba0f2Srobj 	tnode_t *ntn = NULL;
1424825ba0f2Srobj 	tf_idata_t *newi;
1425825ba0f2Srobj 	int err;
1426825ba0f2Srobj 	topo_pgroup_info_t pgi;
1427825ba0f2Srobj 
1428825ba0f2Srobj 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1429738c43b5SEric Schrock 	    "fac_process() called for %s=%d\n", topo_node_name(ptn),
1430738c43b5SEric Schrock 	    topo_node_instance(ptn));
1431825ba0f2Srobj 
1432825ba0f2Srobj 	for (cn = pn->xmlChildrenNode; cn != NULL; cn = cn->next) {
1433825ba0f2Srobj 
1434825ba0f2Srobj 		if (xmlStrcmp(cn->name, (xmlChar *)Facility) != 0)
1435825ba0f2Srobj 			continue;
1436825ba0f2Srobj 
1437825ba0f2Srobj 		if ((fname = xmlGetProp(cn, (xmlChar *)Name)) == NULL)
1438825ba0f2Srobj 			goto facdone;
1439825ba0f2Srobj 
1440738c43b5SEric Schrock 		topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1441738c43b5SEric Schrock 		    "processing facility node '%s'\n", fname);
1442738c43b5SEric Schrock 
1443825ba0f2Srobj 		if ((ftype = xmlGetProp(cn, (xmlChar *)Type)) == NULL)
1444825ba0f2Srobj 			goto facdone;
1445825ba0f2Srobj 
1446825ba0f2Srobj 		if ((provider = xmlGetProp(cn, (xmlChar *)Provider)) == NULL)
1447825ba0f2Srobj 			goto facdone;
1448825ba0f2Srobj 
1449825ba0f2Srobj 		if (xmlStrcmp(ftype, (xmlChar *)Sensor) != 0 &&
1450825ba0f2Srobj 		    xmlStrcmp(ftype, (xmlChar *)Indicator) != 0)
1451825ba0f2Srobj 			goto facdone;
1452825ba0f2Srobj 
1453825ba0f2Srobj 		if ((ntn = topo_node_facbind(mp, ptn, (char *)fname,
1454825ba0f2Srobj 		    (char *)ftype)) == NULL)
1455825ba0f2Srobj 			goto facdone;
1456825ba0f2Srobj 
1457825ba0f2Srobj 		pgi.tpi_name = TOPO_PGROUP_FACILITY;
1458825ba0f2Srobj 		pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
1459825ba0f2Srobj 		pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
1460825ba0f2Srobj 		pgi.tpi_version = 1;
1461825ba0f2Srobj 		if (topo_pgroup_create(ntn, &pgi, &err) != 0) {
1462825ba0f2Srobj 			if (err != ETOPO_PROP_DEFD) {
1463825ba0f2Srobj 				topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1464825ba0f2Srobj 				    "pgroups create failure: %s\n",
1465825ba0f2Srobj 				    topo_strerror(err));
1466825ba0f2Srobj 				return (-1);
1467825ba0f2Srobj 			}
1468825ba0f2Srobj 		}
1469825ba0f2Srobj 		/*
1470aed5247fSJoshua M. Clulow 		 * Invoke enum entry point in the facility provider module,
1471aed5247fSJoshua M. Clulow 		 * which will cause the provider methods to be registered on
1472aed5247fSJoshua M. Clulow 		 * this node
1473825ba0f2Srobj 		 */
1474825ba0f2Srobj 		if (fac_enum_run(mp, ntn, (const char *)provider) != 0) {
1475825ba0f2Srobj 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "fac_process: "
1476825ba0f2Srobj 			    "enum entry point failed for provider %s!\n",
1477825ba0f2Srobj 			    provider);
1478825ba0f2Srobj 			goto facdone;
1479825ba0f2Srobj 		}
1480825ba0f2Srobj 
1481825ba0f2Srobj 		if ((newi = tf_idata_new(mp, 0, ntn)) == NULL)
1482825ba0f2Srobj 			goto facdone;
1483825ba0f2Srobj 
1484825ba0f2Srobj 		if (tf_idata_insert(&rd->rd_instances, newi) < 0)
1485825ba0f2Srobj 			goto facdone;
1486825ba0f2Srobj 
1487825ba0f2Srobj 		if (pad_process(mp, rd, cn, ntn, &newi->ti_pad) < 0)
1488825ba0f2Srobj 			goto facdone;
1489825ba0f2Srobj 
1490825ba0f2Srobj 		topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "done with "
1491825ba0f2Srobj 		    "facility %s=%s.\n", ftype, fname);
1492825ba0f2Srobj 
1493825ba0f2Srobj 		xmlFree(ftype);
1494825ba0f2Srobj 		xmlFree(fname);
1495825ba0f2Srobj 		xmlFree(provider);
1496825ba0f2Srobj 	}
1497825ba0f2Srobj 
1498825ba0f2Srobj 	return (0);
1499825ba0f2Srobj 
1500825ba0f2Srobj facdone:
1501825ba0f2Srobj 	topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "facility processing failed\n");
1502825ba0f2Srobj 
1503825ba0f2Srobj 	if (ftype != NULL)
1504825ba0f2Srobj 		xmlFree(ftype);
1505825ba0f2Srobj 	if (fname != NULL)
1506825ba0f2Srobj 		xmlFree(fname);
1507825ba0f2Srobj 	if (provider != NULL)
1508825ba0f2Srobj 		xmlFree(provider);
1509825ba0f2Srobj 	if (ntn != NULL)
1510825ba0f2Srobj 		topo_node_unbind(ntn);
1511825ba0f2Srobj 
1512825ba0f2Srobj 	return (0);
1513825ba0f2Srobj }
1514825ba0f2Srobj 
1515825ba0f2Srobj static int
node_process(topo_mod_t * mp,xmlNodePtr nn,tf_rdata_t * rd)15167aec1d6eScindi node_process(topo_mod_t *mp, xmlNodePtr nn, tf_rdata_t *rd)
15177aec1d6eScindi {
15180eb822a1Scindi 	xmlChar *str;
15197aec1d6eScindi 	topo_instance_t inst;
15207aec1d6eScindi 	tf_idata_t *newi;
15217aec1d6eScindi 	tnode_t *ntn;
15227aec1d6eScindi 	uint64_t ui;
15237aec1d6eScindi 	int rv = -1;
15240eb822a1Scindi 	int s = 0;
15257aec1d6eScindi 
15260eb822a1Scindi 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
15274557a2a1Srobj 	    "node_process %s\n", rd->rd_name);
15280eb822a1Scindi 
15297aec1d6eScindi 	if (xmlattr_to_int(mp, nn, Instance, &ui) < 0)
15307aec1d6eScindi 		goto nodedone;
15317aec1d6eScindi 	inst = (topo_instance_t)ui;
15327aec1d6eScindi 
15330eb822a1Scindi 	if ((str = xmlGetProp(nn, (xmlChar *)Static)) != NULL) {
15340eb822a1Scindi 		if (xmlStrcmp(str, (xmlChar *)True) == 0)
15350eb822a1Scindi 			s = 1;
15369dd0f810Scindi 		xmlFree(str);
15370eb822a1Scindi 	}
15380eb822a1Scindi 
15399dd0f810Scindi 	if (s == 0) {
15409dd0f810Scindi 		if (topo_mod_enumerate(rd->rd_mod, rd->rd_pn,
15419dd0f810Scindi 		    rd->rd_finfo->tf_scheme, rd->rd_name, inst, inst,
15429dd0f810Scindi 		    s == 1 ? &s : NULL) < 0)
15437aec1d6eScindi 			goto nodedone;
15449dd0f810Scindi 	}
15457aec1d6eScindi 	ntn = topo_node_lookup(rd->rd_pn, rd->rd_name, inst);
15462eeaed14Srobj 
15479dd0f810Scindi 	if (ntn == NULL) {
15489dd0f810Scindi 
15499dd0f810Scindi 		/*
15509dd0f810Scindi 		 * If this is a static node declaration, we can
15519dd0f810Scindi 		 * ignore the lookup failure and continue
15529dd0f810Scindi 		 * processing.  Otherwise, something
15539dd0f810Scindi 		 * went wrong during enumeration
15549dd0f810Scindi 		 */
15559dd0f810Scindi 		if (s == 1)
15569dd0f810Scindi 			rv = 0;
15577aec1d6eScindi 		goto nodedone;
15589dd0f810Scindi 	}
15597aec1d6eScindi 	if ((newi = tf_idata_new(mp, inst, ntn)) == NULL) {
15600eb822a1Scindi 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
15614557a2a1Srobj 		    "node_process: tf_idata_new failed.\n");
15627aec1d6eScindi 		goto nodedone;
15637aec1d6eScindi 	}
15640eb822a1Scindi 	if (tf_idata_insert(&rd->rd_instances, newi) < 0) {
15650eb822a1Scindi 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
15664557a2a1Srobj 		    "node_process: tf_idata_insert failed.\n");
15677aec1d6eScindi 		goto nodedone;
15687aec1d6eScindi 	}
15692eeaed14Srobj 	if (pad_process(mp, rd, nn, ntn, &newi->ti_pad) < 0)
15707aec1d6eScindi 		goto nodedone;
1571825ba0f2Srobj 	if (fac_process(mp, nn, rd, ntn) < 0)
1572825ba0f2Srobj 		goto nodedone;
15737aec1d6eScindi 	rv = 0;
15747aec1d6eScindi nodedone:
15750eb822a1Scindi 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "done with node %s.\n",
15760eb822a1Scindi 	    rd->rd_name);
15777aec1d6eScindi 	return (rv);
15787aec1d6eScindi }
15797aec1d6eScindi 
15807aec1d6eScindi static tf_edata_t *
enum_attributes_process(topo_mod_t * mp,xmlNodePtr en)15817aec1d6eScindi enum_attributes_process(topo_mod_t *mp, xmlNodePtr en)
15827aec1d6eScindi {
15837aec1d6eScindi 	tf_edata_t *einfo;
15847aec1d6eScindi 	uint64_t ui;
15857aec1d6eScindi 
15864557a2a1Srobj 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "enum_attributes_process\n");
15877aec1d6eScindi 	if ((einfo = topo_mod_zalloc(mp, sizeof (tf_edata_t))) == NULL) {
15887aec1d6eScindi 		(void) topo_mod_seterrno(mp, ETOPO_NOMEM);
15897aec1d6eScindi 		return (NULL);
15907aec1d6eScindi 	}
15917aec1d6eScindi 	einfo->te_name = (char *)xmlGetProp(en, (xmlChar *)Name);
15927aec1d6eScindi 	if (einfo->te_name == NULL) {
15930eb822a1Scindi 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
15940eb822a1Scindi 		    "Enumerator name attribute missing.\n");
15957aec1d6eScindi 		(void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
15967aec1d6eScindi 		goto enodedone;
15977aec1d6eScindi 	}
15989dd0f810Scindi 
15999dd0f810Scindi 	/*
16009dd0f810Scindi 	 * Check for recursive enumeration
16019dd0f810Scindi 	 */
16029dd0f810Scindi 	if (strcmp(einfo->te_name, mp->tm_name) == 0) {
16039dd0f810Scindi 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
16049dd0f810Scindi 		    "Recursive enumeration detected for %s\n",
16059dd0f810Scindi 		    einfo->te_name);
16069dd0f810Scindi 		(void) topo_mod_seterrno(mp, ETOPO_ENUM_RECURS);
16079dd0f810Scindi 		goto enodedone;
16089dd0f810Scindi 	}
16097aec1d6eScindi 	if (xmlattr_to_int(mp, en, Version, &ui) < 0)
16107aec1d6eScindi 		goto enodedone;
16117aec1d6eScindi 	einfo->te_vers = (int)ui;
16129dd0f810Scindi 
16137aec1d6eScindi 	return (einfo);
16147aec1d6eScindi 
16157aec1d6eScindi enodedone:
16167aec1d6eScindi 	if (einfo->te_name != NULL)
16177aec1d6eScindi 		xmlFree(einfo->te_name);
16182eeaed14Srobj 	topo_mod_free(mp, einfo, sizeof (tf_edata_t));
16197aec1d6eScindi 	return (NULL);
16207aec1d6eScindi }
16217aec1d6eScindi 
16227aec1d6eScindi static int
enum_run(topo_mod_t * mp,tf_rdata_t * rd)16237aec1d6eScindi enum_run(topo_mod_t *mp, tf_rdata_t *rd)
16247aec1d6eScindi {
16250eb822a1Scindi 	topo_hdl_t *thp = mp->tm_hdl;
16267aec1d6eScindi 	int e = -1;
16277aec1d6eScindi 
16284557a2a1Srobj 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "enum_run\n");
16297aec1d6eScindi 	/*
16300eb822a1Scindi 	 * Check if the enumerator module is already loaded.
16310eb822a1Scindi 	 * Module loading is single-threaded at this point so there's
16320eb822a1Scindi 	 * no need to worry about the module going away or bumping the
16330eb822a1Scindi 	 * ref count.
16347aec1d6eScindi 	 */
16350eb822a1Scindi 	if ((rd->rd_mod = topo_mod_lookup(thp, rd->rd_einfo->te_name,
16360eb822a1Scindi 	    0)) == NULL) {
16370eb822a1Scindi 		if ((rd->rd_mod = topo_mod_load(mp, rd->rd_einfo->te_name,
16380eb822a1Scindi 		    rd->rd_einfo->te_vers)) == NULL) {
16390eb822a1Scindi 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
16404557a2a1Srobj 			    "enum_run: mod_load of %s failed: %s.\n",
16410eb822a1Scindi 			    rd->rd_einfo->te_name,
16420eb822a1Scindi 			    topo_strerror(topo_mod_errno(mp)));
16430eb822a1Scindi 			(void) topo_hdl_seterrno(thp, topo_mod_errno(mp));
16447aec1d6eScindi 			return (e);
16457aec1d6eScindi 		}
16467aec1d6eScindi 	}
16477aec1d6eScindi 	/*
16487aec1d6eScindi 	 * We're live, so let's enumerate.
16497aec1d6eScindi 	 */
16500eb822a1Scindi 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "enumerate request. (%s)\n",
16517aec1d6eScindi 	    rd->rd_einfo->te_name);
16527aec1d6eScindi 	e = topo_mod_enumerate(rd->rd_mod, rd->rd_pn, rd->rd_einfo->te_name,
16530eb822a1Scindi 	    rd->rd_name, rd->rd_min, rd->rd_max, NULL);
16540eb822a1Scindi 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "back from enumeration. %d\n",
16550eb822a1Scindi 	    e);
16567aec1d6eScindi 	if (e != 0) {
16570eb822a1Scindi 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
16580eb822a1Scindi 		    "Enumeration failed (%s)\n",
16597aec1d6eScindi 		    topo_strerror(topo_mod_errno(mp)));
16600eb822a1Scindi 		(void) topo_hdl_seterrno(thp, EMOD_PARTIAL_ENUM);
16617aec1d6eScindi 		return (topo_mod_seterrno(mp, EMOD_PARTIAL_ENUM));
16627aec1d6eScindi 	}
16637aec1d6eScindi 	return (e);
16647aec1d6eScindi }
16657aec1d6eScindi 
1666825ba0f2Srobj static int
fac_enum_run(topo_mod_t * mp,tnode_t * node,const char * name)1667825ba0f2Srobj fac_enum_run(topo_mod_t *mp, tnode_t *node, const char *name)
1668825ba0f2Srobj {
1669825ba0f2Srobj 	topo_hdl_t *thp = mp->tm_hdl;
1670825ba0f2Srobj 	topo_mod_t *fmod;
1671825ba0f2Srobj 	int e = -1;
1672825ba0f2Srobj 
1673825ba0f2Srobj 	topo_dprintf(thp, TOPO_DBG_XML, "fac_enum_run\n");
1674825ba0f2Srobj 	/*
1675825ba0f2Srobj 	 * Check if the enumerator module is already loaded.
1676825ba0f2Srobj 	 * Module loading is single-threaded at this point so there's
1677825ba0f2Srobj 	 * no need to worry about the module going away or bumping the
1678825ba0f2Srobj 	 * ref count.
1679825ba0f2Srobj 	 */
1680825ba0f2Srobj 	if ((fmod = topo_mod_lookup(thp, name, 0)) == NULL) {
1681825ba0f2Srobj 		if ((fmod = topo_mod_load(mp, name, TOPO_VERSION)) == NULL) {
1682825ba0f2Srobj 			topo_dprintf(thp, TOPO_DBG_ERR,
1683825ba0f2Srobj 			    "fac_enum_run: mod_load of %s failed: %s.\n",
1684825ba0f2Srobj 			    name, topo_strerror(topo_mod_errno(mp)));
1685825ba0f2Srobj 			(void) topo_hdl_seterrno(thp, topo_mod_errno(mp));
1686825ba0f2Srobj 			return (e);
1687825ba0f2Srobj 		}
1688825ba0f2Srobj 	}
1689825ba0f2Srobj 	/*
1690825ba0f2Srobj 	 * We're live, so let's enumerate.
1691825ba0f2Srobj 	 */
1692825ba0f2Srobj 	topo_dprintf(thp, TOPO_DBG_XML, "fac enumerate request. (%s)\n", name);
1693825ba0f2Srobj 	e = topo_mod_enumerate(fmod, node, name, name, 0, 0, NULL);
1694825ba0f2Srobj 	topo_dprintf(thp, TOPO_DBG_XML, "back from enumeration. %d\n", e);
1695825ba0f2Srobj 	if (e != 0) {
1696825ba0f2Srobj 		topo_dprintf(thp, TOPO_DBG_ERR,
1697825ba0f2Srobj 		    "Facility provider enumeration failed (%s)\n",
1698825ba0f2Srobj 		    topo_strerror(topo_mod_errno(mp)));
1699825ba0f2Srobj 		(void) topo_hdl_seterrno(thp, EMOD_PARTIAL_ENUM);
1700825ba0f2Srobj 		return (topo_mod_seterrno(mp, EMOD_PARTIAL_ENUM));
1701825ba0f2Srobj 	}
1702825ba0f2Srobj 	return (e);
1703825ba0f2Srobj }
17044557a2a1Srobj 
17054557a2a1Srobj int
decorate_nodes(topo_mod_t * mp,tf_rdata_t * rd,xmlNodePtr pxn,tnode_t * ptn,tf_pad_t ** rpad)17062eeaed14Srobj decorate_nodes(topo_mod_t *mp, tf_rdata_t *rd, xmlNodePtr pxn, tnode_t *ptn,
17072eeaed14Srobj     tf_pad_t **rpad)
17084557a2a1Srobj {
17094557a2a1Srobj 	tnode_t *ctn;
17104557a2a1Srobj 
17114557a2a1Srobj 	ctn = topo_child_first(ptn);
17124557a2a1Srobj 	while (ctn != NULL) {
17134557a2a1Srobj 		/* Only care about instances within the range */
17142eeaed14Srobj 		if (strcmp(topo_node_name(ctn), rd->rd_name) != 0) {
17154557a2a1Srobj 			ctn = topo_child_next(ptn, ctn);
17164557a2a1Srobj 			continue;
17174557a2a1Srobj 		}
17182eeaed14Srobj 		if (pad_process(mp, rd, pxn, ctn, rpad) < 0)
17194557a2a1Srobj 			return (-1);
17202eeaed14Srobj 		if (decorate_nodes(mp, rd, pxn, ctn, rpad) < 0)
17214557a2a1Srobj 			return (-1);
17224557a2a1Srobj 		ctn = topo_child_next(ptn, ctn);
17234557a2a1Srobj 	}
17244557a2a1Srobj 	return (0);
17254557a2a1Srobj }
17264557a2a1Srobj 
17277aec1d6eScindi int
topo_xml_range_process(topo_mod_t * mp,xmlNodePtr rn,tf_rdata_t * rd)17287aec1d6eScindi topo_xml_range_process(topo_mod_t *mp, xmlNodePtr rn, tf_rdata_t *rd)
17297aec1d6eScindi {
17307aec1d6eScindi 	/*
17317aec1d6eScindi 	 * The range may have several children xmlNodes, that may
17327aec1d6eScindi 	 * represent the enumeration method, property groups,
17334557a2a1Srobj 	 * dependents, nodes or services.
17347aec1d6eScindi 	 */
17354557a2a1Srobj 	xmlNodePtr cn, enum_node = NULL, pmap_node = NULL;
17364557a2a1Srobj 	xmlChar *pmap_name;
17377aec1d6eScindi 	tnode_t *ct;
1738c40d7343Scindi 	int e, ccnt = 0;
17397aec1d6eScindi 
17404557a2a1Srobj 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_range_process\n"
17414557a2a1Srobj 	    "process %s range beneath %s\n", rd->rd_name,
17424557a2a1Srobj 	    topo_node_name(rd->rd_pn));
17432eeaed14Srobj 
17447aec1d6eScindi 	e = topo_node_range_create(mp,
17457aec1d6eScindi 	    rd->rd_pn, rd->rd_name, rd->rd_min, rd->rd_max);
1746825ba0f2Srobj 	if (e != 0 && topo_mod_errno(mp) != EMOD_NODE_DUP) {
17470eb822a1Scindi 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
17480eb822a1Scindi 		    "Range create failed due to %s.\n",
17497aec1d6eScindi 		    topo_strerror(topo_mod_errno(mp)));
17507aec1d6eScindi 		return (-1);
17517aec1d6eScindi 	}
17524557a2a1Srobj 
17534557a2a1Srobj 	/*
17544557a2a1Srobj 	 * Before we process any of the other child xmlNodes, we iterate through
17554557a2a1Srobj 	 * the children and looking for either enum-method or propmap elements.
17564557a2a1Srobj 	 */
17577aec1d6eScindi 	for (cn = rn->xmlChildrenNode; cn != NULL; cn = cn->next)
17587aec1d6eScindi 		if (xmlStrcmp(cn->name, (xmlChar *)Enum_meth) == 0)
17594557a2a1Srobj 			enum_node = cn;
17604557a2a1Srobj 		else if (xmlStrcmp(cn->name, (xmlChar *)Propmap) == 0)
17614557a2a1Srobj 			pmap_node = cn;
17627aec1d6eScindi 
17634557a2a1Srobj 	/*
17644557a2a1Srobj 	 * If we found an enum-method element, process it first
17654557a2a1Srobj 	 */
17664557a2a1Srobj 	if (enum_node != NULL) {
17674557a2a1Srobj 		if ((rd->rd_einfo = enum_attributes_process(mp, enum_node))
17684557a2a1Srobj 		    == NULL)
17697aec1d6eScindi 			return (-1);
17707aec1d6eScindi 		if (enum_run(mp, rd) < 0) {
17710eb822a1Scindi 			/*
17720eb822a1Scindi 			 * Note the failure but continue on
17730eb822a1Scindi 			 */
17740eb822a1Scindi 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
17750eb822a1Scindi 			    "Enumeration failed.\n");
17767aec1d6eScindi 		}
17777aec1d6eScindi 	}
17787aec1d6eScindi 
17794557a2a1Srobj 	/*
17804557a2a1Srobj 	 * Next, check if a propmap element was found and if so, load it in
17814557a2a1Srobj 	 * and parse it.
17824557a2a1Srobj 	 */
17834557a2a1Srobj 	if (pmap_node != NULL) {
17844557a2a1Srobj 		topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "found a propmap "
17854557a2a1Srobj 		    "element\n");
17864557a2a1Srobj 		if ((pmap_name = xmlGetProp(pmap_node, (xmlChar *)Name))
17874557a2a1Srobj 		    == NULL) {
17884557a2a1Srobj 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
17894557a2a1Srobj 			    "propmap element missing name attribute.\n");
17904557a2a1Srobj 		} else {
17914557a2a1Srobj 			if (topo_file_load(mp, rd->rd_pn,
17924557a2a1Srobj 			    (const char *)pmap_name,
17934557a2a1Srobj 			    rd->rd_finfo->tf_scheme, 1) < 0) {
17944557a2a1Srobj 
17954557a2a1Srobj 				topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
17964557a2a1Srobj 				    "topo_xml_range_process: topo_file_load"
17974557a2a1Srobj 				    "failed: %s.\n",
17984557a2a1Srobj 				    topo_strerror(topo_mod_errno(mp)));
17994557a2a1Srobj 			}
18004557a2a1Srobj 			xmlFree(pmap_name);
18014557a2a1Srobj 		}
18024557a2a1Srobj 	}
18034557a2a1Srobj 
18047aec1d6eScindi 	/* Now look for nodes, i.e., hard instances */
18057aec1d6eScindi 	for (cn = rn->xmlChildrenNode; cn != NULL; cn = cn->next) {
18062eeaed14Srobj 		if (xmlStrcmp(cn->name, (xmlChar *)Node) == 0) {
18077aec1d6eScindi 			if (node_process(mp, cn, rd) < 0) {
18080eb822a1Scindi 				topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
18097aec1d6eScindi 				    "node processing failed: %s.\n",
18107aec1d6eScindi 				    topo_strerror(topo_mod_errno(mp)));
18117aec1d6eScindi 				return (topo_mod_seterrno(mp,
18127aec1d6eScindi 				    EMOD_PARTIAL_ENUM));
18137aec1d6eScindi 			}
18144557a2a1Srobj 			ccnt++;
18157aec1d6eScindi 		}
18162eeaed14Srobj 	}
18177aec1d6eScindi 
18184557a2a1Srobj 	/*
18194557a2a1Srobj 	 * Finally, process the property groups and dependents
18204557a2a1Srobj 	 *
18214557a2a1Srobj 	 * If the TF_PROPMAP flag is set for the XML file we're currently
18224557a2a1Srobj 	 * processing, then this XML file was loaded via propmap.  In that case
18234557a2a1Srobj 	 * we call a special routine to recursively apply the propgroup settings
18244557a2a1Srobj 	 * to all of nodes in this range
18254557a2a1Srobj 	 */
18264557a2a1Srobj 	if (rd->rd_finfo->tf_flags & TF_PROPMAP)
18272eeaed14Srobj 		(void) decorate_nodes(mp, rd, rn, rd->rd_pn, &rd->rd_pad);
18284557a2a1Srobj 	else {
18297aec1d6eScindi 		ct = topo_child_first(rd->rd_pn);
18307aec1d6eScindi 		while (ct != NULL) {
18317aec1d6eScindi 			/* Only care about instances within the range */
18327aec1d6eScindi 			if (strcmp(topo_node_name(ct), rd->rd_name) != 0) {
18337aec1d6eScindi 				ct = topo_child_next(rd->rd_pn, ct);
18347aec1d6eScindi 				continue;
18357aec1d6eScindi 			}
18362eeaed14Srobj 			if (pad_process(mp, rd, rn, ct, &rd->rd_pad)
18372eeaed14Srobj 			    < 0)
18387aec1d6eScindi 				return (-1);
1839825ba0f2Srobj 
1840825ba0f2Srobj 			if (fac_process(mp, rn, rd, ct) < 0)
1841825ba0f2Srobj 				return (-1);
1842825ba0f2Srobj 
18437aec1d6eScindi 			ct = topo_child_next(rd->rd_pn, ct);
1844c40d7343Scindi 			ccnt++;
18457aec1d6eScindi 		}
18464557a2a1Srobj 	}
1847c40d7343Scindi 
18484557a2a1Srobj 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_range_process: end "
18494557a2a1Srobj 	    "range process %s\n", rd->rd_name);
18504557a2a1Srobj 
18517aec1d6eScindi 	return (0);
18527aec1d6eScindi }
18537aec1d6eScindi 
18547aec1d6eScindi static tf_rdata_t *
topo_xml_walk(topo_mod_t * mp,tf_info_t * xinfo,xmlNodePtr croot,tnode_t * troot)18557aec1d6eScindi topo_xml_walk(topo_mod_t *mp,
18567aec1d6eScindi     tf_info_t *xinfo, xmlNodePtr croot, tnode_t *troot)
18577aec1d6eScindi {
18582eeaed14Srobj 	xmlNodePtr curr, def_set = NULL;
18597aec1d6eScindi 	tf_rdata_t *rr, *pr, *rdp;
18602eeaed14Srobj 	xmlChar *set;
18612eeaed14Srobj 	char *key;
18622eeaed14Srobj 	int joined_set = 0;
18632eeaed14Srobj 
18642eeaed14Srobj 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_walk\n");
18652eeaed14Srobj 	rr = pr = NULL;
18662eeaed14Srobj 	/*
18672eeaed14Srobj 	 * First iterate through all the XML nodes at this level to look for
18682eeaed14Srobj 	 * set nodes.
18692eeaed14Srobj 	 */
18702eeaed14Srobj 	for (curr = croot->xmlChildrenNode; curr != NULL; curr = curr->next) {
18712eeaed14Srobj 		if (curr->name == NULL) {
18722eeaed14Srobj 			topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
18732eeaed14Srobj 			    "topo_xml_walk: Ignoring nameless xmlnode\n");
18742eeaed14Srobj 			continue;
18752eeaed14Srobj 		}
18762eeaed14Srobj 		if (xmlStrcmp(curr->name, (xmlChar *)Set) == 0) {
18772eeaed14Srobj 			if (joined_set)
18782eeaed14Srobj 				continue;
18792eeaed14Srobj 
18802eeaed14Srobj 			set = xmlGetProp(curr, (xmlChar *)Setlist);
18812eeaed14Srobj 
18822eeaed14Srobj 			key = mp->tm_hdl->th_product;
18837aec1d6eScindi 
18847aec1d6eScindi 			/*
18852eeaed14Srobj 			 * If it's the default set then we'll store
18862eeaed14Srobj 			 * a pointer to it so that if none of the other
18872eeaed14Srobj 			 * sets apply to our product we can fall
18882eeaed14Srobj 			 * back to this one.
18892eeaed14Srobj 			 */
18902eeaed14Srobj 			if (strcmp((char *)set, "default") == 0)
18912eeaed14Srobj 				def_set = curr;
18922eeaed14Srobj 			else if (set_contains(mp, key, (char *)set)) {
18932eeaed14Srobj 				joined_set = 1;
18942eeaed14Srobj 				if ((rdp = topo_xml_walk(mp, xinfo, curr,
18952eeaed14Srobj 				    troot)) == NULL) {
18962eeaed14Srobj 					topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
18972eeaed14Srobj 					    "topo_xml_walk: failed1\n");
1898af218de5SRobert Johnston 				} else {
18992eeaed14Srobj 					if (pr == NULL) {
19002eeaed14Srobj 						rr = pr = rdp;
19012eeaed14Srobj 					} else {
19022eeaed14Srobj 						pr->rd_next = rdp;
19032eeaed14Srobj 						pr = rdp;
19042eeaed14Srobj 					}
19052eeaed14Srobj 					rr->rd_cnt++;
19062eeaed14Srobj 				}
1907af218de5SRobert Johnston 			}
19082eeaed14Srobj 			xmlFree(set);
19092eeaed14Srobj 		}
19102eeaed14Srobj 	}
19112eeaed14Srobj 	/*
19122eeaed14Srobj 	 * If we haven't found a set that contains our product AND a default set
19132eeaed14Srobj 	 * exists, then we'll process it.
19142eeaed14Srobj 	 */
191588045cffSRobert Johnston 	if (!joined_set && def_set) {
191688045cffSRobert Johnston 		if ((rdp = topo_xml_walk(mp, xinfo, def_set, troot)) == NULL) {
19172eeaed14Srobj 			topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
19182eeaed14Srobj 			    "topo_xml_walk: failed2\n");
19192eeaed14Srobj 		}
192088045cffSRobert Johnston 		if (pr == NULL) {
192188045cffSRobert Johnston 			rr = pr = rdp;
192288045cffSRobert Johnston 		} else {
192388045cffSRobert Johnston 			pr->rd_next = rdp;
192488045cffSRobert Johnston 			pr = rdp;
192588045cffSRobert Johnston 		}
192688045cffSRobert Johnston 		rr->rd_cnt++;
192788045cffSRobert Johnston 	}
19282eeaed14Srobj 	/*
19292eeaed14Srobj 	 * Now we're interested in children xmlNodes of croot tagged
19304557a2a1Srobj 	 * as 'ranges'.  These define what topology nodes may exist, and need
19317aec1d6eScindi 	 * to be verified.
19327aec1d6eScindi 	 */
19337aec1d6eScindi 	for (curr = croot->xmlChildrenNode; curr != NULL; curr = curr->next) {
19347aec1d6eScindi 		if (curr->name == NULL) {
19350eb822a1Scindi 			topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
19364557a2a1Srobj 			    "topo_xml_walk: Ignoring nameless xmlnode\n");
19377aec1d6eScindi 			continue;
19387aec1d6eScindi 		}
1939738c43b5SEric Schrock 		if (xmlStrcmp(curr->name, (xmlChar *)Range) != 0)
19407aec1d6eScindi 			continue;
19417aec1d6eScindi 		if ((rdp = tf_rdata_new(mp, xinfo, curr, troot)) == NULL) {
1942c40d7343Scindi 			/*
1943c40d7343Scindi 			 * Range processing error, continue walk
1944c40d7343Scindi 			 */
1945c40d7343Scindi 			continue;
19467aec1d6eScindi 		}
19477aec1d6eScindi 		if (pr == NULL) {
19487aec1d6eScindi 			rr = pr = rdp;
19497aec1d6eScindi 		} else {
19507aec1d6eScindi 			pr->rd_next = rdp;
19517aec1d6eScindi 			pr = rdp;
19527aec1d6eScindi 		}
19537aec1d6eScindi 		rr->rd_cnt++;
19547aec1d6eScindi 	}
19554557a2a1Srobj 
19567aec1d6eScindi 	return (rr);
19577aec1d6eScindi }
19587aec1d6eScindi 
19597aec1d6eScindi /*
19607aec1d6eScindi  *  Convert parsed xml topology description into topology nodes
19617aec1d6eScindi  */
19627aec1d6eScindi int
topo_xml_enum(topo_mod_t * tmp,tf_info_t * xinfo,tnode_t * troot)19637aec1d6eScindi topo_xml_enum(topo_mod_t *tmp, tf_info_t *xinfo, tnode_t *troot)
19647aec1d6eScindi {
19657aec1d6eScindi 	xmlNodePtr xroot;
19667aec1d6eScindi 
19674557a2a1Srobj 	topo_dprintf(tmp->tm_hdl, TOPO_DBG_XML, "topo_xml_enum\n");
19684557a2a1Srobj 
19697aec1d6eScindi 	if ((xroot = xmlDocGetRootElement(xinfo->tf_xdoc)) == NULL) {
19700eb822a1Scindi 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
19710eb822a1Scindi 		    "Couldn't get root xmlNode.\n");
19727aec1d6eScindi 		return (-1);
19737aec1d6eScindi 	}
19747aec1d6eScindi 	if ((xinfo->tf_rd = topo_xml_walk(tmp, xinfo, xroot, troot)) == NULL) {
19750eb822a1Scindi 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
19767aec1d6eScindi 		    "error within .xml topology: %s\n",
19777aec1d6eScindi 		    topo_strerror(topo_mod_errno(tmp)));
19787aec1d6eScindi 		return (-1);
19797aec1d6eScindi 	}
19807aec1d6eScindi 	return (0);
19817aec1d6eScindi }
19827aec1d6eScindi 
19837aec1d6eScindi /*
19847aec1d6eScindi  * Load an XML tree from filename and read it into a DOM parse tree.
19857aec1d6eScindi  */
19867aec1d6eScindi static tf_info_t *
txml_file_parse(topo_mod_t * tmp,int fd,const char * filenm,const char * escheme)19877aec1d6eScindi txml_file_parse(topo_mod_t *tmp,
19887aec1d6eScindi     int fd, const char *filenm, const char *escheme)
19897aec1d6eScindi {
19907aec1d6eScindi 	xmlValidCtxtPtr vcp;
19917aec1d6eScindi 	xmlNodePtr cursor;
19927aec1d6eScindi 	xmlDocPtr document;
19937aec1d6eScindi 	xmlDtdPtr dtd = NULL;
19947aec1d6eScindi 	xmlChar *scheme = NULL;
19957aec1d6eScindi 	char *dtdpath = NULL;
19967aec1d6eScindi 	int readflags = 0;
19977aec1d6eScindi 	tf_info_t *r;
19980eb822a1Scindi 	int e, validate = 0;
19997aec1d6eScindi 
20004557a2a1Srobj 	topo_dprintf(tmp->tm_hdl, TOPO_DBG_XML,
20014557a2a1Srobj 	    "txml_file_parse(filenm=%s, escheme=%s)\n", filenm, escheme);
20024557a2a1Srobj 
20037aec1d6eScindi 	/*
20047aec1d6eScindi 	 * Since topologies can XInclude other topologies, and libxml2
20057aec1d6eScindi 	 * doesn't do DTD-based validation with XInclude, by default
20067aec1d6eScindi 	 * we don't validate topology files.  One can force
20077aec1d6eScindi 	 * validation, though, by creating a TOPOXML_VALIDATE
20087aec1d6eScindi 	 * environment variable and creating a TOPO_DTD environment
20097aec1d6eScindi 	 * variable with the path to the DTD against which to validate.
20107aec1d6eScindi 	 */
20117aec1d6eScindi 	if (getenv("TOPOXML_VALIDATE") != NULL) {
20127aec1d6eScindi 		dtdpath = getenv("TOPO_DTD");
20130eb822a1Scindi 		validate = 1;
20147aec1d6eScindi 	}
20157aec1d6eScindi 
20167aec1d6eScindi 	/*
20177aec1d6eScindi 	 * Splat warnings and errors related to parsing the topology
20187aec1d6eScindi 	 * file if the TOPOXML_PERROR environment variable exists.
20197aec1d6eScindi 	 */
20207aec1d6eScindi 	if (getenv("TOPOXML_PERROR") == NULL)
20217aec1d6eScindi 		readflags = XML_PARSE_NOERROR | XML_PARSE_NOWARNING;
20227aec1d6eScindi 
20237aec1d6eScindi 	if ((document = xmlReadFd(fd, filenm, NULL, readflags)) == NULL) {
20240eb822a1Scindi 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
20254557a2a1Srobj 		    "txml_file_parse: couldn't parse document.\n");
20267aec1d6eScindi 		return (NULL);
20277aec1d6eScindi 	}
20287aec1d6eScindi 
20297aec1d6eScindi 	/*
20307aec1d6eScindi 	 * Verify that this is a document type we understand.
20317aec1d6eScindi 	 */
20327aec1d6eScindi 	if ((dtd = xmlGetIntSubset(document)) == NULL) {
20330eb822a1Scindi 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
20340eb822a1Scindi 		    "document has no DTD.\n");
2035c40d7343Scindi 		xmlFreeDoc(document);
20367aec1d6eScindi 		return (NULL);
20377aec1d6eScindi 	}
20387aec1d6eScindi 
20390eb822a1Scindi 	if (strcmp((const char *)dtd->SystemID, TOPO_DTD_PATH) != 0) {
20400eb822a1Scindi 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
20410eb822a1Scindi 		    "document DTD unknown; bad topology file\n");
2042c40d7343Scindi 		xmlFreeDoc(document);
20437aec1d6eScindi 		return (NULL);
20447aec1d6eScindi 	}
20457aec1d6eScindi 
20467aec1d6eScindi 	if ((cursor = xmlDocGetRootElement(document)) == NULL) {
20470eb822a1Scindi 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, "document is empty.\n");
20487aec1d6eScindi 		xmlFreeDoc(document);
20497aec1d6eScindi 		return (NULL);
20507aec1d6eScindi 	}
20517aec1d6eScindi 
20527aec1d6eScindi 	/*
20537aec1d6eScindi 	 * Make sure we're looking at a topology description in the
20547aec1d6eScindi 	 * expected scheme.
20557aec1d6eScindi 	 */
20567aec1d6eScindi 	if (xmlStrcmp(cursor->name, (xmlChar *)Topology) != 0) {
20570eb822a1Scindi 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
20587aec1d6eScindi 		    "document is not a topology description.\n");
20597aec1d6eScindi 		xmlFreeDoc(document);
20607aec1d6eScindi 		return (NULL);
20617aec1d6eScindi 	}
20627aec1d6eScindi 	if ((scheme = xmlGetProp(cursor, (xmlChar *)Scheme)) == NULL) {
20630eb822a1Scindi 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
20640eb822a1Scindi 		    "topology lacks a scheme.\n");
20657aec1d6eScindi 		(void) topo_mod_seterrno(tmp, ETOPO_PRSR_NOATTR);
20667aec1d6eScindi 		xmlFreeDoc(document);
20677aec1d6eScindi 		return (NULL);
20687aec1d6eScindi 	}
20697aec1d6eScindi 	if (xmlStrcmp(scheme, (xmlChar *)escheme) != 0) {
20700eb822a1Scindi 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
20717aec1d6eScindi 		    "topology in unrecognized scheme, %s, expecting %s\n",
20727aec1d6eScindi 		    scheme, escheme);
20737aec1d6eScindi 		(void) topo_mod_seterrno(tmp, ETOPO_PRSR_BADSCH);
20747aec1d6eScindi 		xmlFree(scheme);
20757aec1d6eScindi 		xmlFreeDoc(document);
20767aec1d6eScindi 		return (NULL);
20777aec1d6eScindi 	}
20787aec1d6eScindi 
20797aec1d6eScindi 	if (dtdpath != NULL) {
20807aec1d6eScindi 		dtd = xmlParseDTD(NULL, (xmlChar *)dtdpath);
20817aec1d6eScindi 		if (dtd == NULL) {
20820eb822a1Scindi 			topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
20837aec1d6eScindi 			    "Could not parse DTD \"%s\".\n",
20847aec1d6eScindi 			    dtdpath);
2085c40d7343Scindi 			xmlFree(scheme);
2086c40d7343Scindi 			xmlFreeDoc(document);
20877aec1d6eScindi 			return (NULL);
20887aec1d6eScindi 		}
20897aec1d6eScindi 
20907aec1d6eScindi 		if (document->extSubset != NULL)
20917aec1d6eScindi 			xmlFreeDtd(document->extSubset);
20927aec1d6eScindi 
20937aec1d6eScindi 		document->extSubset = dtd;
20947aec1d6eScindi 	}
20957aec1d6eScindi 
20964557a2a1Srobj 	if (xmlXIncludeProcessFlags(document, XML_PARSE_XINCLUDE) == -1) {
2097c40d7343Scindi 		xmlFree(scheme);
2098c40d7343Scindi 		xmlFreeDoc(document);
20990eb822a1Scindi 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
21007aec1d6eScindi 		    "couldn't handle XInclude statements in document\n");
21017aec1d6eScindi 		return (NULL);
21027aec1d6eScindi 	}
21037aec1d6eScindi 
21040eb822a1Scindi 	if (validate) {
21057aec1d6eScindi 		if ((vcp = xmlNewValidCtxt()) == NULL) {
21067aec1d6eScindi 			xmlFree(scheme);
2107c40d7343Scindi 			xmlFreeDoc(document);
21087aec1d6eScindi 			return (NULL);
21097aec1d6eScindi 		}
21107aec1d6eScindi 		vcp->warning = xmlParserValidityWarning;
21117aec1d6eScindi 		vcp->error = xmlParserValidityError;
21127aec1d6eScindi 
21137aec1d6eScindi 		e = xmlValidateDocument(vcp, document);
21147aec1d6eScindi 
21157aec1d6eScindi 		xmlFreeValidCtxt(vcp);
21167aec1d6eScindi 
21170eb822a1Scindi 		if (e == 0)
21180eb822a1Scindi 			topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
21190eb822a1Scindi 			    "Document is not valid.\n");
21207aec1d6eScindi 	}
21217aec1d6eScindi 
2122c40d7343Scindi 	if ((r = tf_info_new(tmp, document, scheme)) == NULL) {
2123c40d7343Scindi 		xmlFree(scheme);
2124c40d7343Scindi 		xmlFreeDoc(document);
21257aec1d6eScindi 		return (NULL);
2126c40d7343Scindi 	}
21277aec1d6eScindi 
21287aec1d6eScindi 	xmlFree(scheme);
21297aec1d6eScindi 	scheme = NULL;
21307aec1d6eScindi 	return (r);
21317aec1d6eScindi }
21327aec1d6eScindi 
21337aec1d6eScindi tf_info_t *
topo_xml_read(topo_mod_t * tmp,const char * path,const char * escheme)21347aec1d6eScindi topo_xml_read(topo_mod_t *tmp, const char *path, const char *escheme)
21357aec1d6eScindi {
21367aec1d6eScindi 	int fd;
21377aec1d6eScindi 	tf_info_t *tip;
21387aec1d6eScindi 
21394557a2a1Srobj 	if ((fd = open(path, O_RDONLY)) < 0) {
21404557a2a1Srobj 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
21414557a2a1Srobj 		    "failed to open %s for reading\n", path);
21427aec1d6eScindi 		return (NULL);
21437aec1d6eScindi 	}
21447aec1d6eScindi 	tip = txml_file_parse(tmp, fd, path, escheme);
21457aec1d6eScindi 	(void) close(fd);
21467aec1d6eScindi 	return (tip);
21477aec1d6eScindi }
2148