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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 }