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, ®) < 0) {
484 if (di_prom_prop_lookup_ints(prom_handle, node, OBP_REG,
485 ®) < 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