Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include <libxml/parser.h>
     28 #include <libxml/xinclude.h>
     29 #include <sys/fm/protocol.h>
     30 #include <assert.h>
     31 #include <string.h>
     32 #include <strings.h>
     33 #include <ctype.h>
     34 #include <errno.h>
     35 #include <limits.h>
     36 #include <fm/libtopo.h>
     37 #include <unistd.h>
     38 #include <sys/stat.h>
     39 #include <fcntl.h>
     40 #include <topo_file.h>
     41 #include <topo_mod.h>
     42 #include <topo_subr.h>
     43 #include <topo_alloc.h>
     44 #include <topo_parse.h>
     45 #include <topo_error.h>
     46 
     47 static tf_rdata_t *topo_xml_walk(topo_mod_t *, tf_info_t *, xmlNodePtr,
     48     tnode_t *);
     49 static tf_edata_t *enum_attributes_process(topo_mod_t *, xmlNodePtr);
     50 static int enum_run(topo_mod_t *, tf_rdata_t *);
     51 static int fac_enum_run(topo_mod_t *, tnode_t *, const char *);
     52 static int fac_process(topo_mod_t *, xmlNodePtr, tf_rdata_t *, tnode_t *);
     53 static int fac_enum_process(topo_mod_t *, xmlNodePtr, tnode_t *);
     54 static int decorate_nodes(topo_mod_t *, tf_rdata_t *, xmlNodePtr, tnode_t *,
     55     tf_pad_t **);
     56 
     57 
     58 static void
     59 strarr_free(topo_mod_t *mod, char **arr, uint_t nelems)
     60 {
     61 	int i;
     62 
     63 	for (i = 0; i < nelems; i++)
     64 		topo_mod_strfree(mod, arr[i]);
     65 	topo_mod_free(mod, arr, (nelems * sizeof (char *)));
     66 }
     67 
     68 int
     69 xmlattr_to_stab(topo_mod_t *mp, xmlNodePtr n, const char *stabname,
     70     topo_stability_t *rs)
     71 {
     72 	xmlChar *str;
     73 	int rv = 0;
     74 
     75 	if (n == NULL) {
     76 		/* If there is no Stability defined, we default to private */
     77 		*rs = TOPO_STABILITY_PRIVATE;
     78 		return (0);
     79 	}
     80 	if ((str = xmlGetProp(n, (xmlChar *)stabname)) == NULL) {
     81 		topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
     82 		    "attribute to stability:\n");
     83 		return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
     84 	}
     85 
     86 	if (xmlStrcmp(str, (xmlChar *)Internal) == 0) {
     87 		*rs = TOPO_STABILITY_INTERNAL;
     88 	} else if (xmlStrcmp(str, (xmlChar *)Private) == 0) {
     89 		*rs = TOPO_STABILITY_PRIVATE;
     90 	} else if (xmlStrcmp(str, (xmlChar *)Obsolete) == 0) {
     91 		*rs = TOPO_STABILITY_OBSOLETE;
     92 	} else if (xmlStrcmp(str, (xmlChar *)External) == 0) {
     93 		*rs = TOPO_STABILITY_EXTERNAL;
     94 	} else if (xmlStrcmp(str, (xmlChar *)Unstable) == 0) {
     95 		*rs = TOPO_STABILITY_UNSTABLE;
     96 	} else if (xmlStrcmp(str, (xmlChar *)Evolving) == 0) {
     97 		*rs = TOPO_STABILITY_EVOLVING;
     98 	} else if (xmlStrcmp(str, (xmlChar *)Stable) == 0) {
     99 		*rs = TOPO_STABILITY_STABLE;
    100 	} else if (xmlStrcmp(str, (xmlChar *)Standard) == 0) {
    101 		*rs = TOPO_STABILITY_STANDARD;
    102 	} else {
    103 		xmlFree(str);
    104 		return (topo_mod_seterrno(mp, ETOPO_PRSR_BADSTAB));
    105 	}
    106 	xmlFree(str);
    107 	return (rv);
    108 }
    109 
    110 int
    111 xmlattr_to_int(topo_mod_t *mp,
    112     xmlNodePtr n, const char *propname, uint64_t *value)
    113 {
    114 	xmlChar *str;
    115 	xmlChar *estr;
    116 
    117 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "xmlattr_to_int(propname=%s)\n",
    118 	    propname);
    119 	if ((str = xmlGetProp(n, (xmlChar *)propname)) == NULL)
    120 		return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
    121 	*value = strtoull((char *)str, (char **)&estr, 10);
    122 	if (estr == str) {
    123 		/* no conversion was done */
    124 		xmlFree(str);
    125 		return (topo_mod_seterrno(mp, ETOPO_PRSR_BADNUM));
    126 	}
    127 	xmlFree(str);
    128 	return (0);
    129 }
    130 
    131 static int
    132 xmlattr_to_fmri(topo_mod_t *mp,
    133     xmlNodePtr xn, const char *propname, nvlist_t **rnvl)
    134 {
    135 	xmlChar *str;
    136 
    137 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "xmlattr_to_fmri(propname=%s)\n",
    138 	    propname);
    139 	if ((str = xmlGetProp(xn, (xmlChar *)propname)) == NULL)
    140 		return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
    141 	if (topo_mod_str2nvl(mp, (const char *)str, rnvl) < 0) {
    142 		xmlFree(str);
    143 		return (-1);
    144 	}
    145 	xmlFree(str);
    146 	return (0);
    147 }
    148 
    149 static topo_type_t
    150 xmlattr_to_type(topo_mod_t *mp, xmlNodePtr xn, xmlChar *attr)
    151 {
    152 	topo_type_t rv;
    153 	xmlChar *str;
    154 	if ((str = xmlGetProp(xn, (xmlChar *)attr)) == NULL) {
    155 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "%s attribute missing",
    156 		    attr);
    157 		(void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
    158 		return (TOPO_TYPE_INVALID);
    159 	}
    160 	if (xmlStrcmp(str, (xmlChar *)Int32) == 0) {
    161 		rv = TOPO_TYPE_INT32;
    162 	} else if (xmlStrcmp(str, (xmlChar *)UInt32) == 0) {
    163 		rv = TOPO_TYPE_UINT32;
    164 	} else if (xmlStrcmp(str, (xmlChar *)Int64) == 0) {
    165 		rv = TOPO_TYPE_INT64;
    166 	} else if (xmlStrcmp(str, (xmlChar *)UInt64) == 0) {
    167 		rv = TOPO_TYPE_UINT64;
    168 	} else if (xmlStrcmp(str, (xmlChar *)FMRI) == 0) {
    169 		rv = TOPO_TYPE_FMRI;
    170 	} else if (xmlStrcmp(str, (xmlChar *)String) == 0) {
    171 		rv = TOPO_TYPE_STRING;
    172 	} else if (xmlStrcmp(str, (xmlChar *)Int32_Arr) == 0) {
    173 		rv = TOPO_TYPE_INT32_ARRAY;
    174 	} else if (xmlStrcmp(str, (xmlChar *)UInt32_Arr) == 0) {
    175 		rv = TOPO_TYPE_UINT32_ARRAY;
    176 	} else if (xmlStrcmp(str, (xmlChar *)Int64_Arr) == 0) {
    177 		rv = TOPO_TYPE_INT64_ARRAY;
    178 	} else if (xmlStrcmp(str, (xmlChar *)UInt64_Arr) == 0) {
    179 		rv = TOPO_TYPE_UINT64_ARRAY;
    180 	} else if (xmlStrcmp(str, (xmlChar *)String_Arr) == 0) {
    181 		rv = TOPO_TYPE_STRING_ARRAY;
    182 	} else if (xmlStrcmp(str, (xmlChar *)FMRI_Arr) == 0) {
    183 		rv = TOPO_TYPE_FMRI_ARRAY;
    184 	} else {
    185 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
    186 		    "Unrecognized type attribute value '%s'.\n", str);
    187 		(void) topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE);
    188 		xmlFree(str);
    189 		return (TOPO_TYPE_INVALID);
    190 	}
    191 	xmlFree(str);
    192 	return (rv);
    193 }
    194 
    195 static int
    196 xlate_common(topo_mod_t *mp, xmlNodePtr xn, topo_type_t ptype, nvlist_t *nvl,
    197 const char *name)
    198 {
    199 	int rv;
    200 	uint64_t ui;
    201 	uint_t i = 0, nelems = 0;
    202 	nvlist_t *fmri;
    203 	xmlChar *str;
    204 	char **strarrbuf;
    205 	void *arrbuf;
    206 	nvlist_t **nvlarrbuf;
    207 	xmlNodePtr cn;
    208 
    209 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "xlate_common(name=%s)\n", name);
    210 	switch (ptype) {
    211 	case TOPO_TYPE_INT32:
    212 		if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
    213 			return (-1);
    214 		rv = nvlist_add_int32(nvl, name, (int32_t)ui);
    215 		break;
    216 	case TOPO_TYPE_UINT32:
    217 		if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
    218 			return (-1);
    219 		rv = nvlist_add_uint32(nvl, name, (uint32_t)ui);
    220 		break;
    221 	case TOPO_TYPE_INT64:
    222 		if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
    223 			return (-1);
    224 		rv = nvlist_add_int64(nvl, name, (int64_t)ui);
    225 		break;
    226 	case TOPO_TYPE_UINT64:
    227 		if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
    228 			return (-1);
    229 		rv = nvlist_add_uint64(nvl, name, ui);
    230 		break;
    231 	case TOPO_TYPE_FMRI:
    232 		if (xmlattr_to_fmri(mp, xn, Value, &fmri) < 0)
    233 			return (-1);
    234 		rv = nvlist_add_nvlist(nvl, name, fmri);
    235 		nvlist_free(fmri);
    236 		break;
    237 	case TOPO_TYPE_STRING:
    238 		if ((str = xmlGetProp(xn, (xmlChar *)Value)) == NULL)
    239 			return (-1);
    240 		rv = nvlist_add_string(nvl, name, (char *)str);
    241 		xmlFree(str);
    242 		break;
    243 	case TOPO_TYPE_INT32_ARRAY:
    244 	case TOPO_TYPE_UINT32_ARRAY:
    245 	case TOPO_TYPE_INT64_ARRAY:
    246 	case TOPO_TYPE_UINT64_ARRAY:
    247 		for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next)
    248 			if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
    249 			    (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0))
    250 				nelems++;
    251 
    252 		if (nelems < 1) {
    253 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "No <propitem> "
    254 			    "or <argitem> elements found for array val");
    255 			return (-1);
    256 		}
    257 		if ((arrbuf = topo_mod_alloc(mp, (nelems * sizeof (uint64_t))))
    258 		    == NULL)
    259 			return (topo_mod_seterrno(mp, ETOPO_NOMEM));
    260 		break;
    261 	case TOPO_TYPE_STRING_ARRAY:
    262 		for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next)
    263 			if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
    264 			    (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0))
    265 				nelems++;
    266 
    267 		if (nelems < 1) {
    268 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "No <propitem> "
    269 			    "or <argitem> elements found for array val");
    270 			return (-1);
    271 		}
    272 		if ((strarrbuf = topo_mod_alloc(mp, (nelems * sizeof (char *))))
    273 		    == NULL)
    274 			return (topo_mod_seterrno(mp, ETOPO_NOMEM));
    275 		break;
    276 	case TOPO_TYPE_FMRI_ARRAY:
    277 		for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next)
    278 			if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
    279 			    (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0))
    280 				nelems++;
    281 
    282 		if (nelems < 1) {
    283 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "No <propitem> "
    284 			    "elements found for array prop");
    285 			return (-1);
    286 		}
    287 		if ((nvlarrbuf = topo_mod_alloc(mp, (nelems *
    288 		    sizeof (nvlist_t *)))) == NULL)
    289 			return (topo_mod_seterrno(mp, ETOPO_NOMEM));
    290 		break;
    291 	default:
    292 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
    293 		    "Unrecognized type attribute (ptype = %d)\n", ptype);
    294 		return (topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE));
    295 	}
    296 
    297 	switch (ptype) {
    298 	case TOPO_TYPE_INT32_ARRAY:
    299 		for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
    300 			if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
    301 			    (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
    302 
    303 				if ((str = xmlGetProp(xn, (xmlChar *)Value))
    304 				    == NULL)
    305 					return (-1);
    306 
    307 				((int32_t *)arrbuf)[i++]
    308 				    = atoi((const char *)str);
    309 				xmlFree(str);
    310 			}
    311 		}
    312 
    313 		rv = nvlist_add_int32_array(nvl, name, (int32_t *)arrbuf,
    314 		    nelems);
    315 		free(arrbuf);
    316 		break;
    317 	case TOPO_TYPE_UINT32_ARRAY:
    318 		for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
    319 			if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
    320 			    (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
    321 
    322 				if ((str = xmlGetProp(xn, (xmlChar *)Value))
    323 				    == NULL)
    324 					return (-1);
    325 
    326 				((uint32_t *)arrbuf)[i++]
    327 				    = atoi((const char *)str);
    328 				xmlFree(str);
    329 			}
    330 		}
    331 
    332 		rv = nvlist_add_uint32_array(nvl, name, (uint32_t *)arrbuf,
    333 		    nelems);
    334 		free(arrbuf);
    335 		break;
    336 	case TOPO_TYPE_INT64_ARRAY:
    337 		for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
    338 			if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
    339 			    (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
    340 
    341 				if ((str = xmlGetProp(xn, (xmlChar *)Value))
    342 				    == NULL)
    343 					return (-1);
    344 
    345 				((int64_t *)arrbuf)[i++]
    346 				    = atol((const char *)str);
    347 				xmlFree(str);
    348 			}
    349 		}
    350 
    351 		rv = nvlist_add_int64_array(nvl, name, (int64_t *)arrbuf,
    352 		    nelems);
    353 		free(arrbuf);
    354 		break;
    355 	case TOPO_TYPE_UINT64_ARRAY:
    356 		for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
    357 			if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
    358 			    (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
    359 
    360 				if ((str = xmlGetProp(xn, (xmlChar *)Value))
    361 				    == NULL)
    362 					return (-1);
    363 
    364 				((uint64_t *)arrbuf)[i++]
    365 				    = atol((const char *)str);
    366 				xmlFree(str);
    367 			}
    368 		}
    369 
    370 		rv = nvlist_add_uint64_array(nvl, name, arrbuf,
    371 		    nelems);
    372 		free(arrbuf);
    373 		break;
    374 	case TOPO_TYPE_STRING_ARRAY:
    375 		for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
    376 			if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
    377 			    (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
    378 
    379 				if ((str = xmlGetProp(cn, (xmlChar *)Value))
    380 				    == NULL)
    381 					return (-1);
    382 
    383 				strarrbuf[i++] =
    384 				    topo_mod_strdup(mp, (const char *)str);
    385 				xmlFree(str);
    386 			}
    387 		}
    388 
    389 		rv = nvlist_add_string_array(nvl, name, strarrbuf, nelems);
    390 		strarr_free(mp, strarrbuf, nelems);
    391 		break;
    392 	case TOPO_TYPE_FMRI_ARRAY:
    393 		for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
    394 			if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
    395 			    (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
    396 
    397 				if ((str = xmlGetProp(xn, (xmlChar *)Value))
    398 				    == NULL)
    399 					return (-1);
    400 
    401 				if (topo_mod_str2nvl(mp, (const char *)str,
    402 				    &(nvlarrbuf[i++])) < 0) {
    403 					xmlFree(str);
    404 					return (-1);
    405 				}
    406 				xmlFree(str);
    407 			}
    408 		}
    409 
    410 		rv = nvlist_add_nvlist_array(nvl, name, nvlarrbuf,
    411 		    nelems);
    412 		free(nvlarrbuf);
    413 		break;
    414 	}
    415 
    416 	if (rv != 0) {
    417 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
    418 		    "Nvlist construction failed.\n");
    419 		return (topo_mod_seterrno(mp, ETOPO_NOMEM));
    420 	} else
    421 		return (0);
    422 }
    423 
    424 static int
    425 xmlprop_xlate(topo_mod_t *mp, xmlNodePtr xn, nvlist_t *nvl)
    426 {
    427 	topo_type_t ptype;
    428 	xmlChar *str;
    429 
    430 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "xmlprop_xlate\n");
    431 	if ((str = xmlGetProp(xn, (xmlChar *)Immutable)) != NULL) {
    432 		if (xmlStrcmp(str, (xmlChar *)False) == 0)
    433 			(void) nvlist_add_boolean_value(nvl, INV_IMMUTE,
    434 			    B_FALSE);
    435 		else
    436 			(void) nvlist_add_boolean_value(nvl, INV_IMMUTE,
    437 			    B_TRUE);
    438 		xmlFree(str);
    439 	} else {
    440 		(void) nvlist_add_boolean_value(nvl, INV_IMMUTE, B_TRUE);
    441 	}
    442 
    443 	if ((ptype = xmlattr_to_type(mp, xn, (xmlChar *)Type))
    444 	    == TOPO_TYPE_INVALID)
    445 		return (-1);
    446 
    447 	if (nvlist_add_int32(nvl, INV_PVALTYPE, ptype) != 0)
    448 		return (-1);
    449 
    450 	return (xlate_common(mp, xn, ptype, nvl, INV_PVAL));
    451 }
    452 
    453 static int
    454 dependent_create(topo_mod_t *mp,
    455     tf_info_t *xinfo, tf_pad_t *pad, xmlNodePtr dxn, tnode_t *ptn)
    456 {
    457 	tf_rdata_t *rp, *pp, *np;
    458 	xmlChar *grptype;
    459 	int sibs = 0;
    460 
    461 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "dependent_create\n");
    462 	if ((grptype = xmlGetProp(dxn, (xmlChar *)Grouping)) == NULL) {
    463 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
    464 		    "Dependents missing grouping attribute");
    465 		return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
    466 	}
    467 
    468 	pp = NULL;
    469 	if (xmlStrcmp(grptype, (xmlChar *)Siblings) == 0) {
    470 		rp = pad->tpad_sibs;
    471 		sibs++;
    472 	} else if (xmlStrcmp(grptype, (xmlChar *)Children) == 0) {
    473 		rp = pad->tpad_child;
    474 	} else {
    475 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
    476 		    "Dependents have bogus grouping attribute");
    477 		xmlFree(grptype);
    478 		return (topo_mod_seterrno(mp, ETOPO_PRSR_BADGRP));
    479 	}
    480 	xmlFree(grptype);
    481 	/* Add processed dependents to the tail of the list */
    482 	while (rp != NULL) {
    483 		pp = rp;
    484 		rp = rp->rd_next;
    485 	}
    486 	if ((np = topo_xml_walk(mp, xinfo, dxn, ptn)) == NULL) {
    487 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
    488 		    "error within dependent .xml topology: "
    489 		    "%s\n", topo_strerror(topo_mod_errno(mp)));
    490 		return (-1);
    491 	}
    492 	if (pp != NULL)
    493 		pp->rd_next = np;
    494 	else if (sibs == 1)
    495 		pad->tpad_sibs = np;
    496 	else
    497 		pad->tpad_child = np;
    498 	return (0);
    499 }
    500 
    501 static int
    502 dependents_create(topo_mod_t *mp,
    503     tf_info_t *xinfo, tf_pad_t *pad, xmlNodePtr pxn, tnode_t *ptn)
    504 {
    505 	xmlNodePtr cn;
    506 
    507 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "dependents_create\n");
    508 	for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
    509 		if (xmlStrcmp(cn->name, (xmlChar *)Dependents) == 0) {
    510 			if (dependent_create(mp, xinfo, pad, cn, ptn) < 0)
    511 				return (-1);
    512 		}
    513 	}
    514 	return (0);
    515 }
    516 
    517 static int
    518 prop_create(topo_mod_t *mp,
    519     nvlist_t *pfmri, tnode_t *ptn, const char *gnm, const char *pnm,
    520     topo_type_t ptype, int flag)
    521 {
    522 	nvlist_t *fmri, **fmriarr;
    523 	uint32_t ui32, *ui32arr;
    524 	uint64_t ui64, *ui64arr;
    525 	int32_t i32, *i32arr;
    526 	int64_t i64, *i64arr;
    527 	uint_t nelem;
    528 	char *str, **strarr;
    529 	int err, e;
    530 
    531 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "prop_create(pgrp = %s, "
    532 	    "prop = %s)\n", gnm, pnm);
    533 	switch (ptype) {
    534 	case TOPO_TYPE_INT32:
    535 		e = nvlist_lookup_int32(pfmri, INV_PVAL, &i32);
    536 		break;
    537 	case TOPO_TYPE_UINT32:
    538 		e = nvlist_lookup_uint32(pfmri, INV_PVAL, &ui32);
    539 		break;
    540 	case TOPO_TYPE_INT64:
    541 		e = nvlist_lookup_int64(pfmri, INV_PVAL, &i64);
    542 		break;
    543 	case TOPO_TYPE_UINT64:
    544 		e = nvlist_lookup_uint64(pfmri, INV_PVAL, &ui64);
    545 		break;
    546 	case TOPO_TYPE_FMRI:
    547 		e = nvlist_lookup_nvlist(pfmri, INV_PVAL, &fmri);
    548 		break;
    549 	case TOPO_TYPE_STRING:
    550 		e = nvlist_lookup_string(pfmri, INV_PVAL, &str);
    551 		break;
    552 	case TOPO_TYPE_INT32_ARRAY:
    553 		e = nvlist_lookup_int32_array(pfmri, INV_PVAL, &i32arr, &nelem);
    554 		break;
    555 	case TOPO_TYPE_UINT32_ARRAY:
    556 		e = nvlist_lookup_uint32_array(pfmri, INV_PVAL, &ui32arr,
    557 		    &nelem);
    558 		break;
    559 	case TOPO_TYPE_INT64_ARRAY:
    560 		e = nvlist_lookup_int64_array(pfmri, INV_PVAL, &i64arr,
    561 		    &nelem);
    562 		break;
    563 	case TOPO_TYPE_UINT64_ARRAY:
    564 		e = nvlist_lookup_uint64_array(pfmri, INV_PVAL, &ui64arr,
    565 		    &nelem);
    566 		break;
    567 	case TOPO_TYPE_STRING_ARRAY:
    568 		e = nvlist_lookup_string_array(pfmri, INV_PVAL, &strarr,
    569 		    &nelem);
    570 		break;
    571 	case TOPO_TYPE_FMRI_ARRAY:
    572 		e = nvlist_lookup_nvlist_array(pfmri, INV_PVAL, &fmriarr,
    573 		    &nelem);
    574 		break;
    575 	default:
    576 		e = ETOPO_PRSR_BADTYPE;
    577 	}
    578 	if (e != 0) {
    579 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
    580 		    "prop_create: prop value lookup failed.\n");
    581 		return (topo_mod_seterrno(mp, e));
    582 	}
    583 	switch (ptype) {
    584 	case TOPO_TYPE_INT32:
    585 		e = topo_prop_set_int32(ptn, gnm, pnm, flag, i32, &err);
    586 		break;
    587 	case TOPO_TYPE_UINT32:
    588 		e = topo_prop_set_uint32(ptn, gnm, pnm, flag, ui32, &err);
    589 		break;
    590 	case TOPO_TYPE_INT64:
    591 		e = topo_prop_set_int64(ptn, gnm, pnm, flag, i64, &err);
    592 		break;
    593 	case TOPO_TYPE_UINT64:
    594 		e = topo_prop_set_uint64(ptn, gnm, pnm, flag, ui64, &err);
    595 		break;
    596 	case TOPO_TYPE_FMRI:
    597 		e = topo_prop_set_fmri(ptn, gnm, pnm, flag, fmri, &err);
    598 		break;
    599 	case TOPO_TYPE_STRING:
    600 		e = topo_prop_set_string(ptn, gnm, pnm, flag, str, &err);
    601 		break;
    602 	case TOPO_TYPE_INT32_ARRAY:
    603 		e = topo_prop_set_int32_array(ptn, gnm, pnm, flag, i32arr,
    604 		    nelem, &err);
    605 		break;
    606 	case TOPO_TYPE_UINT32_ARRAY:
    607 		e = topo_prop_set_uint32_array(ptn, gnm, pnm, flag, ui32arr,
    608 		    nelem, &err);
    609 		break;
    610 	case TOPO_TYPE_INT64_ARRAY:
    611 		e = topo_prop_set_int64_array(ptn, gnm, pnm, flag, i64arr,
    612 		    nelem, &err);
    613 		break;
    614 	case TOPO_TYPE_UINT64_ARRAY:
    615 		e = topo_prop_set_uint64_array(ptn, gnm, pnm, flag, ui64arr,
    616 		    nelem, &err);
    617 		break;
    618 	case TOPO_TYPE_STRING_ARRAY:
    619 		e = topo_prop_set_string_array(ptn, gnm, pnm, flag,
    620 		    (const char **)strarr, nelem, &err);
    621 		break;
    622 	case TOPO_TYPE_FMRI_ARRAY:
    623 		e = topo_prop_set_fmri_array(ptn, gnm, pnm, flag,
    624 		    (const nvlist_t **)fmriarr, nelem, &err);
    625 		break;
    626 	}
    627 	if (e != 0 && err != ETOPO_PROP_DEFD) {
    628 
    629 		/*
    630 		 * Some properties may have already been set
    631 		 * in topo_node_bind() or topo_prop_inherit if we are
    632 		 * enumerating from a static .xml file
    633 		 */
    634 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "prop set "
    635 		    "failed %s/%s:%s\n", gnm, pnm, topo_strerror(err));
    636 		return (topo_mod_seterrno(mp, err));
    637 	}
    638 	return (0);
    639 }
    640 
    641 static int
    642 props_create(topo_mod_t *mp,
    643     tnode_t *ptn, const char *gnm, nvlist_t **props, int nprops)
    644 {
    645 	topo_type_t ptype;
    646 	boolean_t pim;
    647 	char *pnm;
    648 	int32_t i32;
    649 	int flag;
    650 	int pn;
    651 	int e;
    652 
    653 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "props_create(pgrp = %s)\n",
    654 	    gnm);
    655 	for (pn = 0; pn < nprops; pn++) {
    656 		e = nvlist_lookup_string(props[pn], INV_PNAME, &pnm);
    657 		if (e != 0) {
    658 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
    659 			    "props create lookup (%s) failure: %s",
    660 			    INV_PNAME, strerror(e));
    661 			return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
    662 		}
    663 		e = nvlist_lookup_boolean_value(props[pn], INV_IMMUTE, &pim);
    664 		if (e != 0) {
    665 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
    666 			    "props create lookup (%s) failure: %s",
    667 			    INV_IMMUTE, strerror(e));
    668 			return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
    669 		}
    670 		flag = (pim == B_TRUE) ?
    671 		    TOPO_PROP_IMMUTABLE : TOPO_PROP_MUTABLE;
    672 
    673 		e = nvlist_lookup_int32(props[pn], INV_PVALTYPE, &i32);
    674 		if (e != 0) {
    675 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
    676 			    "props create lookup (%s) failure: %s",
    677 			    INV_PVALTYPE, strerror(e));
    678 			return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
    679 		}
    680 		ptype = (topo_type_t)i32;
    681 		if (prop_create(mp, props[pn], ptn, gnm, pnm, ptype, flag) < 0)
    682 			return (-1);
    683 	}
    684 	return (0);
    685 }
    686 
    687 static int
    688 pgroups_create(topo_mod_t *mp, tf_pad_t *pad, tnode_t *ptn)
    689 {
    690 	topo_pgroup_info_t pgi;
    691 	nvlist_t **props;
    692 	char *gnm;
    693 	char *nmstab, *dstab;
    694 	uint32_t rnprops, nprops;
    695 	uint32_t gv;
    696 	int pg;
    697 	int e;
    698 
    699 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroups_create: %s=%d\n",
    700 	    topo_node_name(ptn), topo_node_instance(ptn));
    701 	for (pg = 0; pg < pad->tpad_pgcnt; pg++) {
    702 		e = nvlist_lookup_string(pad->tpad_pgs[pg],
    703 		    INV_PGRP_NAME, &gnm);
    704 		if (e != 0) {
    705 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
    706 			    "pad lookup (%s) failed (%s).\n",
    707 			    INV_PGRP_NAME, strerror(errno));
    708 			return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
    709 		}
    710 		e = nvlist_lookup_string(pad->tpad_pgs[pg],
    711 		    INV_PGRP_NMSTAB, &nmstab);
    712 		if (e != 0) {
    713 			if (e != ENOENT) {
    714 				topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
    715 				    "pad lookup (%s) "
    716 				    "failed.\n", INV_PGRP_NMSTAB);
    717 				return (topo_mod_seterrno(mp,
    718 				    ETOPO_PRSR_NVPROP));
    719 			} else {
    720 				nmstab = TOPO_STABSTR_PRIVATE;
    721 			}
    722 		}
    723 		e = nvlist_lookup_string(pad->tpad_pgs[pg],
    724 		    INV_PGRP_DSTAB, &dstab);
    725 		if (e != 0) {
    726 			if (e != ENOENT) {
    727 				topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
    728 				    "pad lookup (%s) failed.\n",
    729 				    INV_PGRP_DSTAB);
    730 				return (topo_mod_seterrno(mp,
    731 				    ETOPO_PRSR_NVPROP));
    732 			} else {
    733 				dstab = TOPO_STABSTR_PRIVATE;
    734 			}
    735 		}
    736 		e = nvlist_lookup_uint32(pad->tpad_pgs[pg],
    737 		    INV_PGRP_VER, &gv);
    738 		if (e != 0) {
    739 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
    740 			    "pad lookup (%s) failed.\n",
    741 			    INV_PGRP_VER);
    742 			return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
    743 		}
    744 		pgi.tpi_name = gnm;
    745 		pgi.tpi_namestab = topo_name2stability(nmstab);
    746 		pgi.tpi_datastab = topo_name2stability(dstab);
    747 		pgi.tpi_version = gv;
    748 		if (topo_pgroup_create(ptn, &pgi, &e) != 0) {
    749 			if (e != ETOPO_PROP_DEFD) {
    750 				topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
    751 				    "pgroups create failure: %s\n",
    752 				    topo_strerror(e));
    753 				return (-1);
    754 			}
    755 		}
    756 		e = nvlist_lookup_uint32(pad->tpad_pgs[pg],
    757 		    INV_PGRP_NPROP, &rnprops);
    758 		/*
    759 		 * The number of properties could be zero if the property
    760 		 * group only contains propmethod declarations
    761 		 */
    762 		if (rnprops > 0) {
    763 			e |= nvlist_lookup_nvlist_array(pad->tpad_pgs[pg],
    764 			    INV_PGRP_ALLPROPS, &props, &nprops);
    765 			if (rnprops != nprops) {
    766 				topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
    767 				    "recorded number of props %d does not "
    768 				    "match number of props recorded %d.\n",
    769 				    rnprops, nprops);
    770 			}
    771 			if (props_create(mp, ptn, gnm, props, nprops) < 0)
    772 				return (-1);
    773 		}
    774 	}
    775 	return (0);
    776 }
    777 
    778 static nvlist_t *
    779 pval_record(topo_mod_t *mp, xmlNodePtr xn)
    780 {
    781 	nvlist_t *pnvl = NULL;
    782 	xmlChar *pname;
    783 
    784 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pval_record\n");
    785 	if ((pname = xmlGetProp(xn, (xmlChar *)Name)) == NULL) {
    786 		topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
    787 		    "propval lacks a name\n");
    788 		(void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
    789 		return (NULL);
    790 	}
    791 	if (topo_mod_nvalloc(mp, &pnvl, NV_UNIQUE_NAME) < 0) {
    792 		xmlFree(pname);
    793 		return (NULL);
    794 	}
    795 	if (nvlist_add_string(pnvl, INV_PNAME, (char *)pname) < 0) {
    796 		xmlFree(pname);
    797 		nvlist_free(pnvl);
    798 		return (NULL);
    799 	}
    800 	xmlFree(pname);
    801 	/* FMXXX stability of the property name */
    802 
    803 	if (xmlprop_xlate(mp, xn, pnvl) < 0) {
    804 		nvlist_free(pnvl);
    805 		return (NULL);
    806 	}
    807 	return (pnvl);
    808 }
    809 
    810 
    811 struct propmeth_data {
    812 	const char *pg_name;
    813 	const char *prop_name;
    814 	topo_type_t prop_type;
    815 	const char *meth_name;
    816 	topo_version_t meth_ver;
    817 	nvlist_t *arg_nvl;
    818 };
    819 
    820 static int
    821 register_method(topo_mod_t *mp, tnode_t *ptn, struct propmeth_data *meth)
    822 {
    823 	int err;
    824 
    825 	if (topo_prop_method_version_register(ptn, meth->pg_name,
    826 	    meth->prop_name, meth->prop_type, meth->meth_name, meth->meth_ver,
    827 	    meth->arg_nvl, &err) != 0) {
    828 
    829 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "failed to register "
    830 		    "propmethod %s for property \"%s\" in propgrp %s on node "
    831 		    "%s=%d (%s)\n",
    832 		    meth->meth_name, meth->prop_name, meth->pg_name,
    833 		    topo_node_name(ptn), topo_node_instance(ptn),
    834 		    topo_strerror(err));
    835 		return (-1);
    836 	}
    837 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
    838 	    "registered method %s on %s=%d\n",
    839 	    meth->meth_name, topo_node_name(ptn), topo_node_instance(ptn));
    840 
    841 	return (0);
    842 }
    843 
    844 static int
    845 pmeth_record(topo_mod_t *mp, const char *pg_name, xmlNodePtr xn, tnode_t *tn,
    846     const char *rname, const char *ppgrp_name)
    847 {
    848 	nvlist_t *arg_nvl = NULL;
    849 	xmlNodePtr cn;
    850 	xmlChar *meth_name = NULL, *prop_name = NULL;
    851 	xmlChar *arg_name = NULL;
    852 	uint64_t meth_ver, is_mutable = 0, is_nonvolatile = 0;
    853 	topo_type_t prop_type;
    854 	struct propmeth_data meth;
    855 	int ret = 0, err;
    856 	topo_type_t ptype;
    857 	tnode_t *tmp;
    858 
    859 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pmeth_record: %s=%d "
    860 	    "(pgrp=%s)\n", topo_node_name(tn), topo_node_instance(tn), pg_name);
    861 
    862 	/*
    863 	 * Get propmethod attribute values
    864 	 */
    865 	if ((meth_name = xmlGetProp(xn, (xmlChar *)Name)) == NULL) {
    866 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
    867 		    "propmethod element lacks a name attribute\n");
    868 		return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
    869 	}
    870 	if (xmlattr_to_int(mp, xn, Version, &meth_ver) < 0) {
    871 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
    872 		    "propmethod element lacks version attribute\n");
    873 		ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
    874 		goto pmr_done;
    875 	}
    876 	/*
    877 	 * The "mutable" and "nonvoltile" attributes are optional.  If not
    878 	 * specified we default to false (0)
    879 	 */
    880 	(void) xmlattr_to_int(mp, xn, Mutable, &is_mutable);
    881 	(void) xmlattr_to_int(mp, xn, Nonvolatile, &is_nonvolatile);
    882 
    883 	if ((prop_name = xmlGetProp(xn, (xmlChar *)Propname)) == NULL) {
    884 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
    885 		    "propmethod element lacks propname attribute\n");
    886 		ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
    887 		goto pmr_done;
    888 	}
    889 	if ((prop_type = xmlattr_to_type(mp, xn, (xmlChar *)Proptype))
    890 	    == TOPO_TYPE_INVALID) {
    891 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
    892 		    "error decoding proptype attribute\n");
    893 		ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
    894 		goto pmr_done;
    895 	}
    896 
    897 	/*
    898 	 * Allocate method argument nvlist
    899 	 */
    900 	if (topo_mod_nvalloc(mp, &arg_nvl, NV_UNIQUE_NAME) < 0) {
    901 		ret = topo_mod_seterrno(mp, ETOPO_NOMEM);
    902 		goto pmr_done;
    903 	}
    904 
    905 	/*
    906 	 * Iterate through the argval nodes and build the argval nvlist
    907 	 */
    908 	for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
    909 		if (xmlStrcmp(cn->name, (xmlChar *)Argval) == 0) {
    910 			topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
    911 			    "found argval element\n");
    912 			if ((arg_name = xmlGetProp(cn, (xmlChar *)Name))
    913 			    == NULL) {
    914 				topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
    915 				    "argval element lacks a name attribute\n");
    916 				ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
    917 				goto pmr_done;
    918 			}
    919 			if ((ptype = xmlattr_to_type(mp, cn, (xmlChar *)Type))
    920 			    == TOPO_TYPE_INVALID) {
    921 				ret = topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE);
    922 				xmlFree(arg_name);
    923 				break;
    924 			}
    925 			if (xlate_common(mp, cn, ptype, arg_nvl,
    926 			    (const char *)arg_name) != 0) {
    927 				ret = topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE);
    928 				xmlFree(arg_name);
    929 				break;
    930 			}
    931 		}
    932 		if (arg_name) {
    933 			xmlFree(arg_name);
    934 			arg_name = NULL;
    935 		}
    936 	}
    937 
    938 	if (ret != 0)
    939 		goto pmr_done;
    940 
    941 	/*
    942 	 * Register the prop method for all of the nodes in our range
    943 	 */
    944 	meth.pg_name = (const char *)pg_name;
    945 	meth.prop_name = (const char *)prop_name;
    946 	meth.prop_type = prop_type;
    947 	meth.meth_name = (const char *)meth_name;
    948 	meth.meth_ver = meth_ver;
    949 	meth.arg_nvl = arg_nvl;
    950 
    951 	/*
    952 	 * If the propgroup element is under a range element, we'll apply
    953 	 * the method to all of the topo nodes at this level with the same
    954 	 * range name.
    955 	 *
    956 	 * Otherwise, if the propgroup element is under a node element
    957 	 * then we'll simply register the method for this node.
    958 	 */
    959 	if (strcmp(ppgrp_name, Range) == 0) {
    960 		for (tmp = tn; tmp != NULL; tmp = topo_child_next(NULL, tmp)) {
    961 			if (strcmp(rname, topo_node_name(tmp)) == 0) {
    962 				if (register_method(mp, tmp, &meth) != 0) {
    963 					ret = topo_mod_seterrno(mp,
    964 					    ETOPO_PRSR_REGMETH);
    965 					goto pmr_done;
    966 				}
    967 				if (is_mutable) {
    968 					if (topo_prop_setmutable(tmp,
    969 					    meth.pg_name, meth.prop_name, &err)
    970 					    != 0) {
    971 						ret = topo_mod_seterrno(mp,
    972 						    ETOPO_PRSR_REGMETH);
    973 						goto pmr_done;
    974 					}
    975 				}
    976 				if (is_nonvolatile) {
    977 					if (topo_prop_setnonvolatile(tmp,
    978 					    meth.pg_name, meth.prop_name, &err)
    979 					    != 0) {
    980 						ret = topo_mod_seterrno(mp,
    981 						    ETOPO_PRSR_REGMETH);
    982 						goto pmr_done;
    983 					}
    984 				}
    985 			}
    986 		}
    987 	} else {
    988 		if (register_method(mp, tn, &meth) != 0) {
    989 			ret = topo_mod_seterrno(mp, ETOPO_PRSR_REGMETH);
    990 			goto pmr_done;
    991 		}
    992 		if (is_mutable) {
    993 			if (topo_prop_setmutable(tn, meth.pg_name,
    994 			    meth.prop_name, &err) != 0) {
    995 				ret = topo_mod_seterrno(mp,
    996 				    ETOPO_PRSR_REGMETH);
    997 				goto pmr_done;
    998 			}
    999 		}
   1000 		if (is_nonvolatile) {
   1001 			if (topo_prop_setnonvolatile(tn, meth.pg_name,
   1002 			    meth.prop_name, &err) != 0) {
   1003 				ret = topo_mod_seterrno(mp,
   1004 				    ETOPO_PRSR_REGMETH);
   1005 				goto pmr_done;
   1006 			}
   1007 		}
   1008 	}
   1009 
   1010 pmr_done:
   1011 	if (meth_name)
   1012 		xmlFree(meth_name);
   1013 	if (prop_name)
   1014 		xmlFree(prop_name);
   1015 	if (arg_nvl)
   1016 		nvlist_free(arg_nvl);
   1017 	return (ret);
   1018 }
   1019 
   1020 
   1021 static int
   1022 pgroup_record(topo_mod_t *mp, xmlNodePtr pxn, tnode_t *tn, const char *rname,
   1023     tf_pad_t *rpad, int pi, const char *ppgrp_name)
   1024 {
   1025 	topo_stability_t nmstab, dstab;
   1026 	uint64_t ver;
   1027 	xmlNodePtr cn;
   1028 	xmlChar *name;
   1029 	nvlist_t **apl = NULL;
   1030 	nvlist_t *pgnvl = NULL;
   1031 	int pcnt = 0;
   1032 	int ai = 0;
   1033 	int e;
   1034 
   1035 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroup_record\n");
   1036 	if ((name = xmlGetProp(pxn, (xmlChar *)Name)) == NULL) {
   1037 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
   1038 		    "propgroup lacks a name\n");
   1039 		return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
   1040 	}
   1041 	if (xmlattr_to_int(mp, pxn, Version, &ver) < 0) {
   1042 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
   1043 		    "propgroup lacks a version\n");
   1044 		return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
   1045 	}
   1046 	if (xmlattr_to_stab(mp, pxn, Namestab, &nmstab) < 0) {
   1047 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
   1048 		    "propgroup lacks name-stability\n");
   1049 		return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
   1050 	}
   1051 	if (xmlattr_to_stab(mp, pxn, Datastab, &dstab) < 0) {
   1052 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
   1053 		    "propgroup lacks data-stability\n");
   1054 		return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
   1055 	}
   1056 
   1057 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroup %s\n", (char *)name);
   1058 	for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
   1059 		if (xmlStrcmp(cn->name, (xmlChar *)Propval) == 0)
   1060 			pcnt++;
   1061 	}
   1062 
   1063 	if (topo_mod_nvalloc(mp, &pgnvl, NV_UNIQUE_NAME) < 0) {
   1064 		xmlFree(name);
   1065 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
   1066 		    "failed to allocate propgroup nvlist\n");
   1067 		return (topo_mod_seterrno(mp, ETOPO_NOMEM));
   1068 	}
   1069 
   1070 	e = nvlist_add_string(pgnvl, INV_PGRP_NAME, (char *)name);
   1071 	e |= nvlist_add_uint32(pgnvl, INV_PGRP_NMSTAB, nmstab);
   1072 	e |= nvlist_add_uint32(pgnvl, INV_PGRP_DSTAB, dstab);
   1073 	e |= nvlist_add_uint32(pgnvl, INV_PGRP_VER, ver);
   1074 	e |= nvlist_add_uint32(pgnvl, INV_PGRP_NPROP, pcnt);
   1075 	if (pcnt > 0)
   1076 		if (e != 0 ||
   1077 		    (apl = topo_mod_zalloc(mp, pcnt * sizeof (nvlist_t *)))
   1078 		    == NULL) {
   1079 			xmlFree(name);
   1080 			nvlist_free(pgnvl);
   1081 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
   1082 			    "failed to allocate nvlist array for properties"
   1083 			    "(e=%d)\n", e);
   1084 			return (topo_mod_seterrno(mp, ETOPO_NOMEM));
   1085 		}
   1086 	for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
   1087 		if (xmlStrcmp(cn->name, (xmlChar *)Propval) == 0) {
   1088 			if (ai < pcnt) {
   1089 				if ((apl[ai] = pval_record(mp, cn)) == NULL)
   1090 					break;
   1091 			}
   1092 			ai++;
   1093 		} else if (xmlStrcmp(cn->name, (xmlChar *)Prop_meth) == 0) {
   1094 			if (pmeth_record(mp, (const char *)name, cn, tn, rname,
   1095 			    ppgrp_name) < 0)
   1096 				break;
   1097 		}
   1098 	}
   1099 	xmlFree(name);
   1100 	if (pcnt > 0) {
   1101 		e |= (ai != pcnt);
   1102 		e |= nvlist_add_nvlist_array(pgnvl, INV_PGRP_ALLPROPS, apl,
   1103 		    pcnt);
   1104 		for (ai = 0; ai < pcnt; ai++)
   1105 			if (apl[ai] != NULL)
   1106 				nvlist_free(apl[ai]);
   1107 		topo_mod_free(mp, apl, pcnt * sizeof (nvlist_t *));
   1108 		if (e != 0) {
   1109 			nvlist_free(pgnvl);
   1110 			return (-1);
   1111 		}
   1112 	}
   1113 	rpad->tpad_pgs[pi] = pgnvl;
   1114 	return (0);
   1115 }
   1116 
   1117 static int
   1118 pgroups_record(topo_mod_t *mp, xmlNodePtr pxn, tnode_t *tn, const char *rname,
   1119     tf_pad_t *rpad, const char *ppgrp)
   1120 {
   1121 	xmlNodePtr cn;
   1122 	int pi = 0;
   1123 
   1124 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroups_record: pxn->name=%s\n",
   1125 	    pxn->name);
   1126 	for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
   1127 		if (xmlStrcmp(cn->name, (xmlChar *)Propgrp) == 0) {
   1128 			if (pgroup_record(mp, cn, tn, rname, rpad, pi++, ppgrp)
   1129 			    < 0)
   1130 				return (-1);
   1131 		}
   1132 	}
   1133 	return (0);
   1134 }
   1135 
   1136 /*
   1137  * psn:	pointer to a "set" XML node
   1138  * key: string to search the set for
   1139  *
   1140  * returns: 1, if the set contains key
   1141  *          0, otherwise
   1142  */
   1143 static int
   1144 set_contains(topo_mod_t *mp, char *key, char *set)
   1145 {
   1146 	char *prod;
   1147 	int rv = 0;
   1148 
   1149 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "set_contains(key = %s, "
   1150 	    "setlist = %s)\n", key, set);
   1151 
   1152 	prod = strtok((char *)set, "|");
   1153 	if (prod && (strcmp(key, prod) == 0))
   1154 		return (1);
   1155 
   1156 	while ((prod = strtok(NULL, "|")))
   1157 		if (strcmp(key, prod) == 0)
   1158 			return (1);
   1159 
   1160 	return (rv);
   1161 }
   1162 
   1163 
   1164 /*
   1165  * Process the property group and dependents xmlNode children of
   1166  * parent xmlNode pxn.
   1167  */
   1168 static int
   1169 pad_process(topo_mod_t *mp, tf_rdata_t *rd, xmlNodePtr pxn, tnode_t *ptn,
   1170     tf_pad_t **rpad)
   1171 {
   1172 	xmlNodePtr cn, gcn, psn, ecn, target;
   1173 	xmlNodePtr def_set = NULL;
   1174 	tnode_t *ct;
   1175 	tf_pad_t *new = *rpad;
   1176 	tf_rdata_t tmp_rd;
   1177 	int pgcnt = 0;
   1178 	int dcnt = 0;
   1179 	int ecnt = 0;
   1180 	int joined_set = 0;
   1181 	xmlChar *set;
   1182 	char *key;
   1183 
   1184 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
   1185 	    "pad_process beneath %s=%d\n", topo_node_name(ptn),
   1186 	    topo_node_instance(ptn));
   1187 	if (new == NULL) {
   1188 		for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
   1189 			topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
   1190 			    "cn->name is %s \n", (char *)cn->name);
   1191 			/*
   1192 			 * We're iterating through the XML children looking for
   1193 			 * four types of elements:
   1194 			 *   1) dependents elements
   1195 			 *   2) unconstrained pgroup elements
   1196 			 *   3) pgroup elements constrained by set elements
   1197 			 *   4) enum-method elements for the case that we want
   1198 			 *	to post-process a statically defined node
   1199 			 */
   1200 			if (xmlStrcmp(cn->name, (xmlChar *)Dependents) == 0)
   1201 				dcnt++;
   1202 			else if (xmlStrcmp(cn->name, (xmlChar *)Propgrp) == 0)
   1203 				pgcnt++;
   1204 			else if (xmlStrcmp(cn->name, (xmlChar *)Enum_meth)
   1205 			    == 0) {
   1206 				ecn = cn;
   1207 				ecnt++;
   1208 			} else if (xmlStrcmp(cn->name, (xmlChar *)Set) == 0) {
   1209 				if (joined_set)
   1210 					continue;
   1211 				set = xmlGetProp(cn, (xmlChar *)Setlist);
   1212 
   1213 				if (mp->tm_hdl->th_product)
   1214 					key = mp->tm_hdl->th_product;
   1215 				else
   1216 					key = mp->tm_hdl->th_platform;
   1217 
   1218 				/*
   1219 				 * If it's the default set then we'll store
   1220 				 * a pointer to it so that if none of the other
   1221 				 * sets apply to our product we can fall
   1222 				 * back to this one.
   1223 				 */
   1224 				if (strcmp((char *)set, "default") == 0)
   1225 					def_set = cn;
   1226 				else if (set_contains(mp, key, (char *)set)) {
   1227 					psn = cn;
   1228 					joined_set = 1;
   1229 					for (gcn = cn->xmlChildrenNode;
   1230 					    gcn != NULL; gcn = gcn->next) {
   1231 						if (xmlStrcmp(gcn->name,
   1232 						    (xmlChar *)Propgrp) == 0)
   1233 							pgcnt++;
   1234 					}
   1235 				}
   1236 				xmlFree(set);
   1237 			}
   1238 		}
   1239 		/*
   1240 		 * If we haven't found a set that contains our product AND
   1241 		 * a default set exists, then we'll process it.
   1242 		 */
   1243 		if (!joined_set && def_set) {
   1244 			topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
   1245 			    "Falling back to default set\n");
   1246 			joined_set = 1;
   1247 			psn = def_set;
   1248 			for (gcn = psn->xmlChildrenNode; gcn != NULL;
   1249 			    gcn = gcn->next) {
   1250 				if (xmlStrcmp(gcn->name, (xmlChar *)Propgrp)
   1251 				    == 0)
   1252 					pgcnt++;
   1253 			}
   1254 		}
   1255 		topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
   1256 		    "pad_process: dcnt=%d, pgcnt=%d, ecnt=%d, joined_set=%d\n",
   1257 		    dcnt, pgcnt, ecnt, joined_set);
   1258 		/*
   1259 		 * If an enum-method element was found, AND we're a child of a
   1260 		 * node element, then we invoke the enumerator so that it can do
   1261 		 * post-processing of the node.
   1262 		 */
   1263 		if (ecnt && (strcmp((const char *)pxn->name, Node) == 0)) {
   1264 			if ((tmp_rd.rd_einfo = enum_attributes_process(mp, ecn))
   1265 			    == NULL)
   1266 				return (-1);
   1267 			tmp_rd.rd_mod = mp;
   1268 			tmp_rd.rd_name = rd->rd_name;
   1269 			tmp_rd.rd_min = rd->rd_min;
   1270 			tmp_rd.rd_max = rd->rd_max;
   1271 			tmp_rd.rd_pn = ptn;
   1272 			if (enum_run(mp, &tmp_rd) < 0) {
   1273 				/*
   1274 				 * Note the failure but continue on
   1275 				 */
   1276 				topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
   1277 				    "pad_process: enumeration failed.\n");
   1278 			}
   1279 			tf_edata_free(mp, tmp_rd.rd_einfo);
   1280 		}
   1281 		/*
   1282 		 * Here we allocate an element in an intermediate data structure
   1283 		 * which keeps track property groups and dependents of the range
   1284 		 * currently being processed.
   1285 		 *
   1286 		 * This structure is referenced in pgroups_record() to create
   1287 		 * the actual property groups in the topo tree
   1288 		 */
   1289 		if ((new = tf_pad_new(mp, pgcnt, dcnt)) == NULL)
   1290 			return (-1);
   1291 
   1292 		if (pgcnt > 0) {
   1293 			new->tpad_pgs =
   1294 			    topo_mod_zalloc(mp, pgcnt * sizeof (nvlist_t *));
   1295 			if (new->tpad_pgs == NULL) {
   1296 				tf_pad_free(mp, new);
   1297 				return (-1);
   1298 			}
   1299 		}
   1300 		/*
   1301 		 * If the property groups are contained within a set
   1302 		 * then they will be one level lower in the XML tree.
   1303 		 */
   1304 		if (joined_set)
   1305 			target = psn;
   1306 		else
   1307 			target = pxn;
   1308 
   1309 		/*
   1310 		 * If there is no "node" element under the "range"
   1311 		 * element, then we need to attach the facility node to
   1312 		 * each node in this range.
   1313 		 *
   1314 		 * Otherwise we only attach it to the current node
   1315 		 */
   1316 		if (xmlStrcmp(target->name, (xmlChar *)Range) == 0 ||
   1317 		    xmlStrcmp(target->name, (xmlChar *)Set) == 0) {
   1318 			for (ct = topo_child_first(rd->rd_pn);
   1319 			    ct != NULL;
   1320 			    ct = topo_child_next(rd->rd_pn, ct)) {
   1321 
   1322 				if (strcmp(topo_node_name(ct),
   1323 				    rd->rd_name) != 0)
   1324 					continue;
   1325 
   1326 				if (fac_enum_process(mp, target, ct) < 0)
   1327 						return (-1);
   1328 
   1329 				if (fac_process(mp, target, rd, ct) < 0)
   1330 					return (-1);
   1331 			}
   1332 		} else {
   1333 			if (fac_enum_process(mp, target, ptn) < 0)
   1334 				return (-1);
   1335 			if (fac_process(mp, target, rd, ptn) < 0)
   1336 				return (-1);
   1337 		}
   1338 		if (pgcnt > 0 && pgroups_record(mp, target, ptn, rd->rd_name,
   1339 		    new, (const char *)pxn->name) < 0) {
   1340 			tf_pad_free(mp, new);
   1341 			return (-1);
   1342 		}
   1343 		*rpad = new;
   1344 	}
   1345 
   1346 	if (new->tpad_dcnt > 0)
   1347 		if (dependents_create(mp, rd->rd_finfo, new, pxn, ptn) < 0)
   1348 			return (-1);
   1349 
   1350 	if (new->tpad_pgcnt > 0)
   1351 		if (pgroups_create(mp, new, ptn) < 0)
   1352 			return (-1);
   1353 
   1354 	return (0);
   1355 }
   1356 
   1357 
   1358 static int
   1359 fac_enum_process(topo_mod_t *mp, xmlNodePtr pn, tnode_t *ptn)
   1360 {
   1361 	xmlNodePtr cn;
   1362 	xmlChar *fprov = NULL;
   1363 	int rv = 0;
   1364 
   1365 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
   1366 	    "fac_enum_process() called for %s=%d\n", topo_node_name(ptn),
   1367 	    topo_node_instance(ptn));
   1368 
   1369 	for (cn = pn->xmlChildrenNode; cn != NULL; cn = cn->next) {
   1370 
   1371 		if (xmlStrcmp(cn->name, (xmlChar *)"fac-enum") != 0)
   1372 			continue;
   1373 
   1374 		if ((fprov = xmlGetProp(cn, (xmlChar *)Provider)) == NULL)
   1375 			goto fenumdone;
   1376 
   1377 		if (xmlStrcmp(fprov, (xmlChar *)"fac_prov_ipmi") != 0) {
   1378 			topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
   1379 			    "Invalid provider specified: %s\n", fprov);
   1380 			goto fenumdone;
   1381 		}
   1382 
   1383 		/*
   1384 		 * Invoke enum entry point in fac provider which will cause the
   1385 		 * facility enumeration node method to be registered.
   1386 		 */
   1387 		if (fac_enum_run(mp, ptn, (const char *)fprov) != 0) {
   1388 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
   1389 			    "fac_enum_process: enum entry point failed!\n");
   1390 			goto fenumdone;
   1391 		}
   1392 		xmlFree(fprov);
   1393 	}
   1394 	return (0);
   1395 fenumdone:
   1396 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "fac-enum processing failed\n");
   1397 
   1398 	if (fprov != NULL)
   1399 		xmlFree(fprov);
   1400 
   1401 	return (rv);
   1402 }
   1403 
   1404 
   1405 static int
   1406 fac_process(topo_mod_t *mp, xmlNodePtr pn, tf_rdata_t *rd, tnode_t *ptn)
   1407 {
   1408 	xmlNodePtr cn;
   1409 	xmlChar *fname = NULL, *ftype = NULL, *provider = NULL;
   1410 	tnode_t *ntn = NULL;
   1411 	tf_idata_t *newi;
   1412 	int err;
   1413 	topo_pgroup_info_t pgi;
   1414 
   1415 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
   1416 	    "fac_process() called for %s=%d\n", topo_node_name(ptn),
   1417 	    topo_node_instance(ptn));
   1418 
   1419 	for (cn = pn->xmlChildrenNode; cn != NULL; cn = cn->next) {
   1420 
   1421 		if (xmlStrcmp(cn->name, (xmlChar *)Facility) != 0)
   1422 			continue;
   1423 
   1424 		if ((fname = xmlGetProp(cn, (xmlChar *)Name)) == NULL)
   1425 			goto facdone;
   1426 
   1427 		topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
   1428 		    "processing facility node '%s'\n", fname);
   1429 
   1430 		if ((ftype = xmlGetProp(cn, (xmlChar *)Type)) == NULL)
   1431 			goto facdone;
   1432 
   1433 		if ((provider = xmlGetProp(cn, (xmlChar *)Provider)) == NULL)
   1434 			goto facdone;
   1435 
   1436 		if (xmlStrcmp(ftype, (xmlChar *)Sensor) != 0 &&
   1437 		    xmlStrcmp(ftype, (xmlChar *)Indicator) != 0)
   1438 			goto facdone;
   1439 
   1440 		if (xmlStrcmp(provider, (xmlChar *)"fac_prov_ipmi") != 0) {
   1441 			topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "fac_process: "
   1442 			    "Invalid provider attr value: %s\n", provider);
   1443 			goto facdone;
   1444 		}
   1445 
   1446 		if ((ntn = topo_node_facbind(mp, ptn, (char *)fname,
   1447 		    (char *)ftype)) == NULL)
   1448 			goto facdone;
   1449 
   1450 		pgi.tpi_name = TOPO_PGROUP_FACILITY;
   1451 		pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
   1452 		pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
   1453 		pgi.tpi_version = 1;
   1454 		if (topo_pgroup_create(ntn, &pgi, &err) != 0) {
   1455 			if (err != ETOPO_PROP_DEFD) {
   1456 				topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
   1457 				    "pgroups create failure: %s\n",
   1458 				    topo_strerror(err));
   1459 				return (-1);
   1460 			}
   1461 		}
   1462 		/*
   1463 		 * Invoke enum entry point in fac_prov_ipmi module, which will
   1464 		 * cause the provider methods to be registered on this node
   1465 		 */
   1466 		if (fac_enum_run(mp, ntn, (const char *)provider) != 0) {
   1467 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "fac_process: "
   1468 			    "enum entry point failed for provider %s!\n",
   1469 			    provider);
   1470 			goto facdone;
   1471 		}
   1472 
   1473 		if ((newi = tf_idata_new(mp, 0, ntn)) == NULL)
   1474 			goto facdone;
   1475 
   1476 		if (tf_idata_insert(&rd->rd_instances, newi) < 0)
   1477 			goto facdone;
   1478 
   1479 		if (pad_process(mp, rd, cn, ntn, &newi->ti_pad) < 0)
   1480 			goto facdone;
   1481 
   1482 		topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "done with "
   1483 		    "facility %s=%s.\n", ftype, fname);
   1484 
   1485 		xmlFree(ftype);
   1486 		xmlFree(fname);
   1487 		xmlFree(provider);
   1488 	}
   1489 
   1490 	return (0);
   1491 
   1492 facdone:
   1493 	topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "facility processing failed\n");
   1494 
   1495 	if (ftype != NULL)
   1496 		xmlFree(ftype);
   1497 	if (fname != NULL)
   1498 		xmlFree(fname);
   1499 	if (provider != NULL)
   1500 		xmlFree(provider);
   1501 	if (ntn != NULL)
   1502 		topo_node_unbind(ntn);
   1503 
   1504 	return (0);
   1505 }
   1506 
   1507 static int
   1508 node_process(topo_mod_t *mp, xmlNodePtr nn, tf_rdata_t *rd)
   1509 {
   1510 	xmlChar *str;
   1511 	topo_instance_t inst;
   1512 	tf_idata_t *newi;
   1513 	tnode_t *ntn;
   1514 	uint64_t ui;
   1515 	int rv = -1;
   1516 	int s = 0;
   1517 
   1518 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
   1519 	    "node_process %s\n", rd->rd_name);
   1520 
   1521 	if (xmlattr_to_int(mp, nn, Instance, &ui) < 0)
   1522 		goto nodedone;
   1523 	inst = (topo_instance_t)ui;
   1524 
   1525 	if ((str = xmlGetProp(nn, (xmlChar *)Static)) != NULL) {
   1526 		if (xmlStrcmp(str, (xmlChar *)True) == 0)
   1527 			s = 1;
   1528 		xmlFree(str);
   1529 	}
   1530 
   1531 	if (s == 0) {
   1532 		if (topo_mod_enumerate(rd->rd_mod, rd->rd_pn,
   1533 		    rd->rd_finfo->tf_scheme, rd->rd_name, inst, inst,
   1534 		    s == 1 ? &s : NULL) < 0)
   1535 			goto nodedone;
   1536 	}
   1537 	ntn = topo_node_lookup(rd->rd_pn, rd->rd_name, inst);
   1538 
   1539 	if (ntn == NULL) {
   1540 
   1541 		/*
   1542 		 * If this is a static node declaration, we can
   1543 		 * ignore the lookup failure and continue
   1544 		 * processing.  Otherwise, something
   1545 		 * went wrong during enumeration
   1546 		 */
   1547 		if (s == 1)
   1548 			rv = 0;
   1549 		goto nodedone;
   1550 	}
   1551 	if ((newi = tf_idata_new(mp, inst, ntn)) == NULL) {
   1552 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
   1553 		    "node_process: tf_idata_new failed.\n");
   1554 		goto nodedone;
   1555 	}
   1556 	if (tf_idata_insert(&rd->rd_instances, newi) < 0) {
   1557 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
   1558 		    "node_process: tf_idata_insert failed.\n");
   1559 		goto nodedone;
   1560 	}
   1561 	if (pad_process(mp, rd, nn, ntn, &newi->ti_pad) < 0)
   1562 		goto nodedone;
   1563 	if (fac_process(mp, nn, rd, ntn) < 0)
   1564 		goto nodedone;
   1565 	rv = 0;
   1566 nodedone:
   1567 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "done with node %s.\n",
   1568 	    rd->rd_name);
   1569 	return (rv);
   1570 }
   1571 
   1572 static tf_edata_t *
   1573 enum_attributes_process(topo_mod_t *mp, xmlNodePtr en)
   1574 {
   1575 	tf_edata_t *einfo;
   1576 	uint64_t ui;
   1577 
   1578 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "enum_attributes_process\n");
   1579 	if ((einfo = topo_mod_zalloc(mp, sizeof (tf_edata_t))) == NULL) {
   1580 		(void) topo_mod_seterrno(mp, ETOPO_NOMEM);
   1581 		return (NULL);
   1582 	}
   1583 	einfo->te_name = (char *)xmlGetProp(en, (xmlChar *)Name);
   1584 	if (einfo->te_name == NULL) {
   1585 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
   1586 		    "Enumerator name attribute missing.\n");
   1587 		(void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
   1588 		goto enodedone;
   1589 	}
   1590 
   1591 	/*
   1592 	 * Check for recursive enumeration
   1593 	 */
   1594 	if (strcmp(einfo->te_name, mp->tm_name) == 0) {
   1595 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
   1596 		    "Recursive enumeration detected for %s\n",
   1597 		    einfo->te_name);
   1598 		(void) topo_mod_seterrno(mp, ETOPO_ENUM_RECURS);
   1599 		goto enodedone;
   1600 	}
   1601 	if (xmlattr_to_int(mp, en, Version, &ui) < 0)
   1602 		goto enodedone;
   1603 	einfo->te_vers = (int)ui;
   1604 
   1605 	return (einfo);
   1606 
   1607 enodedone:
   1608 	if (einfo->te_name != NULL)
   1609 		xmlFree(einfo->te_name);
   1610 	topo_mod_free(mp, einfo, sizeof (tf_edata_t));
   1611 	return (NULL);
   1612 }
   1613 
   1614 static int
   1615 enum_run(topo_mod_t *mp, tf_rdata_t *rd)
   1616 {
   1617 	topo_hdl_t *thp = mp->tm_hdl;
   1618 	int e = -1;
   1619 
   1620 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "enum_run\n");
   1621 	/*
   1622 	 * Check if the enumerator module is already loaded.
   1623 	 * Module loading is single-threaded at this point so there's
   1624 	 * no need to worry about the module going away or bumping the
   1625 	 * ref count.
   1626 	 */
   1627 	if ((rd->rd_mod = topo_mod_lookup(thp, rd->rd_einfo->te_name,
   1628 	    0)) == NULL) {
   1629 		if ((rd->rd_mod = topo_mod_load(mp, rd->rd_einfo->te_name,
   1630 		    rd->rd_einfo->te_vers)) == NULL) {
   1631 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
   1632 			    "enum_run: mod_load of %s failed: %s.\n",
   1633 			    rd->rd_einfo->te_name,
   1634 			    topo_strerror(topo_mod_errno(mp)));
   1635 			(void) topo_hdl_seterrno(thp, topo_mod_errno(mp));
   1636 			return (e);
   1637 		}
   1638 	}
   1639 	/*
   1640 	 * We're live, so let's enumerate.
   1641 	 */
   1642 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "enumerate request. (%s)\n",
   1643 	    rd->rd_einfo->te_name);
   1644 	e = topo_mod_enumerate(rd->rd_mod, rd->rd_pn, rd->rd_einfo->te_name,
   1645 	    rd->rd_name, rd->rd_min, rd->rd_max, NULL);
   1646 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "back from enumeration. %d\n",
   1647 	    e);
   1648 	if (e != 0) {
   1649 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
   1650 		    "Enumeration failed (%s)\n",
   1651 		    topo_strerror(topo_mod_errno(mp)));
   1652 		(void) topo_hdl_seterrno(thp, EMOD_PARTIAL_ENUM);
   1653 		return (topo_mod_seterrno(mp, EMOD_PARTIAL_ENUM));
   1654 	}
   1655 	return (e);
   1656 }
   1657 
   1658 static int
   1659 fac_enum_run(topo_mod_t *mp, tnode_t *node, const char *name)
   1660 {
   1661 	topo_hdl_t *thp = mp->tm_hdl;
   1662 	topo_mod_t *fmod;
   1663 	int e = -1;
   1664 
   1665 	topo_dprintf(thp, TOPO_DBG_XML, "fac_enum_run\n");
   1666 	/*
   1667 	 * Check if the enumerator module is already loaded.
   1668 	 * Module loading is single-threaded at this point so there's
   1669 	 * no need to worry about the module going away or bumping the
   1670 	 * ref count.
   1671 	 */
   1672 	if ((fmod = topo_mod_lookup(thp, name, 0)) == NULL) {
   1673 		if ((fmod = topo_mod_load(mp, name, TOPO_VERSION)) == NULL) {
   1674 			topo_dprintf(thp, TOPO_DBG_ERR,
   1675 			    "fac_enum_run: mod_load of %s failed: %s.\n",
   1676 			    name, topo_strerror(topo_mod_errno(mp)));
   1677 			(void) topo_hdl_seterrno(thp, topo_mod_errno(mp));
   1678 			return (e);
   1679 		}
   1680 	}
   1681 	/*
   1682 	 * We're live, so let's enumerate.
   1683 	 */
   1684 	topo_dprintf(thp, TOPO_DBG_XML, "fac enumerate request. (%s)\n", name);
   1685 	e = topo_mod_enumerate(fmod, node, name, name, 0, 0, NULL);
   1686 	topo_dprintf(thp, TOPO_DBG_XML, "back from enumeration. %d\n", e);
   1687 	if (e != 0) {
   1688 		topo_dprintf(thp, TOPO_DBG_ERR,
   1689 		    "Facility provider enumeration failed (%s)\n",
   1690 		    topo_strerror(topo_mod_errno(mp)));
   1691 		(void) topo_hdl_seterrno(thp, EMOD_PARTIAL_ENUM);
   1692 		return (topo_mod_seterrno(mp, EMOD_PARTIAL_ENUM));
   1693 	}
   1694 	return (e);
   1695 }
   1696 
   1697 int
   1698 decorate_nodes(topo_mod_t *mp, tf_rdata_t *rd, xmlNodePtr pxn, tnode_t *ptn,
   1699     tf_pad_t **rpad)
   1700 {
   1701 	tnode_t *ctn;
   1702 
   1703 	ctn = topo_child_first(ptn);
   1704 	while (ctn != NULL) {
   1705 		/* Only care about instances within the range */
   1706 		if (strcmp(topo_node_name(ctn), rd->rd_name) != 0) {
   1707 			ctn = topo_child_next(ptn, ctn);
   1708 			continue;
   1709 		}
   1710 		if (pad_process(mp, rd, pxn, ctn, rpad) < 0)
   1711 			return (-1);
   1712 		if (decorate_nodes(mp, rd, pxn, ctn, rpad) < 0)
   1713 			return (-1);
   1714 		ctn = topo_child_next(ptn, ctn);
   1715 	}
   1716 	return (0);
   1717 }
   1718 
   1719 int
   1720 topo_xml_range_process(topo_mod_t *mp, xmlNodePtr rn, tf_rdata_t *rd)
   1721 {
   1722 	/*
   1723 	 * The range may have several children xmlNodes, that may
   1724 	 * represent the enumeration method, property groups,
   1725 	 * dependents, nodes or services.
   1726 	 */
   1727 	xmlNodePtr cn, enum_node = NULL, pmap_node = NULL;
   1728 	xmlChar *pmap_name;
   1729 	tnode_t *ct;
   1730 	int e, ccnt = 0;
   1731 
   1732 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_range_process\n"
   1733 	    "process %s range beneath %s\n", rd->rd_name,
   1734 	    topo_node_name(rd->rd_pn));
   1735 
   1736 	e = topo_node_range_create(mp,
   1737 	    rd->rd_pn, rd->rd_name, rd->rd_min, rd->rd_max);
   1738 	if (e != 0 && topo_mod_errno(mp) != EMOD_NODE_DUP) {
   1739 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
   1740 		    "Range create failed due to %s.\n",
   1741 		    topo_strerror(topo_mod_errno(mp)));
   1742 		return (-1);
   1743 	}
   1744 
   1745 	/*
   1746 	 * Before we process any of the other child xmlNodes, we iterate through
   1747 	 * the children and looking for either enum-method or propmap elements.
   1748 	 */
   1749 	for (cn = rn->xmlChildrenNode; cn != NULL; cn = cn->next)
   1750 		if (xmlStrcmp(cn->name, (xmlChar *)Enum_meth) == 0)
   1751 			enum_node = cn;
   1752 		else if (xmlStrcmp(cn->name, (xmlChar *)Propmap) == 0)
   1753 			pmap_node = cn;
   1754 
   1755 	/*
   1756 	 * If we found an enum-method element, process it first
   1757 	 */
   1758 	if (enum_node != NULL) {
   1759 		if ((rd->rd_einfo = enum_attributes_process(mp, enum_node))
   1760 		    == NULL)
   1761 			return (-1);
   1762 		if (enum_run(mp, rd) < 0) {
   1763 			/*
   1764 			 * Note the failure but continue on
   1765 			 */
   1766 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
   1767 			    "Enumeration failed.\n");
   1768 		}
   1769 	}
   1770 
   1771 	/*
   1772 	 * Next, check if a propmap element was found and if so, load it in
   1773 	 * and parse it.
   1774 	 */
   1775 	if (pmap_node != NULL) {
   1776 		topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "found a propmap "
   1777 		    "element\n");
   1778 		if ((pmap_name = xmlGetProp(pmap_node, (xmlChar *)Name))
   1779 		    == NULL) {
   1780 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
   1781 			    "propmap element missing name attribute.\n");
   1782 		} else {
   1783 			if (topo_file_load(mp, rd->rd_pn,
   1784 			    (const char *)pmap_name,
   1785 			    rd->rd_finfo->tf_scheme, 1) < 0) {
   1786 
   1787 				topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
   1788 				    "topo_xml_range_process: topo_file_load"
   1789 				    "failed: %s.\n",
   1790 				    topo_strerror(topo_mod_errno(mp)));
   1791 			}
   1792 			xmlFree(pmap_name);
   1793 		}
   1794 	}
   1795 
   1796 	/* Now look for nodes, i.e., hard instances */
   1797 	for (cn = rn->xmlChildrenNode; cn != NULL; cn = cn->next) {
   1798 		if (xmlStrcmp(cn->name, (xmlChar *)Node) == 0) {
   1799 			if (node_process(mp, cn, rd) < 0) {
   1800 				topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
   1801 				    "node processing failed: %s.\n",
   1802 				    topo_strerror(topo_mod_errno(mp)));
   1803 				return (topo_mod_seterrno(mp,
   1804 				    EMOD_PARTIAL_ENUM));
   1805 			}
   1806 			ccnt++;
   1807 		}
   1808 	}
   1809 
   1810 	/*
   1811 	 * Finally, process the property groups and dependents
   1812 	 *
   1813 	 * If the TF_PROPMAP flag is set for the XML file we're currently
   1814 	 * processing, then this XML file was loaded via propmap.  In that case
   1815 	 * we call a special routine to recursively apply the propgroup settings
   1816 	 * to all of nodes in this range
   1817 	 */
   1818 	if (rd->rd_finfo->tf_flags & TF_PROPMAP)
   1819 		(void) decorate_nodes(mp, rd, rn, rd->rd_pn, &rd->rd_pad);
   1820 	else {
   1821 		ct = topo_child_first(rd->rd_pn);
   1822 		while (ct != NULL) {
   1823 			/* Only care about instances within the range */
   1824 			if (strcmp(topo_node_name(ct), rd->rd_name) != 0) {
   1825 				ct = topo_child_next(rd->rd_pn, ct);
   1826 				continue;
   1827 			}
   1828 			if (pad_process(mp, rd, rn, ct, &rd->rd_pad)
   1829 			    < 0)
   1830 				return (-1);
   1831 
   1832 			if (fac_process(mp, rn, rd, ct) < 0)
   1833 				return (-1);
   1834 
   1835 			ct = topo_child_next(rd->rd_pn, ct);
   1836 			ccnt++;
   1837 		}
   1838 	}
   1839 
   1840 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_range_process: end "
   1841 	    "range process %s\n", rd->rd_name);
   1842 
   1843 	return (0);
   1844 }
   1845 
   1846 static tf_rdata_t *
   1847 topo_xml_walk(topo_mod_t *mp,
   1848     tf_info_t *xinfo, xmlNodePtr croot, tnode_t *troot)
   1849 {
   1850 	xmlNodePtr curr, def_set = NULL;
   1851 	tf_rdata_t *rr, *pr, *rdp;
   1852 	xmlChar *set;
   1853 	char *key;
   1854 	int joined_set = 0;
   1855 
   1856 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_walk\n");
   1857 	rr = pr = NULL;
   1858 	/*
   1859 	 * First iterate through all the XML nodes at this level to look for
   1860 	 * set nodes.
   1861 	 */
   1862 	for (curr = croot->xmlChildrenNode; curr != NULL; curr = curr->next) {
   1863 		if (curr->name == NULL) {
   1864 			topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
   1865 			    "topo_xml_walk: Ignoring nameless xmlnode\n");
   1866 			continue;
   1867 		}
   1868 		if (xmlStrcmp(curr->name, (xmlChar *)Set) == 0) {
   1869 			if (joined_set)
   1870 				continue;
   1871 
   1872 			set = xmlGetProp(curr, (xmlChar *)Setlist);
   1873 
   1874 			if (mp->tm_hdl->th_product)
   1875 				key = mp->tm_hdl->th_product;
   1876 			else
   1877 				key = mp->tm_hdl->th_platform;
   1878 
   1879 			/*
   1880 			 * If it's the default set then we'll store
   1881 			 * a pointer to it so that if none of the other
   1882 			 * sets apply to our product we can fall
   1883 			 * back to this one.
   1884 			 */
   1885 			if (strcmp((char *)set, "default") == 0)
   1886 				def_set = curr;
   1887 			else if (set_contains(mp, key, (char *)set)) {
   1888 				joined_set = 1;
   1889 				if ((rdp = topo_xml_walk(mp, xinfo, curr,
   1890 				    troot)) == NULL) {
   1891 					topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
   1892 					    "topo_xml_walk: failed1\n");
   1893 				}
   1894 				if (pr == NULL) {
   1895 					rr = pr = rdp;
   1896 				} else {
   1897 					pr->rd_next = rdp;
   1898 					pr = rdp;
   1899 				}
   1900 				rr->rd_cnt++;
   1901 			}
   1902 			xmlFree(set);
   1903 		}
   1904 	}
   1905 	/*
   1906 	 * If we haven't found a set that contains our product AND a default set
   1907 	 * exists, then we'll process it.
   1908 	 */
   1909 	if (!joined_set && def_set) {
   1910 		if ((rdp = topo_xml_walk(mp, xinfo, def_set, troot)) == NULL) {
   1911 			topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
   1912 			    "topo_xml_walk: failed2\n");
   1913 		}
   1914 		if (pr == NULL) {
   1915 			rr = pr = rdp;
   1916 		} else {
   1917 			pr->rd_next = rdp;
   1918 			pr = rdp;
   1919 		}
   1920 		rr->rd_cnt++;
   1921 	}
   1922 	/*
   1923 	 * Now we're interested in children xmlNodes of croot tagged
   1924 	 * as 'ranges'.  These define what topology nodes may exist, and need
   1925 	 * to be verified.
   1926 	 */
   1927 	for (curr = croot->xmlChildrenNode; curr != NULL; curr = curr->next) {
   1928 		if (curr->name == NULL) {
   1929 			topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
   1930 			    "topo_xml_walk: Ignoring nameless xmlnode\n");
   1931 			continue;
   1932 		}
   1933 		if (xmlStrcmp(curr->name, (xmlChar *)Range) != 0)
   1934 			continue;
   1935 		if ((rdp = tf_rdata_new(mp, xinfo, curr, troot)) == NULL) {
   1936 			/*
   1937 			 * Range processing error, continue walk
   1938 			 */
   1939 			continue;
   1940 		}
   1941 		if (pr == NULL) {
   1942 			rr = pr = rdp;
   1943 		} else {
   1944 			pr->rd_next = rdp;
   1945 			pr = rdp;
   1946 		}
   1947 		rr->rd_cnt++;
   1948 	}
   1949 
   1950 	return (rr);
   1951 }
   1952 
   1953 /*
   1954  *  Convert parsed xml topology description into topology nodes
   1955  */
   1956 int
   1957 topo_xml_enum(topo_mod_t *tmp, tf_info_t *xinfo, tnode_t *troot)
   1958 {
   1959 	xmlNodePtr xroot;
   1960 
   1961 	topo_dprintf(tmp->tm_hdl, TOPO_DBG_XML, "topo_xml_enum\n");
   1962 
   1963 	if ((xroot = xmlDocGetRootElement(xinfo->tf_xdoc)) == NULL) {
   1964 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
   1965 		    "Couldn't get root xmlNode.\n");
   1966 		return (-1);
   1967 	}
   1968 	if ((xinfo->tf_rd = topo_xml_walk(tmp, xinfo, xroot, troot)) == NULL) {
   1969 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
   1970 		    "error within .xml topology: %s\n",
   1971 		    topo_strerror(topo_mod_errno(tmp)));
   1972 		return (-1);
   1973 	}
   1974 	return (0);
   1975 }
   1976 
   1977 /*
   1978  * Load an XML tree from filename and read it into a DOM parse tree.
   1979  */
   1980 static tf_info_t *
   1981 txml_file_parse(topo_mod_t *tmp,
   1982     int fd, const char *filenm, const char *escheme)
   1983 {
   1984 	xmlValidCtxtPtr vcp;
   1985 	xmlNodePtr cursor;
   1986 	xmlDocPtr document;
   1987 	xmlDtdPtr dtd = NULL;
   1988 	xmlChar *scheme = NULL;
   1989 	char *dtdpath = NULL;
   1990 	int readflags = 0;
   1991 	tf_info_t *r;
   1992 	int e, validate = 0;
   1993 
   1994 	topo_dprintf(tmp->tm_hdl, TOPO_DBG_XML,
   1995 	    "txml_file_parse(filenm=%s, escheme=%s)\n", filenm, escheme);
   1996 
   1997 	/*
   1998 	 * Since topologies can XInclude other topologies, and libxml2
   1999 	 * doesn't do DTD-based validation with XInclude, by default
   2000 	 * we don't validate topology files.  One can force
   2001 	 * validation, though, by creating a TOPOXML_VALIDATE
   2002 	 * environment variable and creating a TOPO_DTD environment
   2003 	 * variable with the path to the DTD against which to validate.
   2004 	 */
   2005 	if (getenv("TOPOXML_VALIDATE") != NULL) {
   2006 		dtdpath = getenv("TOPO_DTD");
   2007 		if (dtdpath != NULL)
   2008 			xmlLoadExtDtdDefaultValue = 0;
   2009 		validate = 1;
   2010 	}
   2011 
   2012 	/*
   2013 	 * Splat warnings and errors related to parsing the topology
   2014 	 * file if the TOPOXML_PERROR environment variable exists.
   2015 	 */
   2016 	if (getenv("TOPOXML_PERROR") == NULL)
   2017 		readflags = XML_PARSE_NOERROR | XML_PARSE_NOWARNING;
   2018 
   2019 	if ((document = xmlReadFd(fd, filenm, NULL, readflags)) == NULL) {
   2020 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
   2021 		    "txml_file_parse: couldn't parse document.\n");
   2022 		return (NULL);
   2023 	}
   2024 
   2025 	/*
   2026 	 * Verify that this is a document type we understand.
   2027 	 */
   2028 	if ((dtd = xmlGetIntSubset(document)) == NULL) {
   2029 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
   2030 		    "document has no DTD.\n");
   2031 		xmlFreeDoc(document);
   2032 		return (NULL);
   2033 	}
   2034 
   2035 	if (strcmp((const char *)dtd->SystemID, TOPO_DTD_PATH) != 0) {
   2036 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
   2037 		    "document DTD unknown; bad topology file\n");
   2038 		xmlFreeDoc(document);
   2039 		return (NULL);
   2040 	}
   2041 
   2042 	if ((cursor = xmlDocGetRootElement(document)) == NULL) {
   2043 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, "document is empty.\n");
   2044 		xmlFreeDoc(document);
   2045 		return (NULL);
   2046 	}
   2047 
   2048 	/*
   2049 	 * Make sure we're looking at a topology description in the
   2050 	 * expected scheme.
   2051 	 */
   2052 	if (xmlStrcmp(cursor->name, (xmlChar *)Topology) != 0) {
   2053 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
   2054 		    "document is not a topology description.\n");
   2055 		xmlFreeDoc(document);
   2056 		return (NULL);
   2057 	}
   2058 	if ((scheme = xmlGetProp(cursor, (xmlChar *)Scheme)) == NULL) {
   2059 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
   2060 		    "topology lacks a scheme.\n");
   2061 		(void) topo_mod_seterrno(tmp, ETOPO_PRSR_NOATTR);
   2062 		xmlFreeDoc(document);
   2063 		return (NULL);
   2064 	}
   2065 	if (xmlStrcmp(scheme, (xmlChar *)escheme) != 0) {
   2066 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
   2067 		    "topology in unrecognized scheme, %s, expecting %s\n",
   2068 		    scheme, escheme);
   2069 		(void) topo_mod_seterrno(tmp, ETOPO_PRSR_BADSCH);
   2070 		xmlFree(scheme);
   2071 		xmlFreeDoc(document);
   2072 		return (NULL);
   2073 	}
   2074 
   2075 	if (dtdpath != NULL) {
   2076 		dtd = xmlParseDTD(NULL, (xmlChar *)dtdpath);
   2077 		if (dtd == NULL) {
   2078 			topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
   2079 			    "Could not parse DTD \"%s\".\n",
   2080 			    dtdpath);
   2081 			xmlFree(scheme);
   2082 			xmlFreeDoc(document);
   2083 			return (NULL);
   2084 		}
   2085 
   2086 		if (document->extSubset != NULL)
   2087 			xmlFreeDtd(document->extSubset);
   2088 
   2089 		document->extSubset = dtd;
   2090 	}
   2091 
   2092 	if (xmlXIncludeProcessFlags(document, XML_PARSE_XINCLUDE) == -1) {
   2093 		xmlFree(scheme);
   2094 		xmlFreeDoc(document);
   2095 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
   2096 		    "couldn't handle XInclude statements in document\n");
   2097 		return (NULL);
   2098 	}
   2099 
   2100 	if (validate) {
   2101 		if ((vcp = xmlNewValidCtxt()) == NULL) {
   2102 			xmlFree(scheme);
   2103 			xmlFreeDoc(document);
   2104 			return (NULL);
   2105 		}
   2106 		vcp->warning = xmlParserValidityWarning;
   2107 		vcp->error = xmlParserValidityError;
   2108 
   2109 		e = xmlValidateDocument(vcp, document);
   2110 
   2111 		xmlFreeValidCtxt(vcp);
   2112 
   2113 		if (e == 0)
   2114 			topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
   2115 			    "Document is not valid.\n");
   2116 	}
   2117 
   2118 	if ((r = tf_info_new(tmp, document, scheme)) == NULL) {
   2119 		xmlFree(scheme);
   2120 		xmlFreeDoc(document);
   2121 		return (NULL);
   2122 	}
   2123 
   2124 	xmlFree(scheme);
   2125 	scheme = NULL;
   2126 	return (r);
   2127 }
   2128 
   2129 tf_info_t *
   2130 topo_xml_read(topo_mod_t *tmp, const char *path, const char *escheme)
   2131 {
   2132 	int fd;
   2133 	tf_info_t *tip;
   2134 
   2135 	if ((fd = open(path, O_RDONLY)) < 0) {
   2136 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
   2137 		    "failed to open %s for reading\n", path);
   2138 		return (NULL);
   2139 	}
   2140 	tip = txml_file_parse(tmp, fd, path, escheme);
   2141 	(void) close(fd);
   2142 	return (tip);
   2143 }
   2144