xref: /titanic_50/usr/src/cmd/picl/plugins/sun4u/snowbird/frutree/picllibdevinfo.c (revision fa9e4066f08beec538e775443c5be79dd423fcab)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Implementation to interact with libdevinfo to find port nodes,
31  * and information regarding each node (fru, port, location).
32  */
33 
34 #include <stdio.h>
35 #include <libdevinfo.h>
36 #include <picl.h>
37 #include <picltree.h>
38 #include <strings.h>
39 #include <stdlib.h>
40 #include <config_admin.h>
41 #include <sys/types.h>
42 #include <sys/obpdefs.h>
43 #include <sys/pci.h>
44 #include <picldefs.h>
45 #include "piclfrutree.h"
46 
47 #include <syslog.h>
48 
49 static di_prom_handle_t	prom_handle = DI_PROM_HANDLE_NIL;
50 extern int frutree_debug;
51 
52 typedef struct {
53 	di_node_t rnode;
54 	char 	bus_addr[PICL_PROPNAMELEN_MAX];
55 	char 	path[PICL_PROPNAMELEN_MAX];
56 	void 	*arg;
57 	picl_errno_t retval;
58 } frutree_devinfo_t;
59 
60 typedef struct p_info {
61 	frutree_port_type_t	type;
62 	int  geo_addr;
63 	int  instance;
64 	char drv_name[20];
65 	char bus_addr[20];
66 	char devfs_path[MAXPATHLEN];
67 	struct p_info	*next;
68 }port_info_t;
69 
70 typedef struct {
71 	port_info_t	*first;
72 	port_info_t	*last;
73 	int		n_serial;
74 	int		n_parallel;
75 	int		n_network;
76 } plist_t;
77 
78 static void
free_list(plist_t * listptr)79 free_list(plist_t *listptr)
80 {
81 	port_info_t	*tmp;
82 	port_info_t	*nextptr;
83 	if (listptr == NULL)
84 		return;
85 
86 	nextptr = listptr->first;
87 	while (nextptr != NULL) {
88 		tmp = nextptr;
89 		nextptr = nextptr->next;
90 		free(tmp);
91 	}
92 }
93 
94 /* (callback function for qsort) compare the bus_addr */
95 static int
compare(const void * a,const void * b)96 compare(const void *a, const void *b)
97 {
98 	port_info_t *pinfo1, *pinfo2;
99 	port_info_t **ptr2pinfo1, **ptr2pinfo2;
100 
101 	ptr2pinfo1 = (port_info_t **)a;
102 	ptr2pinfo2 = (port_info_t **)b;
103 
104 	pinfo1 = (port_info_t *)*ptr2pinfo1;
105 	pinfo2 = (port_info_t *)*ptr2pinfo2;
106 	return (strcmp(pinfo1->bus_addr, pinfo2->bus_addr));
107 }
108 
109 /*
110  * assigns GeoAddr property for ports based on bus-addr
111  */
112 static picl_errno_t
assign_geo_addr(plist_t * list,frutree_port_type_t type)113 assign_geo_addr(plist_t *list, frutree_port_type_t type)
114 {
115 
116 	int i = 0;
117 	port_info_t **port_info = NULL;
118 	port_info_t *nextptr = NULL;
119 	int num_ports = 0;
120 
121 	if (list == NULL) {
122 		return (PICL_FAILURE);
123 	}
124 
125 	if (list->first == NULL) {
126 		return (PICL_SUCCESS);
127 	}
128 
129 	switch (type) {
130 	case SERIAL_PORT:
131 	if (list->n_serial == 0) {
132 		return (PICL_SUCCESS);
133 	}
134 	num_ports = list->n_serial;
135 	break;
136 
137 	case PARALLEL_PORT:
138 	if (list->n_parallel == 0) {
139 		return (PICL_SUCCESS);
140 	}
141 	num_ports = list->n_parallel;
142 	break;
143 
144 	case NETWORK_PORT:
145 	if (list->n_network == 0) {
146 		return (PICL_SUCCESS);
147 	}
148 	num_ports = list->n_network;
149 	break;
150 
151 	}
152 
153 	port_info = (port_info_t **)malloc(
154 		sizeof (port_info_t *) * num_ports);
155 	if (port_info == NULL) {
156 		return (PICL_NOSPACE);
157 	}
158 
159 	/* traverse thru list and look for ports of given type */
160 	nextptr = list->first;
161 	while (nextptr != NULL) {
162 		if (nextptr->type != type) {
163 			nextptr = nextptr->next;
164 			continue;
165 		}
166 		port_info[i] = nextptr;
167 		nextptr = nextptr->next;
168 		i++;
169 	}
170 
171 	/* sort the nodes to assign geo_address */
172 	(void) qsort((void *)port_info, num_ports,
173 		sizeof (port_info_t *), compare);
174 	for (i = 0; i < num_ports; i++) {
175 		if (port_info[i] != NULL) {
176 			port_info[i]->geo_addr = i + 1;
177 		}
178 	}
179 	free(port_info);
180 	return (PICL_SUCCESS);
181 }
182 
183 static picl_errno_t
create_port_config_info(plist_t * list,frutree_device_args_t * devp)184 create_port_config_info(plist_t *list, frutree_device_args_t *devp)
185 {
186 	port_info_t *port_info = NULL;
187 	frutree_cache_t	*cachep = NULL;
188 	char port_type[PICL_PROPNAMELEN_MAX];
189 	char label[PICL_PROPNAMELEN_MAX];
190 
191 	if (list == NULL) {
192 		return (PICL_FAILURE);
193 	}
194 
195 	port_info = list->first;
196 	while (port_info != NULL) {
197 
198 		cachep = (frutree_cache_t *)malloc(sizeof (frutree_cache_t));
199 		if (cachep == NULL) {
200 			return (PICL_NOSPACE);
201 		}
202 
203 		switch (port_info->type) {
204 		case NETWORK_PORT:
205 			(void) strncpy(label, SANIBEL_NETWORK_LABEL,
206 				sizeof (label));
207 			(void) strncpy(port_type, SANIBEL_NETWORK_PORT,
208 				sizeof (port_type));
209 			break;
210 		case PARALLEL_PORT:
211 			(void) strncpy(label, SANIBEL_PARALLEL_PORT,
212 				sizeof (label));
213 			(void) strncpy(port_type, SANIBEL_PARALLEL_PORT,
214 				sizeof (port_type));
215 			break;
216 		case SERIAL_PORT:
217 			(void) strncpy(label, SANIBEL_SERIAL_PORT,
218 				sizeof (label));
219 			(void) strncpy(port_type, SANIBEL_SERIAL_PORT,
220 				sizeof (port_type));
221 			break;
222 		default:
223 			port_info = port_info->next;
224 		}
225 		cachep->buf[0] = '\0';
226 		cachep->next = NULL;
227 		(void) snprintf(cachep->buf,
228 			sizeof (cachep->buf),
229 			"\n%s %s%d %s\n"
230 			"\t%s %s %s %s 0 \"%s %d\"\n"
231 			"\t%s %s %s %s 0 \"%s\"\n"
232 			"\t%s %s %s %s 1 %d\n"
233 			"\t%s %s %s %s 0 \"%s\"\n"
234 			"\t%s %s %s %s 0 \"%s\"\n"
235 			"%s\n",
236 			"NODE", port_info->drv_name, port_info->instance,
237 				PICL_CLASS_PORT,
238 			"PROP", PICL_PROP_LABEL, "string", "r",
239 				label, (port_info->geo_addr -1),
240 			"PROP", PICL_PROP_BUS_ADDR, "string",
241 				"r", port_info->bus_addr,
242 			"PROP", PICL_PROP_GEO_ADDR, "uint",
243 				"r", port_info->geo_addr,
244 			"PROP", PICL_PROP_PORT_TYPE, "string",
245 				"r", port_type,
246 			"PROP", PICL_PROP_DEVFS_PATH, "string",
247 				"r", port_info->devfs_path,
248 			"ENDNODE");
249 
250 			/* add to the cache */
251 			if (devp->first == NULL) {	/* 1st node */
252 				devp->first = cachep;
253 				devp->last = NULL;
254 			} else if (devp->last != NULL) { /* last node */
255 				devp->last->next = cachep;
256 				devp->last = cachep;
257 			} else {			/* 2nd node */
258 				devp->first->next = cachep;
259 				devp->last = cachep;
260 			}
261 		port_info = port_info->next;	/* advance to next node */
262 	}
263 	return (PICL_SUCCESS);
264 }
265 
266 /*ARGSUSED*/
267 static int
load_driver(di_node_t node,void * arg)268 load_driver(di_node_t node, void *arg)
269 {
270 	char *drv_name = NULL;
271 	char cmd[MAXPATHLEN];
272 
273 	if (di_node_state(node) >= DS_ATTACHED) {
274 		return (DI_WALK_CONTINUE);
275 	}
276 	drv_name = di_driver_name(node);
277 	if (drv_name == NULL) {
278 		return (DI_WALK_CONTINUE);
279 	}
280 
281 	(void) snprintf(cmd, sizeof (cmd), "%s %s",
282 		DEVFSADM_CMD, drv_name);
283 	(void) pclose(popen(cmd, "r"));
284 	return (DI_WALK_CONTINUE);
285 }
286 
287 static picl_errno_t
load_drivers(char * path)288 load_drivers(char *path)
289 {
290 	di_node_t	rnode;
291 	if (path == NULL) {
292 		return (PICL_INVALIDARG);
293 	}
294 
295 	rnode = di_init(path, DINFOSUBTREE|DINFOMINOR);
296 	if (rnode == DI_NODE_NIL) {
297 		return (PICL_FAILURE);
298 	}
299 
300 	if (di_walk_node(rnode, DI_WALK_CLDFIRST, NULL, load_driver) != 0) {
301 		di_fini(rnode);
302 		return (PICL_FAILURE);
303 	}
304 
305 	di_fini(rnode);
306 	return (PICL_SUCCESS);
307 }
308 
309 /*
310  * probe for port nodes
311  */
312 static int
probe_tree(di_node_t node,void * arg)313 probe_tree(di_node_t node, void *arg)
314 {
315 	char *nodetype = NULL;
316 	char *devfs_path = NULL;
317 	char *bus_addr = NULL;
318 	char *drv_name = NULL;
319 	plist_t *listptr = NULL;
320 	port_info_t *port_info = NULL;
321 	frutree_port_type_t port_type = UNKNOWN_PORT;
322 	di_minor_t minor = DI_MINOR_NIL;
323 
324 	if (arg == NULL) {
325 		return (DI_WALK_TERMINATE);
326 	}
327 	listptr = (plist_t *)arg;
328 
329 	while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
330 		nodetype = di_minor_nodetype(minor);
331 		if (nodetype == NULL) {
332 			continue;
333 		}
334 
335 		if (strcmp(nodetype, DDI_NT_NET) == 0) {
336 			port_type = NETWORK_PORT;
337 		} else if (strcmp(nodetype, DDI_NT_PARALLEL) == 0) {
338 			port_type = PARALLEL_PORT;
339 		} else if ((strcmp(nodetype, DDI_NT_SERIAL) == 0) ||
340 			(strcmp(nodetype, DDI_NT_SERIAL_MB) == 0) ||
341 			(strcmp(nodetype, DDI_NT_SERIAL_DO) == 0) ||
342 			(strcmp(nodetype, DDI_NT_SERIAL_MB_DO) == 0)) {
343 			port_type = SERIAL_PORT;
344 		} else {
345 			continue;
346 		}
347 
348 		/* found port node */
349 		devfs_path = di_devfs_path(node);
350 		if (devfs_path == NULL) {
351 			continue;
352 		}
353 
354 		bus_addr = di_bus_addr(node);
355 		drv_name = di_driver_name(node);
356 
357 		if ((bus_addr == NULL) || (drv_name == NULL)) {
358 			di_devfs_path_free(devfs_path);
359 			continue;
360 		}
361 
362 		port_info = malloc(sizeof (port_info_t));
363 		if (port_info == NULL) {
364 			di_devfs_path_free(devfs_path);
365 			return (PICL_NOSPACE);
366 		}
367 
368 		(void) strncpy(port_info->devfs_path, devfs_path,
369 			sizeof (port_info->devfs_path));
370 		(void) strncpy(port_info->bus_addr, bus_addr,
371 			sizeof (port_info->bus_addr));
372 		(void) strncpy(port_info->drv_name, drv_name,
373 			sizeof (port_info->drv_name));
374 		port_info->type = port_type;
375 		port_info->instance = di_instance(node);
376 		port_info->geo_addr = -1;
377 		port_info->next = NULL;
378 
379 		switch (port_type) {
380 		case NETWORK_PORT:
381 			listptr->n_network++;
382 			break;
383 		case SERIAL_PORT:
384 			listptr->n_serial++;
385 			break;
386 		case PARALLEL_PORT:
387 			listptr->n_parallel++;
388 			break;
389 		}
390 
391 		/* add to the list */
392 		if (listptr->first == NULL) {	/* 1st node */
393 			listptr->first = port_info;
394 			listptr->last = NULL;
395 		} else if (listptr->last != NULL) { /* last node */
396 			listptr->last->next = port_info;
397 			listptr->last = port_info;
398 		} else {			/* 2nd node */
399 			listptr->first->next = port_info;
400 			listptr->last = port_info;
401 		}
402 		di_devfs_path_free(devfs_path);
403 		return (DI_WALK_CONTINUE);
404 	}
405 	return (DI_WALK_CONTINUE);
406 }
407 
408 /* This routine probes libdevinfo for port nodes */
409 picl_errno_t
probe_libdevinfo(frutree_frunode_t * frup,frutree_device_args_t ** device,boolean_t load_drv)410 probe_libdevinfo(frutree_frunode_t *frup, frutree_device_args_t ** device,
411 	boolean_t load_drv)
412 {
413 	di_node_t	rnode;
414 	picl_errno_t	rc;
415 	plist_t	list;
416 
417 	if (frup == NULL) {
418 		return (PICL_FAILURE);
419 	}
420 	FRUTREE_DEBUG1(EVENTS, "loading drivers for %s", frup->name);
421 
422 	if (load_drv == B_TRUE) {
423 		if ((rc = load_drivers(frup->fru_path)) != PICL_SUCCESS) {
424 			return (rc);
425 		}
426 	}
427 	FRUTREE_DEBUG1(EVENTS, "done with loading drivers for %s", frup->name);
428 
429 	rnode = di_init(frup->fru_path, DINFOSUBTREE|DINFOMINOR);
430 	if (rnode == DI_NODE_NIL) {
431 		return (PICL_FAILURE);
432 	}
433 
434 	list.first = NULL;
435 	list.last = NULL;
436 	list.n_network = 0;
437 	list.n_serial = 0;
438 	list.n_parallel = 0;
439 
440 	if (di_walk_node(rnode, DI_WALK_CLDFIRST, &list, probe_tree) != 0) {
441 		di_fini(rnode);
442 		free_list(&list);
443 		return (PICL_FAILURE);
444 	}
445 
446 	if (list.n_serial > 0)
447 	if ((rc = assign_geo_addr(&list, SERIAL_PORT)) != PICL_SUCCESS) {
448 		di_fini(rnode);
449 		free_list(&list);
450 		return (rc);
451 	}
452 
453 	if (list.n_network > 0)
454 	if ((rc = assign_geo_addr(&list, NETWORK_PORT)) != PICL_SUCCESS) {
455 		di_fini(rnode);
456 		free_list(&list);
457 		return (rc);
458 	}
459 
460 	if (list.n_parallel > 0)
461 	if ((rc = assign_geo_addr(&list, PARALLEL_PORT)) != PICL_SUCCESS) {
462 		di_fini(rnode);
463 		free_list(&list);
464 		return (rc);
465 	}
466 
467 	if ((rc = create_port_config_info(&list, *device)) != PICL_SUCCESS) {
468 		di_fini(rnode);
469 		free_list(&list);
470 		return (rc);
471 	}
472 
473 	di_fini(rnode);
474 	free_list(&list);
475 	FRUTREE_DEBUG1(EVENTS, "done with probing %s", frup->name);
476 	return (PICL_SUCCESS);
477 }
478 
479 static int
get_reg_dev(di_node_t node)480 get_reg_dev(di_node_t node)
481 {
482 	int *reg = NULL;
483 	if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, OBP_REG, &reg) < 0) {
484 		if (di_prom_prop_lookup_ints(prom_handle, node, OBP_REG,
485 			&reg) < 0) {
486 			return (-1);
487 		}
488 		return (PCI_REG_DEV_G(reg[0]));
489 	}
490 	return (PCI_REG_DEV_G(reg[0]));
491 }
492 
493 static int
walk_tree(di_node_t node,void * arg)494 walk_tree(di_node_t node, void *arg)
495 {
496 	char	*path = NULL;
497 	char	*bus_addr = NULL;
498 	char	*char_di_bus_addr = NULL;
499 	int	busaddr = 0;
500 	int	di_busaddr = 0;
501 	char 	*node_name = NULL;
502 	frutree_devinfo_t *devinfo;
503 	frutree_frunode_t *frup = NULL;
504 
505 	devinfo = *(frutree_devinfo_t **)arg;
506 	frup = (frutree_frunode_t *)devinfo->arg;
507 	if (frup == NULL) {
508 		return (DI_WALK_TERMINATE);
509 	}
510 
511 	if (devinfo->rnode == node) {	/* skip the root node */
512 		return (DI_WALK_CONTINUE);
513 	}
514 	bus_addr = devinfo->bus_addr;
515 
516 	char_di_bus_addr = di_bus_addr(node);
517 	if (char_di_bus_addr == NULL) {
518 		/*
519 		 * look for reg property
520 		 * This applies to only cPCI devices
521 		 */
522 		if (strstr(bus_addr, ",") != NULL) {
523 			/* bus addr is of type 1,0 */
524 			/* we dont handle this case yet */
525 			return (DI_WALK_PRUNECHILD);
526 		}
527 		di_busaddr = get_reg_dev(node);
528 		if (di_busaddr == -1) {
529 			/* reg prop not found */
530 			return (DI_WALK_PRUNECHILD);
531 		}
532 
533 		/* check if the bus addresses are same */
534 		errno = 0;
535 		busaddr = strtol(bus_addr, (char **)NULL, 16);
536 		if (errno != 0) {
537 			return (DI_WALK_TERMINATE);
538 		}
539 		if (di_busaddr != busaddr) {
540 			return (DI_WALK_PRUNECHILD);
541 		}
542 
543 		/* build the fru path name */
544 		/* parent_path/nodename@bus_addr */
545 		node_name = di_node_name(node);
546 		if (node_name == NULL) {
547 			return (DI_WALK_TERMINATE);
548 		}
549 		(void) snprintf(devinfo->path, sizeof (devinfo->path),
550 			"%s/%s@%s", frup->fru_path, node_name, bus_addr);
551 		return (DI_WALK_TERMINATE);
552 	}
553 
554 	if (strstr(bus_addr, ",") != NULL) { /* bus addr is of type 1,0 */
555 		if (strcmp(bus_addr, char_di_bus_addr) != 0) {
556 			return (DI_WALK_PRUNECHILD);
557 		}
558 	} else { /* bus addr is of type 0x */
559 
560 		/* check if the values are same */
561 		errno = 0;
562 		busaddr = strtol(bus_addr, (char **)NULL, 16);
563 		if (errno != 0) {
564 			return (DI_WALK_TERMINATE);
565 		}
566 
567 		errno = 0;
568 		di_busaddr = strtol(char_di_bus_addr, (char **)NULL, 16);
569 		if (errno != 0) {
570 			return (DI_WALK_TERMINATE);
571 		}
572 
573 		if (di_busaddr != busaddr) {
574 			return (DI_WALK_PRUNECHILD);
575 		}
576 	}
577 
578 	/* node found */
579 	path = di_devfs_path(node);
580 	(void) strncpy(devinfo->path, path, sizeof (devinfo->path));
581 	di_devfs_path_free(path);
582 	return (DI_WALK_TERMINATE);
583 }
584 
585 picl_errno_t
get_fru_path(char * parent_path,frutree_frunode_t * frup)586 get_fru_path(char *parent_path, frutree_frunode_t *frup)
587 {
588 	picl_errno_t rc = 0;
589 	picl_nodehdl_t loch;
590 	di_node_t rnode;
591 	frutree_devinfo_t *devinfo = NULL;
592 	char slot_type[PICL_PROPNAMELEN_MAX];
593 	char probe_path[PICL_PROPNAMELEN_MAX];
594 	char bus_addr[PICL_PROPNAMELEN_MAX];
595 
596 	if ((rc = ptree_get_propval_by_name(frup->frunodeh, PICL_PROP_PARENT,
597 		&loch, sizeof (loch))) != PICL_SUCCESS) {
598 		return (rc);
599 	}
600 
601 	if ((rc = ptree_get_propval_by_name(loch, PICL_PROP_SLOT_TYPE,
602 		slot_type, sizeof (slot_type))) != PICL_SUCCESS) {
603 		return (rc);
604 	}
605 
606 	if (strcmp(slot_type, SANIBEL_SCSI_SLOT) == 0 ||
607 		strcmp(slot_type, SANIBEL_IDE_SLOT) == 0) {
608 		if (ptree_get_propval_by_name(loch, PICL_PROP_PROBE_PATH,
609 			probe_path, sizeof (probe_path)) != PICL_SUCCESS) {
610 			return (rc);
611 		}
612 		(void) strncpy(frup->fru_path, probe_path,
613 			sizeof (frup->fru_path));
614 		return (PICL_SUCCESS);
615 	}
616 
617 	prom_handle = di_prom_init();
618 	rnode = di_init(parent_path, DINFOSUBTREE|DINFOMINOR);
619 	if (rnode == DI_NODE_NIL) {
620 		di_prom_fini(prom_handle);
621 		return (PICL_FAILURE);
622 	}
623 
624 	devinfo = (frutree_devinfo_t *)malloc(sizeof (frutree_devinfo_t));
625 	if (devinfo == NULL) {
626 		di_fini(rnode);
627 		di_prom_fini(prom_handle);
628 		return (PICL_NOSPACE);
629 	}
630 
631 	if (ptree_get_propval_by_name(loch, PICL_PROP_BUS_ADDR,
632 		bus_addr, sizeof (bus_addr)) != PICL_SUCCESS) {
633 		free(devinfo);
634 		di_fini(rnode);
635 		di_prom_fini(prom_handle);
636 		return (rc);
637 	}
638 
639 	devinfo->rnode = rnode;
640 	(void) strncpy(devinfo->bus_addr, bus_addr, sizeof (devinfo->bus_addr));
641 	devinfo->path[0] = '\0';
642 	devinfo->arg = frup;
643 
644 	if (di_walk_node(rnode, DI_WALK_SIBFIRST, &devinfo, walk_tree) != 0) {
645 		di_fini(rnode);
646 		di_prom_fini(prom_handle);
647 		free(devinfo);
648 		return (PICL_FAILURE);
649 	}
650 	di_fini(rnode);
651 	di_prom_fini(prom_handle);
652 
653 	if (devinfo->path[0]) {
654 		(void) strncpy(frup->fru_path, devinfo->path,
655 			sizeof (frup->fru_path));
656 		free(devinfo);
657 		return (PICL_SUCCESS);
658 	} else {
659 		free(devinfo);
660 		return (PICL_NODENOTFOUND);
661 	}
662 }
663 
664 static int
find_fru_node(di_node_t node,void * arg)665 find_fru_node(di_node_t node, void *arg)
666 {
667 	frutree_locnode_t *locp = NULL;
668 	char	*char_di_bus_addr = NULL;
669 	int	busaddr = 0;
670 	int	di_busaddr = 0;
671 	char bus_addr[PICL_PROPNAMELEN_MAX];
672 	frutree_devinfo_t *devinfo = NULL;
673 
674 	devinfo = *(frutree_devinfo_t **)arg;
675 	locp = *(frutree_locnode_t **)devinfo->arg;
676 
677 	if (devinfo->rnode == node) {
678 		return (DI_WALK_CONTINUE);
679 	}
680 
681 	char_di_bus_addr = di_bus_addr(node);
682 	if (char_di_bus_addr == NULL) {
683 		return (DI_WALK_PRUNECHILD);
684 	}
685 
686 	if (ptree_get_propval_by_name(locp->locnodeh, PICL_PROP_BUS_ADDR,
687 		bus_addr, sizeof (bus_addr)) != PICL_SUCCESS) {
688 		return (DI_WALK_PRUNECHILD);
689 	}
690 
691 	if (strstr(bus_addr, ",") != NULL) {
692 		/* bus addr is of type 1,0 */
693 		if (strcmp(bus_addr, char_di_bus_addr) == 0) {
694 			devinfo->retval = PICL_SUCCESS;
695 			return (DI_WALK_TERMINATE);
696 		} else {
697 			return (DI_WALK_PRUNECHILD);
698 		}
699 	} else { /* bus addr is of type 0x */
700 
701 		/* check if the values are same */
702 		errno = 0;
703 		busaddr = strtol(bus_addr, (char **)NULL, 16);
704 		if (errno != 0) {
705 			return (DI_WALK_PRUNECHILD);
706 		}
707 
708 		errno = 0;
709 		di_busaddr = strtol(char_di_bus_addr, (char **)NULL, 16);
710 		if (errno != 0) {
711 			return (DI_WALK_PRUNECHILD);
712 		}
713 
714 		if (di_busaddr == busaddr) {
715 			devinfo->retval = PICL_SUCCESS;
716 			return (DI_WALK_TERMINATE);
717 		} else {
718 			return (DI_WALK_PRUNECHILD);
719 		}
720 	}
721 }
722 
723 /*
724  * checks if a fru is present under location using pdev-path and busaddr
725  */
726 boolean_t
is_fru_present_under_location(frutree_locnode_t * locp)727 is_fru_present_under_location(frutree_locnode_t *locp)
728 {
729 	di_node_t		rnode;
730 	frutree_devinfo_t	*devinfo = NULL;
731 	char probe_path[PICL_PROPNAMELEN_MAX];
732 
733 	if (locp == NULL) {
734 		return (B_FALSE);
735 	}
736 
737 	if (ptree_get_propval_by_name(locp->locnodeh, PICL_PROP_PROBE_PATH,
738 		probe_path, sizeof (probe_path)) != PICL_SUCCESS) {
739 		if (ptree_get_propval_by_name(locp->locnodeh,
740 			PICL_PROP_DEVFS_PATH, probe_path,
741 			sizeof (probe_path)) != PICL_SUCCESS) {
742 			return (B_FALSE);
743 		}
744 	}
745 
746 	rnode = di_init(probe_path, DINFOSUBTREE);
747 	if (rnode == DI_NODE_NIL) {
748 		di_fini(rnode);
749 		return (B_FALSE);
750 	}
751 
752 	devinfo = (frutree_devinfo_t *)malloc(sizeof (frutree_devinfo_t));
753 	if (devinfo == NULL) {
754 		di_fini(rnode);
755 		return (B_FALSE);
756 	}
757 	devinfo->rnode = rnode;
758 	devinfo->arg = (frutree_locnode_t **)&locp;
759 	devinfo->retval = PICL_FAILURE;
760 
761 	if (di_walk_node(rnode, DI_WALK_SIBFIRST, &devinfo,
762 		find_fru_node) != 0) {
763 		di_fini(rnode);
764 		free(devinfo);
765 		return (B_FALSE);
766 	}
767 	di_fini(rnode);
768 
769 	if (devinfo->retval == PICL_SUCCESS) {
770 		free(devinfo);
771 		return (B_TRUE);
772 	} else {
773 		free(devinfo);
774 		return (B_FALSE);
775 	}
776 }
777 
778 /*
779  * initializes the port driver and instance fields based on libdevinfo
780  */
781 picl_errno_t
get_port_info(frutree_portnode_t * portp)782 get_port_info(frutree_portnode_t *portp)
783 {
784 	picl_errno_t rc;
785 	di_node_t rnode, curr, peer;
786 	char devfs_path[PICL_PROPNAMELEN_MAX];
787 	char bus_addr[PICL_PROPNAMELEN_MAX];
788 	char *di_busaddr = NULL, *di_drv = NULL;
789 	int di_int_busaddr, int_busaddr;
790 
791 	if ((rc = ptree_get_propval_by_name(portp->portnodeh,
792 		PICL_PROP_DEVFS_PATH, devfs_path,
793 		sizeof (devfs_path))) != PICL_SUCCESS) {
794 		return (rc);
795 	}
796 
797 	if (ptree_get_propval_by_name(portp->portnodeh, PICL_PROP_BUS_ADDR,
798 		bus_addr, sizeof (bus_addr)) != PICL_SUCCESS) {
799 		return (rc);
800 	}
801 
802 	rnode = di_init(devfs_path, DINFOCPYALL);
803 	if (rnode == DI_NODE_NIL) {
804 		return (PICL_FAILURE);
805 	}
806 
807 	peer = di_child_node(rnode);
808 	while (peer != DI_NODE_NIL) {
809 		curr = peer;
810 		peer = di_sibling_node(curr);
811 
812 		di_busaddr = di_bus_addr(curr);
813 		if (di_busaddr == NULL) {
814 			continue;
815 		}
816 
817 		/* compare the bus_addr */
818 		if (strstr(bus_addr, ",") != NULL) {
819 			/* bus addr is of type 1,0 */
820 			if (strcmp(bus_addr, di_busaddr) != 0) {
821 				continue;
822 			}
823 		} else { /* bus addr is of type 0x */
824 			errno = 0;
825 			int_busaddr = strtol(bus_addr, (char **)NULL, 16);
826 			if (errno != 0) {
827 				continue;
828 			}
829 
830 			errno = 0;
831 			di_int_busaddr = strtol(di_busaddr, (char **)NULL, 16);
832 			if (errno != 0) {
833 				continue;
834 			}
835 
836 			if (di_int_busaddr != int_busaddr) {
837 				continue;
838 			}
839 		}
840 		di_drv = di_driver_name(curr);
841 		if (di_drv == NULL) {
842 			di_fini(rnode);
843 			return (PICL_FAILURE);
844 		}
845 		/* initialize the driver name and instance number */
846 		(void) strncpy(portp->driver, di_drv, sizeof (portp->driver));
847 		portp->instance = di_instance(curr);
848 		di_fini(rnode);
849 		return (PICL_SUCCESS);
850 	}
851 	di_fini(rnode);
852 	return (PICL_NODENOTFOUND);
853 }
854