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