Home | History | Annotate | Download | only in sun4vpi
      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 
     28 /*
     29  * Subroutines used by various components of the Sun4v PI enumerator
     30  */
     31 
     32 #include <sys/types.h>
     33 #include <sys/systeminfo.h>
     34 #include <sys/utsname.h>
     35 #include <string.h>
     36 #include <strings.h>
     37 #include <sys/fm/protocol.h>
     38 #include <fm/topo_mod.h>
     39 #include <fm/topo_hc.h>
     40 #include <sys/mdesc.h>
     41 #include <libnvpair.h>
     42 
     43 #include "pi_impl.h"
     44 
     45 #define	MAX_PATH_DEPTH	(MAXPATHLEN / 256)	/* max pci path = 256 */
     46 
     47 static const topo_pgroup_info_t sys_pgroup = {
     48 	TOPO_PGROUP_SYSTEM,
     49 	TOPO_STABILITY_PRIVATE,
     50 	TOPO_STABILITY_PRIVATE,
     51 	1
     52 };
     53 
     54 static const topo_pgroup_info_t auth_pgroup = {
     55 	FM_FMRI_AUTHORITY,
     56 	TOPO_STABILITY_PRIVATE,
     57 	TOPO_STABILITY_PRIVATE,
     58 	1
     59 };
     60 
     61 
     62 /*
     63  * Search the PRI for MDE nodes using md_scan_dag.  Using this routine
     64  * consolodates similar searches used in a few places within the sun4vpi
     65  * enumerator.
     66  *
     67  * The routine returns the number of nodes found, or -1.  If the node array
     68  * is non-NULL on return, then it must be freed:
     69  *	topo_mod_free(mod, nodes, nsize);
     70  *
     71  */
     72 int
     73 pi_find_mdenodes(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_start,
     74     char *type_str, char *arc_str, mde_cookie_t **nodes, size_t *nsize)
     75 {
     76 	int	result;
     77 	int	total_mdenodes;
     78 
     79 	mde_str_cookie_t	start_cookie;
     80 	mde_str_cookie_t	arc_cookie;
     81 
     82 	/* Prepare to scan the PRI using the start string and given arc */
     83 	total_mdenodes	= md_node_count(mdp);
     84 	start_cookie	= md_find_name(mdp, type_str);
     85 	arc_cookie	= md_find_name(mdp, arc_str);
     86 
     87 	/* Allocate an array to hold the results of the scan */
     88 	*nsize		= sizeof (mde_cookie_t) * total_mdenodes;
     89 	*nodes		= topo_mod_zalloc(mod, *nsize);
     90 	if (*nodes == NULL) {
     91 		/* We have no memory.  Set an error code and return failure */
     92 		*nsize = 0;
     93 		topo_mod_seterrno(mod, EMOD_NOMEM);
     94 		return (-1);
     95 	}
     96 
     97 	result = md_scan_dag(mdp, mde_start, start_cookie, arc_cookie, *nodes);
     98 	if (result <= 0) {
     99 		/* No nodes found.  Free the node array before returning */
    100 		topo_mod_free(mod, *nodes, *nsize);
    101 		*nodes = NULL;
    102 		*nsize = 0;
    103 	}
    104 
    105 	return (result);
    106 }
    107 
    108 
    109 /*
    110  * Determine if this node should be skipped by finding the topo-skip property.
    111  */
    112 int
    113 pi_skip_node(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
    114 {
    115 	int		result;
    116 	uint64_t	skip;
    117 
    118 	if (mod == NULL || mdp == NULL) {
    119 		/*
    120 		 * These parameters are required.  Tell the caller to skip
    121 		 * all nodes.
    122 		 */
    123 		return (1);
    124 	}
    125 
    126 	skip = 0;	/* do not skip by default */
    127 	result = md_get_prop_val(mdp, mde_node, MD_STR_TOPO_SKIP, &skip);
    128 	if (result != 0) {
    129 		/*
    130 		 * There is no topo-skip property.  Assume we are not skipping
    131 		 * the mde node.
    132 		 */
    133 		skip = 0;
    134 	}
    135 
    136 	/*
    137 	 * If skip is present and non-zero we want to skip this node.  We
    138 	 * return 1 to indicate this.
    139 	 */
    140 	if (skip != 0) {
    141 		return (1);
    142 	}
    143 	return (0);
    144 }
    145 
    146 /*
    147  * Get the product serial number (the ID as far as the topo authority is
    148  * concerned) either from the current node, if it is of type 'product', or
    149  * search for a product node in the PRI.
    150  *
    151  * The string must be freed with topo_mod_strfree()
    152  */
    153 char *
    154 pi_get_productsn(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
    155 {
    156 	int		result;
    157 	int		idx;
    158 	int		num_nodes;
    159 	char		*id = NULL;
    160 	char		*type;
    161 	size_t		size;
    162 	mde_cookie_t	*nodes = NULL;
    163 
    164 	topo_mod_dprintf(mod, "pi_get_productsn: enter\n");
    165 
    166 	result = md_get_prop_str(mdp, mde_node, MD_STR_TYPE, &type);
    167 	if (result == 0 && strcmp(type, MD_STR_PRODUCT) == 0) {
    168 		/*
    169 		 * This is a product node.  We need only search for the serial
    170 		 * number property on this node to return the ID.
    171 		 */
    172 		result = md_get_prop_str(mdp, mde_node, MD_STR_SERIAL_NUMBER,
    173 		    &id);
    174 		if (result != 0 || id == NULL || strlen(id) == 0)
    175 			return (NULL);
    176 
    177 		topo_mod_dprintf(mod, "pi_get_productsn: product-sn = %s\n",
    178 		    id);
    179 		return (topo_mod_strdup(mod, id));
    180 	}
    181 
    182 	/*
    183 	 * Search the PRI for nodes of type MD_STR_COMPONENT and find the
    184 	 * first element with type of MD_STR_PRODUCT.  This node
    185 	 * will contain the MD_STR_SERIAL_NUMBER property to use as the
    186 	 * product-sn.
    187 	 */
    188 	num_nodes = pi_find_mdenodes(mod, mdp, MDE_INVAL_ELEM_COOKIE,
    189 	    MD_STR_COMPONENT, MD_STR_FWD, &nodes, &size);
    190 	if (num_nodes <= 0 || nodes == NULL) {
    191 		/* We did not find any component nodes */
    192 		return (NULL);
    193 	}
    194 	topo_mod_dprintf(mod, "pi_get_productsn: found %d %s nodes\n",
    195 	    num_nodes, MD_STR_COMPONENT);
    196 
    197 	idx = 0;
    198 	while (id == NULL && idx < num_nodes) {
    199 		result = md_get_prop_str(mdp, nodes[idx], MD_STR_TYPE, &type);
    200 		if (result == 0 && strcmp(type, MD_STR_PRODUCT) == 0) {
    201 			/*
    202 			 * This is a product node.  Get the serial number
    203 			 * property from the node.
    204 			 */
    205 			result = md_get_prop_str(mdp, nodes[idx],
    206 			    MD_STR_SERIAL_NUMBER, &id);
    207 			if (result != 0)
    208 				topo_mod_dprintf(mod, "pi_get_productsn: "
    209 				    "failed to read %s from node_0x%llx\n",
    210 				    MD_STR_SERIAL_NUMBER,
    211 				    (uint64_t)nodes[idx]);
    212 		}
    213 		/* Search the next node, if necessary */
    214 		idx++;
    215 	}
    216 	topo_mod_free(mod, nodes, size);
    217 
    218 	/* Everything is freed up and it's time to return the product-sn */
    219 	if (result != 0 || id == NULL || strlen(id) == 0) {
    220 		return (NULL);
    221 	}
    222 	topo_mod_dprintf(mod, "pi_get_productsn: product-sn %s\n", id);
    223 
    224 	return (topo_mod_strdup(mod, id));
    225 }
    226 
    227 
    228 /*
    229  * Get the chassis serial number (the ID as far as the topo authority is
    230  * concerned) either from the current node, if it is of type 'chassis', or
    231  * search for a chassis node in the PRI.
    232  *
    233  * The string must be freed with topo_mod_strfree()
    234  */
    235 char *
    236 pi_get_chassisid(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
    237 {
    238 	int		result;
    239 	int		idx;
    240 	int		num_nodes;
    241 	char		*id = NULL;
    242 	char		*hc_name = NULL;
    243 	size_t		chassis_size;
    244 	mde_cookie_t	*chassis_nodes = NULL;
    245 
    246 	topo_mod_dprintf(mod, "pi_get_chassis: enter\n");
    247 
    248 	hc_name = pi_get_topo_hc_name(mod, mdp, mde_node);
    249 	if (hc_name != NULL && strcmp(hc_name, MD_STR_CHASSIS) == 0) {
    250 		topo_mod_strfree(mod, hc_name);
    251 
    252 		/*
    253 		 * This is a chassis node.  We need only search for the serial
    254 		 * number property on this node to return the ID.
    255 		 */
    256 		result = md_get_prop_str(mdp, mde_node, MD_STR_SERIAL_NUMBER,
    257 		    &id);
    258 		if (result != 0 || id == NULL || strlen(id) == 0) {
    259 			return (NULL);
    260 		}
    261 		topo_mod_dprintf(mod, "pi_get_chassis: chassis-id = %s\n", id);
    262 		return (topo_mod_strdup(mod, id));
    263 	}
    264 	if (hc_name != NULL) {
    265 		topo_mod_strfree(mod, hc_name);
    266 	}
    267 
    268 	/*
    269 	 * Search the PRI for nodes of type MD_STR_COMPONENT and find the
    270 	 * first element with topo-hc-type of MD_STR_CHASSIS.  This node
    271 	 * will contain the MD_STR_SERIAL_NUMBER property to use as the
    272 	 * chassis-id.
    273 	 */
    274 	num_nodes = pi_find_mdenodes(mod, mdp, MDE_INVAL_ELEM_COOKIE,
    275 	    MD_STR_COMPONENT, MD_STR_FWD, &chassis_nodes, &chassis_size);
    276 	if (num_nodes <= 0 || chassis_nodes == NULL) {
    277 		/* We did not find any chassis nodes */
    278 		return (NULL);
    279 	}
    280 	topo_mod_dprintf(mod, "pi_get_chassisid: found %d %s nodes\n",
    281 	    num_nodes, MD_STR_COMPONENT);
    282 
    283 	idx = 0;
    284 	while (id == NULL && idx < num_nodes) {
    285 		hc_name = pi_get_topo_hc_name(mod, mdp, chassis_nodes[idx]);
    286 		if (hc_name != NULL && strcmp(hc_name, MD_STR_CHASSIS) == 0) {
    287 			/*
    288 			 * This is a chassis node.  Get the serial number
    289 			 * property from the node.
    290 			 */
    291 			result = md_get_prop_str(mdp, chassis_nodes[idx],
    292 			    MD_STR_SERIAL_NUMBER, &id);
    293 			if (result != 0) {
    294 				topo_mod_dprintf(mod, "pi_get_chassisid: "
    295 				    "failed to read %s from node_0x%llx\n",
    296 				    MD_STR_SERIAL_NUMBER,
    297 				    (uint64_t)chassis_nodes[idx]);
    298 			}
    299 		}
    300 		topo_mod_strfree(mod, hc_name);
    301 
    302 		/* Search the next node, if necessary */
    303 		idx++;
    304 	}
    305 	topo_mod_free(mod, chassis_nodes, chassis_size);
    306 
    307 	/* Everything is freed up and it's time to return the platform-id */
    308 	if (result != 0 || id == NULL || strlen(id) == 0) {
    309 		return (NULL);
    310 	}
    311 	topo_mod_dprintf(mod, "pi_get_chassis: chassis-id %s\n", id);
    312 
    313 	return (topo_mod_strdup(mod, id));
    314 }
    315 
    316 
    317 /*
    318  * Determine if the node is a FRU by checking for the existance and non-zero
    319  * value of the 'fru' property on the mde node.
    320  */
    321 int
    322 pi_get_fru(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node, int *is_fru)
    323 {
    324 	int		result;
    325 	uint64_t	fru;
    326 
    327 	if (mod == NULL || mdp == NULL || is_fru == NULL) {
    328 		return (-1);
    329 	}
    330 	fru = 0;
    331 	*is_fru = 0;
    332 
    333 	result = md_get_prop_val(mdp, mde_node, MD_STR_FRU, &fru);
    334 	if (result != 0) {
    335 		/* The node is not a FRU. */
    336 		return (-1);
    337 	}
    338 	if (fru != 0) {
    339 		*is_fru = 1;
    340 	}
    341 	return (0);
    342 }
    343 
    344 
    345 /*
    346  * Get the id property value from the given PRI node
    347  */
    348 int
    349 pi_get_instance(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
    350     topo_instance_t *ip)
    351 {
    352 	int		result;
    353 	uint64_t	id;
    354 
    355 	id = 0;
    356 	result = md_get_prop_val(mdp, mde_node, MD_STR_ID, &id);
    357 	if (result != 0) {
    358 		/*
    359 		 * There is no id property.
    360 		 */
    361 		topo_mod_dprintf(mod, "node_0x%llx has no id property\n",
    362 		    (uint64_t)mde_node);
    363 		return (-1);
    364 	}
    365 	*ip = id;
    366 
    367 	return (0);
    368 }
    369 
    370 
    371 /*
    372  * If the given MDE node is a FRU return the 'nac' property, if it exists,
    373  * to use as the label.
    374  *
    375  * The string must be freed with topo_mod_strfree()
    376  */
    377 char *
    378 pi_get_label(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
    379 {
    380 	int	result;
    381 	int	is_fru;
    382 	char	*lp = NULL;
    383 
    384 	result = pi_get_fru(mod, mdp, mde_node, &is_fru);
    385 	if (result != 0 || is_fru == 0) {
    386 		/* This node is not a FRU.  It has no label */
    387 		return (NULL);
    388 	}
    389 
    390 	/*
    391 	 * The node is a FRU.  Get the NAC name to use as a label.
    392 	 */
    393 	result = md_get_prop_str(mdp, mde_node, MD_STR_NAC, &lp);
    394 	if (result != 0 || lp == NULL || strlen(lp) == 0) {
    395 		/* No NAC label.  Return NULL */
    396 		return (NULL);
    397 	}
    398 
    399 	/* Return a copy of the label */
    400 	return (topo_mod_strdup(mod, lp));
    401 }
    402 
    403 
    404 /*
    405  * Return the complete part number string to the caller.  The complete part
    406  * number is made up of the part number attribute concatenated with the dash
    407  * number attribute of the mde node.
    408  *
    409  * The string must be freed with topo_mod_strfree()
    410  */
    411 char *
    412 pi_get_part(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
    413 {
    414 	int	result;
    415 	size_t	bufsize;
    416 	char	*buf  = NULL;
    417 	char	*part = NULL;
    418 	char	*dash = NULL;
    419 
    420 	result = md_get_prop_str(mdp, mde_node, MD_STR_PART_NUMBER, &part);
    421 	if (result != 0) {
    422 		part = NULL;
    423 	}
    424 	result = md_get_prop_str(mdp, mde_node, MD_STR_DASH_NUMBER, &dash);
    425 	if (result != 0) {
    426 		dash = NULL;
    427 	}
    428 	bufsize = 1 + (part ? strlen(part) : 0) + (dash ? strlen(dash) : 0);
    429 	if (bufsize == 1) {
    430 		return (NULL);
    431 	}
    432 
    433 	/* Construct the part number from the part and dash values */
    434 	buf = topo_mod_alloc(mod, bufsize);
    435 	if (buf != NULL) {
    436 		(void) snprintf(buf, bufsize, "%s%s", (part ? part : ""),
    437 		    (dash ? dash : ""));
    438 	}
    439 
    440 	return (buf);
    441 }
    442 
    443 
    444 /*
    445  * Return the path string to the caller.
    446  *
    447  * The string must be freed with topo_mod_strfree()
    448  */
    449 char *
    450 pi_get_path(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
    451 {
    452 	int	result;
    453 	int	i = 0;
    454 	size_t	max_addrs;
    455 	size_t	path_len = 0;
    456 	size_t	buf_len;
    457 	char	*propbuf = NULL;
    458 	char	*buf = NULL;
    459 	char	*buffree;
    460 	char	*path = NULL;
    461 	char	*token;
    462 	char	*dev_addr[MAX_PATH_DEPTH] = { NULL };
    463 	char	*dev_path[MAX_PATH_DEPTH] = { NULL };
    464 	char	*lastp;
    465 
    466 	/*
    467 	 * Get the path property from PRI; should look something
    468 	 * like "/@600/@0".
    469 	 */
    470 	result = md_get_prop_str(mdp, mde_node, MD_STR_PATH, &propbuf);
    471 	if (result != 0 || propbuf == NULL || strlen(propbuf) == 0) {
    472 		topo_mod_dprintf(mod, "pi_get_path: failed to get path\n");
    473 		return (NULL);
    474 	}
    475 	buf_len = strlen(propbuf) + 1;
    476 	buf = topo_mod_alloc(mod, buf_len);
    477 	if (buf == NULL) {
    478 		topo_mod_dprintf(mod, "pi_get_path: no memory\n");
    479 		return (NULL);
    480 	}
    481 	buffree = buf; /* strtok_r is destructive */
    482 	(void) strcpy(buf, propbuf);
    483 
    484 	/*
    485 	 * Grab the address(es) from the path property.
    486 	 */
    487 	if ((token = strtok_r(buf, "/@", &lastp)) != NULL) {
    488 		dev_addr[i] = topo_mod_strdup(mod, token);
    489 		while ((token = strtok_r(NULL, "/@", &lastp)) != NULL) {
    490 			if (++i < MAX_PATH_DEPTH) {
    491 				dev_addr[i] = topo_mod_strdup(mod, token);
    492 			} else {
    493 				topo_mod_dprintf(mod, "pi_get_path: path "
    494 				    "too long (%d)\n", i);
    495 				topo_mod_free(mod, buffree, buf_len);
    496 				return (NULL);
    497 			}
    498 		}
    499 	} else {
    500 		topo_mod_dprintf(mod, "pi_get_path: path wrong\n");
    501 		topo_mod_free(mod, buffree, buf_len);
    502 		return (NULL);
    503 	}
    504 	max_addrs = ++i;
    505 	topo_mod_free(mod, buffree, buf_len);
    506 
    507 	/*
    508 	 * Construct the path to look something like "/pci@600/pci@0".
    509 	 */
    510 	for (i = 0; i < max_addrs; i++) {
    511 		int len = strlen(dev_addr[i]) + strlen("/pci@") + 1;
    512 		path_len += len;
    513 		dev_path[i] = (char *)topo_mod_alloc(mod, len);
    514 		result = snprintf(dev_path[i], len, "/pci@%s", dev_addr[i]);
    515 		if (result < 0) {
    516 			return (NULL);
    517 		}
    518 	}
    519 
    520 	path_len -= (i - 1); /* leave room for one null char */
    521 	path = (char *)topo_mod_alloc(mod, path_len);
    522 	path = strcpy(path, dev_path[0]);
    523 
    524 	/* put the parts together */
    525 	for (i = 1; i < max_addrs; i++) {
    526 		path = strncat(path, dev_path[i], strlen(dev_path[i]) + 1);
    527 	}
    528 
    529 	/*
    530 	 * Cleanup
    531 	 */
    532 	for (i = 0; i < max_addrs; i++) {
    533 		if (dev_addr[i] != NULL) {
    534 			topo_mod_free(mod, dev_addr[i],
    535 			    strlen(dev_addr[i]) + 1);
    536 		}
    537 		if (dev_path[i] != NULL) {
    538 			topo_mod_free(mod, dev_path[i],
    539 			    strlen(dev_path[i]) + 1);
    540 		}
    541 	}
    542 
    543 	topo_mod_dprintf(mod, "pi_get_path: path = (%s)\n", path);
    544 	return (path);
    545 }
    546 
    547 
    548 /*
    549  * Get the product ID from the 'platform' node in the PRI
    550  *
    551  * The string must be freed with topo_mod_strfree()
    552  */
    553 char *
    554 pi_get_productid(topo_mod_t *mod, md_t *mdp)
    555 {
    556 	int		result;
    557 	char		*id = NULL;
    558 	size_t		platform_size;
    559 	mde_cookie_t	*platform_nodes = NULL;
    560 
    561 	topo_mod_dprintf(mod, "pi_get_product: enter\n");
    562 
    563 	/*
    564 	 * Search the PRI for nodes of type MD_STR_PLATFORM, which contains
    565 	 * the product-id in it's MD_STR_NAME property.
    566 	 */
    567 	result = pi_find_mdenodes(mod, mdp, MDE_INVAL_ELEM_COOKIE,
    568 	    MD_STR_PLATFORM, MD_STR_FWD, &platform_nodes, &platform_size);
    569 	if (result <= 0 || platform_nodes == NULL) {
    570 		/* We did not find any platform nodes */
    571 		return (NULL);
    572 	}
    573 	topo_mod_dprintf(mod, "pi_get_productid: found %d platform nodes\n",
    574 	    result);
    575 
    576 	/*
    577 	 * There should only be 1 platform node, so we will always
    578 	 * use the first if we find any at all.
    579 	 */
    580 	result = md_get_prop_str(mdp, platform_nodes[0], MD_STR_NAME, &id);
    581 	topo_mod_free(mod, platform_nodes, platform_size);
    582 
    583 	/* Everything is freed up and it's time to return the platform-id */
    584 	if (result != 0 || id == NULL || strlen(id) == 0) {
    585 		return (NULL);
    586 	}
    587 	topo_mod_dprintf(mod, "pi_get_product: returning %s\n", id);
    588 
    589 	return (topo_mod_strdup(mod, id));
    590 }
    591 
    592 
    593 /*
    594  * Return the revision string to the caller.
    595  *
    596  * The string must be freed with topo_mod_strfree()
    597  */
    598 char *
    599 pi_get_revision(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
    600 {
    601 	int	result;
    602 	char	*rp = NULL;
    603 
    604 	result = md_get_prop_str(mdp, mde_node, MD_STR_REVISION_NUMBER, &rp);
    605 	if (result != 0 || rp == NULL || strlen(rp) == 0) {
    606 		return (NULL);
    607 	}
    608 
    609 	return (topo_mod_strdup(mod, rp));
    610 }
    611 
    612 
    613 /*
    614  * Return the serial number string to the caller.
    615  *
    616  * The string must be freed with topo_mod_strfree()
    617  */
    618 char *
    619 pi_get_serial(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
    620 {
    621 	int		result;
    622 	uint64_t	sn;
    623 	char		*sp = NULL;
    624 	char		buf[MAXNAMELEN];
    625 
    626 	result = md_get_prop_str(mdp, mde_node, MD_STR_SERIAL_NUMBER, &sp);
    627 	if (result != 0 || sp == NULL || strlen(sp) == 0) {
    628 		/* Is this a uint64_t type serial number? */
    629 		result = md_get_prop_val(mdp, mde_node, MD_STR_SERIAL_NUMBER,
    630 		    &sn);
    631 		if (result != 0) {
    632 			/* No.  We have failed to find a serial number */
    633 			return (NULL);
    634 		}
    635 		topo_mod_dprintf(mod, "pi_get_serial: node_0x%llx numeric "
    636 		    "serial number %llx\n", (uint64_t)mde_node, sn);
    637 
    638 		/* Convert the acquired value to a string */
    639 		result = snprintf(buf, sizeof (buf), "%llu", sn);
    640 		if (result < 0) {
    641 			return (NULL);
    642 		}
    643 		sp = buf;
    644 	}
    645 	topo_mod_dprintf(mod, "pi_get_serial: node_0x%llx = %s\n",
    646 	    (uint64_t)mde_node, (sp == NULL ? "NULL" : sp));
    647 
    648 	return (topo_mod_strdup(mod, sp));
    649 }
    650 
    651 
    652 /*
    653  * Get the server hostname (the ID as far as the topo authority is
    654  * concerned) from sysinfo and return a copy to the caller.
    655  *
    656  * The string must be freed with topo_mod_strfree()
    657  */
    658 char *
    659 pi_get_serverid(topo_mod_t *mod)
    660 {
    661 	int	result;
    662 	char	hostname[MAXNAMELEN];
    663 
    664 	topo_mod_dprintf(mod, "pi_get_serverid: enter\n");
    665 
    666 	result = sysinfo(SI_HOSTNAME, hostname, sizeof (hostname));
    667 	/* Everything is freed up and it's time to return the platform-id */
    668 	if (result == -1) {
    669 		return (NULL);
    670 	}
    671 	topo_mod_dprintf(mod, "pi_get_serverid: hostname = %s\n", hostname);
    672 
    673 	return (topo_mod_strdup(mod, hostname));
    674 }
    675 
    676 
    677 /*
    678  * Get the hc scheme name for the given node
    679  */
    680 char *
    681 pi_get_topo_hc_name(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
    682 {
    683 	int	result;
    684 	char	*hc_name;
    685 
    686 	/*
    687 	 * Request the hc name from the node.
    688 	 */
    689 	hc_name = NULL;
    690 	result = md_get_prop_str(mdp, mde_node, MD_STR_TOPO_HC_NAME, &hc_name);
    691 	if (result != 0 || hc_name == NULL) {
    692 		topo_mod_dprintf(mod,
    693 		    "failed to get property %s from node_0x%llx\n",
    694 		    MD_STR_TOPO_HC_NAME, (uint64_t)mde_node);
    695 		return (NULL);
    696 	}
    697 
    698 	/* Return a copy of the type string */
    699 	return (topo_mod_strdup(mod, hc_name));
    700 }
    701 
    702 
    703 /*
    704  * Calculate the authority information for a node.  Inherit the data if
    705  * possible, but always create an appropriate property group.
    706  */
    707 int
    708 pi_set_auth(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
    709     tnode_t *t_parent, tnode_t *t_node)
    710 {
    711 	int 		result;
    712 	int		err;
    713 	nvlist_t	*auth;
    714 	char		*val = NULL;
    715 	char		*prod = NULL;
    716 	char		*psn = NULL;
    717 	char		*csn = NULL;
    718 	char		*server = NULL;
    719 
    720 	if (mod == NULL || mdp == NULL || t_parent == NULL || t_node == NULL) {
    721 		return (-1);
    722 	}
    723 
    724 	result = topo_pgroup_create(t_node, &auth_pgroup, &err);
    725 	if (result != 0 && err != ETOPO_PROP_DEFD) {
    726 		/*
    727 		 * We failed to create the property group and it was not
    728 		 * already defined.  Set the err code and return failure.
    729 		 */
    730 		topo_mod_seterrno(mod, err);
    731 		return (-1);
    732 	}
    733 
    734 	/* Get the authority information already available from the parent */
    735 	auth = topo_mod_auth(mod, t_parent);
    736 
    737 	/*
    738 	 * Set the authority data, inheriting it if possible, but creating it
    739 	 * if necessary.
    740 	 */
    741 
    742 	/* product-id */
    743 	result = topo_prop_inherit(t_node, FM_FMRI_AUTHORITY,
    744 	    FM_FMRI_AUTH_PRODUCT, &err);
    745 	if (result != 0 && err != ETOPO_PROP_DEFD) {
    746 		val = NULL;
    747 		result = nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT,
    748 		    &val);
    749 		if (result != 0 || val == NULL) {
    750 			/*
    751 			 * No product information in the parent node or auth
    752 			 * list.  Find the product information in the PRI.
    753 			 */
    754 			prod = pi_get_productid(mod, mdp);
    755 			if (prod == NULL) {
    756 				topo_mod_dprintf(mod, "pi_set_auth: product "
    757 				    "name not found for node_0x%llx\n",
    758 				    (uint64_t)mde_node);
    759 			}
    760 		} else {
    761 			/*
    762 			 * Dup the string.  If we cannot find it in the auth
    763 			 * nvlist we will need to free it, so this lets us
    764 			 * have a single code path.
    765 			 */
    766 			prod = topo_mod_strdup(mod, val);
    767 		}
    768 
    769 		/*
    770 		 * We continue even if the product information is not available
    771 		 * to enumerate as much as possible.
    772 		 */
    773 		if (prod != NULL) {
    774 			result = topo_prop_set_string(t_node, FM_FMRI_AUTHORITY,
    775 			    FM_FMRI_AUTH_PRODUCT, TOPO_PROP_IMMUTABLE, prod,
    776 			    &err);
    777 			if (result != 0) {
    778 				/* Preserve the error and continue */
    779 				topo_mod_seterrno(mod, err);
    780 				topo_mod_dprintf(mod, "pi_set_auth: failed to "
    781 				    "set property %s (%d) : %s\n",
    782 				    FM_FMRI_AUTH_CHASSIS, err,
    783 				    topo_strerror(err));
    784 			}
    785 			topo_mod_strfree(mod, prod);
    786 		}
    787 	}
    788 
    789 	/* product-sn */
    790 	result = topo_prop_inherit(t_node, FM_FMRI_AUTHORITY,
    791 	    FM_FMRI_AUTH_PRODUCT_SN, &err);
    792 	if (result != 0 && err != ETOPO_PROP_DEFD) {
    793 		val = NULL;
    794 		result = nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT_SN,
    795 		    &val);
    796 		if (result != 0 || val == NULL) {
    797 			/*
    798 			 * No product-sn information in the parent node or auth
    799 			 * list.  Find the product-sn information in the PRI.
    800 			 */
    801 			psn = pi_get_productsn(mod, mdp, mde_node);
    802 			if (psn == NULL) {
    803 				topo_mod_dprintf(mod, "pi_set_auth: psn "
    804 				    "name not found for node_0x%llx\n",
    805 				    (uint64_t)mde_node);
    806 			}
    807 		} else {
    808 			/*
    809 			 * Dup the string.  If we cannot find it in the auth
    810 			 * nvlist we will need to free it, so this lets us
    811 			 * have a single code path.
    812 			 */
    813 			psn = topo_mod_strdup(mod, val);
    814 		}
    815 
    816 		/*
    817 		 * We continue even if the product information is not available
    818 		 * to enumerate as much as possible.
    819 		 */
    820 		if (psn != NULL) {
    821 			result = topo_prop_set_string(t_node, FM_FMRI_AUTHORITY,
    822 			    FM_FMRI_AUTH_PRODUCT_SN, TOPO_PROP_IMMUTABLE, psn,
    823 			    &err);
    824 			if (result != 0) {
    825 				/* Preserve the error and continue */
    826 				topo_mod_seterrno(mod, err);
    827 				topo_mod_dprintf(mod, "pi_set_auth: failed to "
    828 				    "set property %s (%d) : %s\n",
    829 				    FM_FMRI_AUTH_PRODUCT_SN, err,
    830 				    topo_strerror(err));
    831 			}
    832 			topo_mod_strfree(mod, psn);
    833 		}
    834 	}
    835 
    836 	/* chassis-id */
    837 	result = topo_prop_inherit(t_node, FM_FMRI_AUTHORITY,
    838 	    FM_FMRI_AUTH_CHASSIS, &err);
    839 	if (result != 0 && err != ETOPO_PROP_DEFD) {
    840 		val = NULL;
    841 		result = nvlist_lookup_string(auth, FM_FMRI_AUTH_CHASSIS,
    842 		    &val);
    843 		if (result != 0 || val == NULL) {
    844 			/*
    845 			 * No product information in the parent node or auth
    846 			 * list.  Find the product information in the PRI.
    847 			 */
    848 			csn = pi_get_chassisid(mod, mdp, mde_node);
    849 			if (csn == NULL) {
    850 				topo_mod_dprintf(mod, "pi_set_auth: csn "
    851 				    "name not found for node_0x%llx\n",
    852 				    (uint64_t)mde_node);
    853 			}
    854 		} else {
    855 			/*
    856 			 * Dup the string.  If we cannot find it in the auth
    857 			 * nvlist we will need to free it, so this lets us
    858 			 * have a single code path.
    859 			 */
    860 			csn = topo_mod_strdup(mod, val);
    861 		}
    862 
    863 		/*
    864 		 * We continue even if the product information is not available
    865 		 * to enumerate as much as possible.
    866 		 */
    867 		if (csn != NULL) {
    868 			result = topo_prop_set_string(t_node, FM_FMRI_AUTHORITY,
    869 			    FM_FMRI_AUTH_CHASSIS, TOPO_PROP_IMMUTABLE, csn,
    870 			    &err);
    871 			if (result != 0) {
    872 				/* Preserve the error and continue */
    873 				topo_mod_seterrno(mod, err);
    874 				topo_mod_dprintf(mod, "pi_set_auth: failed to "
    875 				    "set property %s (%d) : %s\n",
    876 				    FM_FMRI_AUTH_CHASSIS, err,
    877 				    topo_strerror(err));
    878 			}
    879 			topo_mod_strfree(mod, csn);
    880 		}
    881 	}
    882 
    883 	/* server-id */
    884 	result = topo_prop_inherit(t_node, FM_FMRI_AUTHORITY,
    885 	    FM_FMRI_AUTH_SERVER, &err);
    886 	if (result != 0 && err != ETOPO_PROP_DEFD) {
    887 		val = NULL;
    888 		result = nvlist_lookup_string(auth, FM_FMRI_AUTH_SERVER,
    889 		    &val);
    890 		if (result != 0 || val == NULL) {
    891 			/*
    892 			 * No product information in the parent node or auth
    893 			 * list.  Find the product information in the PRI.
    894 			 */
    895 			server = pi_get_serverid(mod);
    896 			if (server == NULL) {
    897 				topo_mod_dprintf(mod, "pi_set_auth: server "
    898 				    "name not found for node_0x%llx\n",
    899 				    (uint64_t)mde_node);
    900 			}
    901 		} else {
    902 			/*
    903 			 * Dup the string.  If we cannot find it in the auth
    904 			 * nvlist we will need to free it, so this lets us
    905 			 * have a single code path.
    906 			 */
    907 			server = topo_mod_strdup(mod, val);
    908 		}
    909 
    910 		/*
    911 		 * We continue even if the product information is not available
    912 		 * to enumerate as much as possible.
    913 		 */
    914 		if (server != NULL) {
    915 			result = topo_prop_set_string(t_node, FM_FMRI_AUTHORITY,
    916 			    FM_FMRI_AUTH_SERVER, TOPO_PROP_IMMUTABLE, server,
    917 			    &err);
    918 			if (result != 0) {
    919 				/* Preserve the error and continue */
    920 				topo_mod_seterrno(mod, err);
    921 				topo_mod_dprintf(mod, "pi_set_auth: failed to "
    922 				    "set property %s (%d) : %s\n",
    923 				    FM_FMRI_AUTH_SERVER, err,
    924 				    topo_strerror(err));
    925 			}
    926 			topo_mod_strfree(mod, server);
    927 		}
    928 	}
    929 
    930 	nvlist_free(auth);
    931 
    932 	return (0);
    933 }
    934 
    935 
    936 /*
    937  * Calculate a generic FRU for the given node.  If the node is not a FRU,
    938  * then inherit the FRU data from the nodes parent.
    939  */
    940 int
    941 pi_set_frufmri(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
    942     const char *name, topo_instance_t inst, tnode_t *t_parent, tnode_t *t_node)
    943 {
    944 	int		result;
    945 	int		err;
    946 	int		is_fru;
    947 	char		*part;
    948 	char		*rev;
    949 	char		*serial;
    950 	nvlist_t	*auth = NULL;
    951 	nvlist_t	*frufmri = NULL;
    952 
    953 	if (t_node == NULL || mod == NULL || mdp == NULL) {
    954 		return (-1);
    955 	}
    956 
    957 	/*
    958 	 * Determine if this node is a FRU
    959 	 */
    960 	result = pi_get_fru(mod, mdp, mde_node, &is_fru);
    961 	if (result != 0 || is_fru == 0) {
    962 		/* This node is not a FRU.  Inherit from parent and return */
    963 		topo_node_fru_set(t_node, NULL, 0, &result);
    964 		return (0);
    965 	}
    966 
    967 	/*
    968 	 * This node is a FRU.  Create an FMRI.
    969 	 */
    970 	part	= pi_get_part(mod, mdp, mde_node);
    971 	rev	= pi_get_revision(mod, mdp, mde_node);
    972 	serial	= pi_get_serial(mod, mdp, mde_node);
    973 	auth	= topo_mod_auth(mod, t_parent);
    974 	frufmri	= topo_mod_hcfmri(mod, t_parent, FM_HC_SCHEME_VERSION, name,
    975 	    inst, NULL, auth, part, rev, serial);
    976 	if (frufmri == NULL) {
    977 		topo_mod_dprintf(mod, "failed to create FRU: %s\n",
    978 		    topo_strerror(topo_mod_errno(mod)));
    979 	}
    980 	nvlist_free(auth);
    981 	topo_mod_strfree(mod, part);
    982 	topo_mod_strfree(mod, rev);
    983 	topo_mod_strfree(mod, serial);
    984 
    985 	/* Set the FRU, whether NULL or not */
    986 	result = topo_node_fru_set(t_node, frufmri, 0, &err);
    987 	if (result != 0)  {
    988 		topo_mod_seterrno(mod, err);
    989 	}
    990 	nvlist_free(frufmri);
    991 
    992 	return (result);
    993 }
    994 
    995 
    996 int
    997 pi_set_label(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node, tnode_t *t_node)
    998 {
    999 	int	result;
   1000 	int	err;
   1001 	char	*label;
   1002 
   1003 	if (mod == NULL || mdp == NULL) {
   1004 		return (-1);
   1005 	}
   1006 
   1007 	/*
   1008 	 * Get the label, if any, from the mde node and apply it as the label
   1009 	 * for this topology node.  Note that a NULL label will inherit the
   1010 	 * label from topology node's parent.
   1011 	 */
   1012 	label = pi_get_label(mod, mdp, mde_node);
   1013 	result = topo_node_label_set(t_node, label, &err);
   1014 	topo_mod_strfree(mod, label);
   1015 	if (result != 0) {
   1016 		topo_mod_seterrno(mod, err);
   1017 		topo_mod_dprintf(mod, "pi_set_label: failed with label %s "
   1018 		    "on node_0x%llx: %s\n", (label == NULL ? "NULL" : label),
   1019 		    (uint64_t)mde_node, topo_strerror(err));
   1020 	}
   1021 
   1022 	return (result);
   1023 }
   1024 
   1025 
   1026 /*
   1027  * Calculate the system information for a node.  Inherit the data if
   1028  * possible, but always create an appropriate property group.
   1029  */
   1030 int
   1031 pi_set_system(topo_mod_t *mod, tnode_t *t_node)
   1032 {
   1033 	int		result;
   1034 	int		err;
   1035 	struct utsname	uts;
   1036 	char		isa[MAXNAMELEN];
   1037 
   1038 	if (mod == NULL || t_node == NULL) {
   1039 		return (-1);
   1040 	}
   1041 
   1042 	result = topo_pgroup_create(t_node, &sys_pgroup, &err);
   1043 	if (result != 0 && err != ETOPO_PROP_DEFD) {
   1044 		/*
   1045 		 * We failed to create the property group and it was not
   1046 		 * already defined.  Set the err code and return failure.
   1047 		 */
   1048 		topo_mod_seterrno(mod, err);
   1049 		return (-1);
   1050 	}
   1051 
   1052 	result = topo_prop_inherit(t_node, TOPO_PGROUP_SYSTEM, TOPO_PROP_ISA,
   1053 	    &err);
   1054 	if (result != 0 && err != ETOPO_PROP_DEFD) {
   1055 		isa[0] = '\0';
   1056 		result = sysinfo(SI_ARCHITECTURE, isa, sizeof (isa));
   1057 		if (result == -1) {
   1058 			/* Preserve the error and continue */
   1059 			topo_mod_dprintf(mod, "pi_set_system: failed to "
   1060 			    "read SI_ARCHITECTURE: %d\n", errno);
   1061 		}
   1062 		if (strnlen(isa, MAXNAMELEN) > 0) {
   1063 			result = topo_prop_set_string(t_node,
   1064 			    TOPO_PGROUP_SYSTEM, TOPO_PROP_ISA,
   1065 			    TOPO_PROP_IMMUTABLE, isa, &err);
   1066 			if (result != 0) {
   1067 				/* Preserve the error and continue */
   1068 				topo_mod_seterrno(mod, err);
   1069 				topo_mod_dprintf(mod, "pi_set_auth: failed to "
   1070 				    "set property %s (%d) : %s\n",
   1071 				    TOPO_PROP_ISA, err, topo_strerror(err));
   1072 			}
   1073 		}
   1074 	}
   1075 
   1076 	result = topo_prop_inherit(t_node, TOPO_PGROUP_SYSTEM,
   1077 	    TOPO_PROP_MACHINE, &err);
   1078 	if (result != 0 && err != ETOPO_PROP_DEFD) {
   1079 		result = uname(&uts);
   1080 		if (result == -1) {
   1081 			/* Preserve the error and continue */
   1082 			topo_mod_seterrno(mod, errno);
   1083 			topo_mod_dprintf(mod, "pi_set_system: failed to "
   1084 			    "read uname: %d\n", errno);
   1085 		}
   1086 		if (strnlen(uts.machine, sizeof (uts.machine)) > 0) {
   1087 			result = topo_prop_set_string(t_node,
   1088 			    TOPO_PGROUP_SYSTEM, TOPO_PROP_MACHINE,
   1089 			    TOPO_PROP_IMMUTABLE, uts.machine, &err);
   1090 			if (result != 0) {
   1091 				/* Preserve the error and continue */
   1092 				topo_mod_seterrno(mod, err);
   1093 				topo_mod_dprintf(mod, "pi_set_auth: failed to "
   1094 				    "set property %s (%d) : %s\n",
   1095 				    TOPO_PROP_MACHINE, err, topo_strerror(err));
   1096 			}
   1097 		}
   1098 	}
   1099 
   1100 	return (0);
   1101 }
   1102 
   1103 
   1104 tnode_t *
   1105 pi_node_bind(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
   1106     tnode_t *t_parent, const char *hc_name, topo_instance_t inst,
   1107     nvlist_t *fmri)
   1108 {
   1109 	int	result;
   1110 	tnode_t	*t_node;
   1111 
   1112 	if (t_parent == NULL) {
   1113 		topo_mod_dprintf(mod,
   1114 		    "cannot bind for node_0x%llx instance %d type %s\n",
   1115 		    (uint64_t)mde_node, inst, hc_name);
   1116 		return (NULL);
   1117 	}
   1118 
   1119 	/* Bind this node to the parent */
   1120 	t_node = topo_node_bind(mod, t_parent, hc_name, inst, fmri);
   1121 	if (t_node == NULL) {
   1122 		topo_mod_dprintf(mod,
   1123 		    "failed to bind node_0x%llx instance %d: %s\n",
   1124 		    (uint64_t)mde_node, (uint32_t)inst,
   1125 		    topo_strerror(topo_mod_errno(mod)));
   1126 		return (NULL);
   1127 	}
   1128 	topo_mod_dprintf(mod, "bound node_0x%llx instance %d type %s\n",
   1129 	    (uint64_t)mde_node, inst, hc_name);
   1130 
   1131 	/*
   1132 	 * We have bound the node.  Now decorate it with an appropriate
   1133 	 * FRU and label (which may be inherited from the parent).
   1134 	 */
   1135 	result = pi_set_frufmri(mod, mdp, mde_node, hc_name, inst, t_parent,
   1136 	    t_node);
   1137 	if (result != 0) {
   1138 		/*
   1139 		 * Though we have failed to set the FRU FMRI we still continue.
   1140 		 * The module errno is set by the called routine, so we report
   1141 		 * the problem and move on.
   1142 		 */
   1143 		topo_mod_dprintf(mod,
   1144 		    "failed to set FRU FMRI for node_0x%llx\n",
   1145 		    (uint64_t)mde_node);
   1146 	}
   1147 
   1148 	result = pi_set_label(mod, mdp, mde_node, t_node);
   1149 	if (result != 0) {
   1150 		/*
   1151 		 * Though we have failed to set the label, we still continue.
   1152 		 * The module errno is set by the called routine, so we report
   1153 		 * the problem and move on.
   1154 		 */
   1155 		topo_mod_dprintf(mod, "failed to set label for node_0x%llx\n",
   1156 		    (uint64_t)mde_node);
   1157 	}
   1158 
   1159 	result = pi_set_auth(mod, mdp, mde_node, t_parent, t_node);
   1160 	if (result != 0) {
   1161 		/*
   1162 		 * Though we have failed to set the authority, we still
   1163 		 * continue. The module errno is set by the called routine, so
   1164 		 * we report the problem and move on.
   1165 		 */
   1166 		topo_mod_dprintf(mod, "failed to set authority for "
   1167 		    "node_0x%llx\n", (uint64_t)mde_node);
   1168 	}
   1169 
   1170 	result = pi_set_system(mod, t_node);
   1171 	if (result != 0) {
   1172 		/*
   1173 		 * Though we have failed to set the system group, we still
   1174 		 * continue. The module errno is set by the called routine, so
   1175 		 * we report the problem and move on.
   1176 		 */
   1177 		topo_mod_dprintf(mod, "failed to set system for node_0x%llx\n",
   1178 		    (uint64_t)mde_node);
   1179 	}
   1180 
   1181 	return (t_node);
   1182 }
   1183