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