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 2000, 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * 26 * Littleneck Platform specific functions. 27 */ 28 29 #pragma ident "%Z%%M% %I% %E% SMI" 30 31 #include <libprtdiag.h> 32 #include <sys/mc.h> 33 34 35 static Prom_node *dev_next_node_by_compat(Prom_node *root, char *model); 36 static Prom_node *dev_find_node_by_compat(Prom_node *root, char *model); 37 38 static Board_node *littleneck_insert_board(Sys_tree *root, int board); 39 static Board_node *littleneck_find_board(Sys_tree *root, int board); 40 41 void print_us3_memory_line(int portid, 42 int bank_id, 43 uint64_t bank_size, 44 char *bank_status, 45 uint64_t dimm_size, 46 uint32_t intlv, 47 int seg_id); 48 49 void add_node(Sys_tree *root, Prom_node *pnode); 50 int do_prominfo(int syserrlog, 51 char *pgname, 52 int log_flag, 53 int prt_flag); 54 55 void *get_prop_val(Prop *prop); 56 Prop *find_prop(Prom_node *pnode, char *name); 57 char *get_node_name(Prom_node *pnode); 58 char *get_node_type(Prom_node *pnode); 59 60 void fill_pci_card_list(Prom_node *pci_instance, 61 Prom_node *pci_card_node, 62 struct io_card *pci_card, 63 struct io_card **pci_card_list, 64 char **pci_slot_name_arr); 65 66 static Prom_node *next_pci_card(Prom_node *curr_card, int *is_bridge, 67 int is_pcidev, Prom_node *curr_bridge, 68 Prom_node * parent_bridge, Prom_node *pci); 69 70 71 #define LNECK_MAX_SLOTS_PER_IO_BD 9 72 #define LNECK_CLK_FREQ_TO_MHZ(x) (((x) + 500000) / 1000000) 73 74 /* This is stuff to get the HW Revisions stuff to work */ 75 76 #define LNECK_SAFARI_ID_MASK 0x1F /* 5 bits */ 77 #define LNECK_NODE_MASK 0x1F /* 5 bits */ 78 #define LNECK_PORTID_NODE_SHIFT 5 79 #define LNECK_MIN_CPU_SAFARI_ID 0 /* 0x00 */ 80 #define LNECK_MAX_CPU_SAFARI_ID 23 /* 0x17 */ 81 #define LNECK_MIN_IO_SAFARI_ID 24 /* 0x18 */ 82 #define LNECK_MAX_IO_SAFARI_ID 31 /* 0x1F */ 83 #define NUM_MBANKS_PER_MC 4 84 85 /* 86 * LNECK_PORTID_TO_SAFARI_ID 87 * 88 * Calculates the Safari Agent ID from the portid. 89 */ 90 #define LNECK_PORTID_TO_SAFARI_ID(portid) ((portid) & LNECK_SAFARI_ID_MASK) 91 92 /* 93 * LNECK_PORTID_IS_CPU_TYPE 94 * 95 * If the portid associated with a CPU board is passed in, TRUE is returned, 96 * otherwise FALSE. 97 */ 98 #define LNECK_PORTID_IS_CPU_TYPE(portid) \ 99 (((((portid) & LNECK_SAFARI_ID_MASK) >= LNECK_MIN_CPU_SAFARI_ID) && \ 100 (((portid) & LNECK_SAFARI_ID_MASK) <= LNECK_MAX_CPU_SAFARI_ID)) ? \ 101 TRUE: FALSE) 102 103 /* 104 * LNECK_PORTID_TO_NODEID 105 * 106 * Calculates the SSM NodeID from the portid 107 */ 108 #define LNECK_PORTID_TO_NODEID(portid) (((portid) >> LNECK_PORTID_NODE_SHIFT) \ 109 & LNECK_NODE_MASK) 110 111 /* 112 * LNECK_CPU_BD_PORTID_TO_BD_NUM 113 * 114 * If the portid associated with a CPU board is passed in, the board number 115 * associated with this portid is returned, otherwise -1. 116 */ 117 #define LNECK_CPU_BD_PORTID_TO_BD_NUM(portid) \ 118 ((LNECK_PORTID_IS_CPU_TYPE(portid)) ? \ 119 (((portid) & LNECK_SAFARI_ID_MASK) / 4) : (-1)) 120 121 /* 122 * LNECK_PORTID_IS_IO_TYPE 123 * 124 * If the portid associated with an IO board is passed in, TRUE is returned, 125 * otherwise FALSE. 126 */ 127 #define LNECK_PORTID_IS_IO_TYPE(portid) \ 128 (((((portid) & LNECK_SAFARI_ID_MASK) >= LNECK_MIN_IO_SAFARI_ID) && \ 129 (((portid) & LNECK_SAFARI_ID_MASK) <= LNECK_MAX_IO_SAFARI_ID)) ? \ 130 TRUE: FALSE) 131 132 /* 133 * LNECK_IO_BD_PORTID_TO_BD_NUM 134 * 135 * If the portid associated with an IO board is passed in, the board number 136 * associated with this portid is returned, otherwise -1. 137 */ 138 #define LNECK_IO_BD_PORTID_TO_BD_NUM(portid) \ 139 (LNECK_PORTID_IS_IO_TYPE(portid) ? \ 140 (((((portid) & LNECK_SAFARI_ID_MASK) - 24) / 2) + 6) : (-1)) 141 142 /* 143 * LNECK_PORTID_TO_BOARD_NUM 144 * 145 * If a valid portid is passed in, this macro returns the board number 146 * associated with it, otherwise it returns -1. 147 */ 148 #define LNECK_PORTID_TO_BOARD_NUM(portid) \ 149 ((LNECK_PORTID_IS_CPU_TYPE(portid)) ? \ 150 (LNECK_CPU_BD_PORTID_TO_BD_NUM(portid)) : \ 151 ((LNECK_PORTID_IS_IO_TYPE(portid)) ? \ 152 LNECK_IO_BD_PORTID_TO_BD_NUM(portid) : (-1))) 153 154 155 /* 156 * Start from the current node and return the next node besides 157 * the current one which has the requested model property. 158 */ 159 static Prom_node * 160 dev_next_node_by_compat(Prom_node *root, char *compat) 161 { 162 Prom_node *node; 163 164 if (root == NULL) 165 return (NULL); 166 167 /* look at your children first */ 168 if ((node = dev_find_node_by_compat(root->child, compat)) != NULL) 169 return (node); 170 171 /* now look at your siblings */ 172 if ((node = dev_find_node_by_compat(root->sibling, compat)) != NULL) 173 return (node); 174 175 return (NULL); /* not found */ 176 } 177 178 /* 179 * Do a depth-first walk of a device tree and 180 * return the first node with the matching model. 181 */ 182 static Prom_node * 183 dev_find_node_by_compat(Prom_node *root, char *compat) 184 { 185 Prom_node *node; 186 char *compatible; 187 char *name; 188 189 if (root == NULL) 190 return (NULL); 191 192 if (compat == NULL) 193 return (NULL); 194 195 name = get_node_name(root); 196 if (name == NULL) 197 name = ""; 198 199 compatible = (char *)get_prop_val(find_prop(root, "compatible")); 200 201 if (compatible == NULL) 202 return (NULL); 203 204 if ((strcmp(name, "pci") == 0) && (compatible != NULL) && 205 (strcmp(compatible, compat) == 0)) { 206 return (root); /* found a match */ 207 } 208 209 /* look at your children first */ 210 if ((node = dev_find_node_by_compat(root->child, compat)) != NULL) 211 return (node); 212 213 /* now look at your siblings */ 214 if ((node = dev_find_node_by_compat(root->sibling, compat)) != NULL) 215 return (node); 216 217 return (NULL); /* not found */ 218 } 219 220 int32_t 221 find_child_device(picl_nodehdl_t parent, char *child_name, 222 picl_nodehdl_t *child) 223 { 224 int32_t err; 225 char name[PICL_PROPNAMELEN_MAX]; 226 227 err = picl_get_propval_by_name(parent, PICL_PROP_CHILD, &(*child), 228 sizeof (picl_nodehdl_t)); 229 switch (err) { 230 case PICL_SUCCESS: 231 break; 232 case PICL_PROPNOTFOUND: 233 err = PICL_INVALIDHANDLE; 234 return (err); 235 default: 236 #ifdef WORKFILE_DEBUG 237 log_printf(dgettext(TEXT_DOMAIN, 238 "Failed picl_get_propval_by_name with %s\n"), 239 picl_strerror(err)); 240 #endif 241 return (err); 242 } 243 244 err = picl_get_propval_by_name(*child, PICL_PROP_NAME, name, 245 PICL_PROPNAMELEN_MAX); 246 247 #ifdef WORKFILE_DEBUG 248 if (err != PICL_SUCCESS) { 249 log_printf(dgettext(TEXT_DOMAIN, 250 "failed the get name for root\n")); 251 log_printf(dgettext(TEXT_DOMAIN, "%s\n"), picl_strerror(err)); 252 } 253 #endif 254 255 if (strcmp(name, child_name) == 0) 256 return (err); 257 258 while (err != PICL_PROPNOTFOUND) { 259 #ifdef WORKFILE_DEBUG 260 log_printf(dgettext(TEXT_DOMAIN, "child name is %s\n"), name); 261 #endif 262 err = picl_get_propval_by_name(*child, PICL_PROP_PEER, 263 &(*child), sizeof (picl_nodehdl_t)); 264 switch (err) { 265 case PICL_SUCCESS: 266 err = picl_get_propval_by_name(*child, PICL_PROP_NAME, 267 name, PICL_PROPNAMELEN_MAX); 268 if (strcmp(name, child_name) == 0) 269 return (err); 270 break; 271 case PICL_PROPNOTFOUND: 272 break; 273 default: 274 #ifdef WORKFILE_DEBUG 275 log_printf(dgettext(TEXT_DOMAIN, 276 "Failed picl_get_propval_by_name with %s\n"), 277 picl_strerror(err)); 278 #endif 279 return (err); 280 } 281 } 282 err = PICL_INVALIDHANDLE; 283 return (err); 284 } 285 286 int32_t 287 fill_device_from_id(picl_nodehdl_t device_id, char *assoc_id, 288 picl_nodehdl_t *device) 289 { 290 int32_t err; 291 picl_prophdl_t tbl_hdl; 292 picl_prophdl_t reference_property; 293 294 err = picl_get_propval_by_name(device_id, assoc_id, &tbl_hdl, 295 sizeof (picl_prophdl_t)); 296 if (err != PICL_SUCCESS) { 297 #ifdef WORKFILE_DEBUG 298 if (err != PICL_INVALIDHANDLE) { 299 log_printf(dgettext(TEXT_DOMAIN, 300 "fill_device_from_id failure in " 301 "picl_get_propval_by_name err is %s\n"), 302 picl_strerror(err)); 303 } 304 #endif 305 return (err); 306 } 307 308 err = picl_get_next_by_row(tbl_hdl, &reference_property); 309 if (err != PICL_SUCCESS) { 310 #ifdef WORKFILE_DEBUG 311 log_printf(dgettext(TEXT_DOMAIN, 312 "fill_device_from_id failure in picl_get_next_by_row" 313 " err is %s\n"), picl_strerror(err)); 314 #endif 315 return (err); 316 } 317 318 /* get node associated with reference property */ 319 err = picl_get_propval(reference_property, &(*device), 320 sizeof (picl_nodehdl_t)); 321 322 #ifdef WORKFILE_DEBUG 323 if (err != 0) { 324 log_printf(dgettext(TEXT_DOMAIN, 325 "fill_device_from_id failure in picl_get_propval" 326 " err is %s\n"), picl_strerror(err)); 327 } 328 #endif 329 330 return (err); 331 } 332 333 int32_t 334 fill_device_array_from_id(picl_nodehdl_t device_id, char *assoc_id, 335 int32_t *number_of_devices, picl_nodehdl_t *device_array[]) 336 { 337 int32_t err; 338 int i; 339 picl_prophdl_t tbl_hdl; 340 picl_prophdl_t entry; 341 int devs = 0; 342 343 err = picl_get_propval_by_name(device_id, assoc_id, &tbl_hdl, 344 sizeof (picl_prophdl_t)); 345 if ((err != PICL_SUCCESS) && (err != PICL_INVALIDHANDLE)) { 346 #ifdef WORKFILE_DEBUG 347 log_printf(dgettext(TEXT_DOMAIN, 348 "fill_device_array_from_id failure in " 349 "picl_get_propval_by_name err is %s\n"), picl_strerror(err)); 350 #endif 351 return (err); 352 } 353 354 entry = tbl_hdl; 355 while (picl_get_next_by_row(entry, &entry) == 0) 356 ++devs; 357 358 *device_array = calloc((devs), sizeof (picl_nodehdl_t)); 359 if (*device_array == NULL) { 360 361 #ifdef WORFILE_DEBUG 362 log_printf(dgettext(TEXT_DOMAIN, 363 "fill_device_array_from_id failure getting memory" 364 " for array\n")); 365 #endif 366 return (PICL_FAILURE); 367 } 368 369 entry = tbl_hdl; 370 for (i = 0; i < devs; i++) { 371 err = picl_get_next_by_row(entry, &entry); 372 if (err != 0) { 373 #ifdef WORKFILE_DEBUG 374 log_printf(dgettext(TEXT_DOMAIN, 375 "fill_device_array_from_id failure in " 376 "picl_get_next_by_row err is %s\n"), 377 picl_strerror(err)); 378 #endif 379 return (err); 380 } 381 382 /* get node associated with reference property */ 383 err = picl_get_propval(entry, &((*device_array)[i]), 384 sizeof (picl_nodehdl_t)); 385 if (err != 0) { 386 #ifdef WORKFILE_DEBUG 387 log_printf(dgettext(TEXT_DOMAIN, 388 "fill_device_array_from_id failure in " 389 "picl_get_propval err is %s\n"), picl_strerror(err)); 390 #endif 391 392 return (err); 393 } 394 } 395 *number_of_devices = devs; 396 return (err); 397 } 398 399 /* 400 * Add a board to the system list in order (sorted by board#). 401 * Initialize all pointer fields to NULL. 402 */ 403 static Board_node * 404 littleneck_insert_board(Sys_tree *root, int board) 405 { 406 Board_node *bnode; 407 Board_node *temp = root->bd_list; 408 409 if ((bnode = (Board_node *) malloc(sizeof (Board_node))) == NULL) { 410 perror("malloc"); 411 exit(1); 412 } 413 414 bnode->nodes = NULL; 415 bnode->next = NULL; 416 bnode->board_num = board; 417 418 bnode->board_type = UNKNOWN_BOARD; 419 420 if (temp == NULL) 421 root->bd_list = bnode; 422 423 else if (temp->board_num > board) { 424 bnode->next = temp; 425 root->bd_list = bnode; 426 427 } else { 428 while ((temp->next != NULL) && (board > temp->next->board_num)) 429 temp = temp->next; 430 431 bnode->next = temp->next; 432 temp->next = bnode; 433 } 434 root->board_cnt++; 435 436 return (bnode); 437 } 438 439 /* 440 * Find the requested board struct in the system device tree. 441 * 442 * This function overrides the functionality of the generic find_board() 443 * function in libprtdiag, but since we need to pass another parameter, 444 * we cannot simply overlay the symbol table. 445 */ 446 static Board_node * 447 littleneck_find_board(Sys_tree *root, int board) 448 { 449 Board_node *bnode = root->bd_list; 450 451 while ((bnode != NULL) && (board != bnode->board_num)) { 452 bnode = bnode->next; 453 } 454 return (bnode); 455 } 456 457 /* 458 * add_node 459 * 460 * This function adds a board node to the board structure where that 461 * that node's physical component lives. 462 */ 463 void 464 add_node(Sys_tree *root, Prom_node *pnode) 465 { 466 int board = -1; 467 int portid = -1; 468 469 void *value = NULL; 470 Board_node *bnode = NULL; 471 Prom_node *p = NULL; 472 473 /* Get the board number of this board from the portid prop */ 474 value = get_prop_val(find_prop(pnode, "portid")); 475 if (value != NULL) { 476 portid = *(int *)value; 477 } 478 479 board = LNECK_PORTID_TO_BOARD_NUM(portid); 480 481 /* find the board node with the same board number */ 482 if ((bnode = littleneck_find_board(root, board)) == NULL) { 483 bnode = littleneck_insert_board(root, board); 484 } 485 486 /* now attach this prom node to the board list */ 487 /* Insert this node at the end of the list */ 488 pnode->sibling = NULL; 489 if (bnode->nodes == NULL) 490 bnode->nodes = pnode; 491 else { 492 p = bnode->nodes; 493 while (p->sibling != NULL) 494 p = p->sibling; 495 p->sibling = pnode; 496 } 497 } 498 499 /* 500 * This function provides formatting of the memory config 501 * information that get_us3_mem_regs() and display_us3_banks() code has 502 * gathered. It overrides the generic print_us3_memory_line() code 503 * which prints an error message. 504 */ 505 void 506 print_us3_memory_line(int portid, int bank_id, uint64_t bank_size, 507 char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id) 508 { 509 int mcid; 510 char board_id[2]; 511 board_id[0] = 'A'; /* it will usually be, A, there's only one mc! */ 512 board_id[1] = 'B'; /* redundant. */ 513 mcid = LNECK_PORTID_TO_SAFARI_ID(portid); 514 515 log_printf(dgettext(TEXT_DOMAIN, 516 "\n C%-1c %2d %2d %4lldMB %11-s %4lldMB " 517 " %2d-way %d"), 518 board_id[portid], mcid, (bank_id % 4), bank_size, 519 bank_status, dimm_size, intlv, seg_id, 0); 520 } 521 522 /* 523 * We call do_devinfo() in order to use the libdevinfo device tree 524 * instead of OBP's device tree. 525 */ 526 int 527 do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag) 528 { 529 return (do_devinfo(syserrlog, pgname, log_flag, prt_flag)); 530 } 531 532 /* 533 * return the property value for the Prop 534 * passed in. (When using libdevinfo) 535 */ 536 void * 537 get_prop_val(Prop *prop) 538 { 539 if (prop == NULL) 540 return (NULL); 541 542 return ((void *)(prop->value.val_ptr)); 543 } 544 545 /* 546 * Search a Prom node and retrieve the property with the correct 547 * name. (When using libdevinfo) 548 */ 549 Prop * 550 find_prop(Prom_node *pnode, char *name) 551 { 552 Prop *prop; 553 554 if (pnode == NULL) 555 return (NULL); 556 557 if (pnode->props == NULL) 558 return (NULL); 559 560 prop = pnode->props; 561 if (prop == NULL) 562 return (NULL); 563 564 if (prop->name.val_ptr == NULL) 565 return (NULL); 566 567 while ((prop != NULL) && (strcmp((char *)(prop->name.val_ptr), name))) { 568 prop = prop->next; 569 } 570 return (prop); 571 } 572 573 /* 574 * This function searches through the properties of the node passed in 575 * and returns a pointer to the value of the name property. 576 * (When using libdevinfo) 577 */ 578 char * 579 get_node_name(Prom_node *pnode) 580 { 581 Prop *prop; 582 583 if (pnode == NULL) { 584 return (NULL); 585 } 586 587 prop = pnode->props; 588 while (prop != NULL) { 589 if (strcmp("name", (char *)prop->name.val_ptr) == 0) 590 return (prop->value.val_ptr); 591 prop = prop->next; 592 } 593 return (NULL); 594 } 595 596 /* 597 * This function searches through the properties of the node passed in 598 * and returns a pointer to the value of the device_type property. 599 * (When using libdevinfo) 600 */ 601 char * 602 get_node_type(Prom_node *pnode) 603 { 604 Prop *prop; 605 606 if (pnode == NULL) { 607 return (NULL); 608 } 609 610 prop = pnode->props; 611 while (prop != NULL) { 612 if (strcmp("device_type", (char *)prop->name.val_ptr) == 0) 613 return (prop->value.val_ptr); 614 prop = prop->next; 615 } 616 return (NULL); 617 } 618 619 620 /* 621 * Fills in the i/o card list to be displayed later in display_pci(); 622 */ 623 void 624 fill_pci_card_list(Prom_node * pci_instance, Prom_node * pci_card_node, 625 struct io_card *pci_card, 626 struct io_card **pci_card_list, char **slot_name_arr) 627 { 628 Prom_node *pci_bridge_node; 629 Prom_node *pci_parent_bridge; 630 int *int_val; 631 int pci_bridge = FALSE; 632 int pci_bridge_dev_no = -1; 633 int portid; 634 int pci_bus; 635 char buf[MAXSTRLEN]; 636 char *slot_name = NULL; /* info in "slot-names" prop */ 637 char *child_name; 638 char *name; 639 char *type; 640 void *value; 641 642 while (pci_card_node != NULL) { 643 int is_pci = FALSE; 644 type = NULL; 645 name = NULL; 646 /* If it doesn't have a name, skip it */ 647 name = (char *)get_prop_val( 648 find_prop(pci_card_node, "name")); 649 if (name == NULL) { 650 pci_card_node = pci_card_node->sibling; 651 continue; 652 } 653 /* 654 * Get the portid of the schizo that this card 655 * lives under. 656 */ 657 portid = -1; 658 value = get_prop_val(find_prop(pci_instance, "portid")); 659 if (value != NULL) { 660 portid = *(int *)value; 661 } 662 pci_card->schizo_portid = portid; 663 /* 664 * Find out whether this is PCI bus A or B 665 * using the 'reg' property. 666 */ 667 int_val = (int *)get_prop_val(find_prop(pci_instance, "reg")); 668 669 if (int_val != NULL) { 670 int_val++; /* skip over first integer */ 671 pci_bus = ((*int_val) & 0x7f0000); 672 if (pci_bus == 0x600000) 673 pci_card->pci_bus = 'A'; 674 else if (pci_bus == 0x700000) 675 pci_card->pci_bus = 'B'; 676 else 677 pci_card->pci_bus = '-'; 678 } else { 679 pci_card->pci_bus = '-'; 680 } 681 /* 682 * get dev# and func# for this card from the 683 * 'reg' property. 684 */ 685 int_val = (int *)get_prop_val( 686 find_prop(pci_card_node, "reg")); 687 if (int_val != NULL) { 688 pci_card->dev_no = (((*int_val) & 0xF800) >> 11); 689 pci_card->func_no = (((*int_val) & 0x700) >> 8); 690 } else { 691 pci_card->dev_no = -1; 692 pci_card->func_no = -1; 693 } 694 695 /* We only have one slot on bus A */ 696 if ((pci_card->pci_bus == 'A') && (pci_card->dev_no != 1) && 697 !pci_bridge) { 698 pci_card_node = pci_card_node->sibling; 699 continue; 700 } 701 if ((pci_card->pci_bus == 'B') && (pci_card->dev_no > 4)) { 702 pci_card_node = pci_card_node->sibling; 703 continue; 704 } 705 706 type = (char *)get_prop_val( 707 find_prop(pci_card_node, "device_type")); 708 /* 709 * If this is a pci-bridge, then store its dev# 710 * as its children nodes need this to get their slot#. 711 * We set the pci_bridge flag so that we know we are 712 * looking at a pci-bridge node. This flag gets reset 713 * every time we enter this while loop. 714 */ 715 716 /* 717 * Check for a PCI-PCI Bridge for PCI and cPCI 718 * IO Boards using the name and type properties. 719 */ 720 if ((type != NULL) && (strncmp(name, "pci", 3) == 0) && 721 (strcmp(type, "pci") == 0)) { 722 pci_bridge_node = pci_card_node; 723 is_pci = TRUE; 724 if (!pci_bridge) { 725 pci_bridge_dev_no = pci_card->dev_no; 726 pci_parent_bridge = pci_bridge_node; 727 pci_bridge = TRUE; 728 } 729 } 730 731 /* 732 * Get slot-names property from slot_names_arr. 733 * If we are the child of a pci_bridge we use the 734 * dev# of the pci_bridge as an index to get 735 * the slot number. We know that we are a child of 736 * a pci-bridge if our parent is the same as the last 737 * pci_bridge node found above. 738 */ 739 if (pci_card->dev_no != -1) { 740 /* 741 * We compare this cards parent node with the 742 * pci_bridge_node to see if it's a child. 743 */ 744 if (pci_card_node->parent != pci_instance && 745 pci_bridge) { 746 /* use dev_no of pci_bridge */ 747 slot_name = 748 slot_name_arr[pci_bridge_dev_no -1]; 749 } else { 750 slot_name = 751 slot_name_arr[pci_card->dev_no-1]; 752 } 753 if (slot_name != NULL && 754 strlen(slot_name) != 0) { 755 /* Slot num is last char in string */ 756 (void) snprintf(pci_card->slot_str, MAXSTRLEN, 757 "%c", slot_name[strlen(slot_name) - 1]); 758 } else { 759 (void) snprintf(pci_card->slot_str, MAXSTRLEN, 760 "-"); 761 } 762 763 } else { 764 (void) snprintf(pci_card->slot_str, MAXSTRLEN, 765 "%c", '-'); 766 } 767 768 /* 769 * Check for failed status. 770 */ 771 if (node_failed(pci_card_node)) 772 strcpy(pci_card->status, "fail"); 773 else 774 strcpy(pci_card->status, "ok"); 775 776 /* Get the model of this pci_card */ 777 value = get_prop_val(find_prop(pci_card_node, "model")); 778 if (value == NULL) 779 pci_card->model[0] = '\0'; 780 else { 781 (void) snprintf(pci_card->model, MAXSTRLEN, "%s", 782 (char *)value); 783 /* Skip sgsbbc nodes, they are not cards */ 784 if (strcmp(pci_card->model, "SUNW,sgsbbc") == 0) { 785 pci_card_node = pci_card_node->sibling; 786 continue; 787 } 788 } 789 /* 790 * The card may have a "clock-frequency" but we 791 * are not interested in that. Instead we get the 792 * "clock-frequency" of the PCI Bus that the card 793 * resides on. PCI-A can operate at 33Mhz or 66Mhz 794 * depending on what card is plugged into the Bus. 795 * PCI-B always operates at 33Mhz. 796 */ 797 int_val = get_prop_val(find_prop(pci_instance, 798 "clock-frequency")); 799 if (int_val != NULL) { 800 pci_card->freq = LNECK_CLK_FREQ_TO_MHZ(*int_val); 801 } else { 802 pci_card->freq = -1; 803 } 804 805 /* 806 * Figure out how we want to display the name 807 */ 808 value = get_prop_val(find_prop(pci_card_node, 809 "compatible")); 810 if (value != NULL) { 811 /* use 'name'-'compatible' */ 812 (void) snprintf(buf, MAXSTRLEN, "%s-%s", name, 813 (char *)value); 814 } else { 815 /* just use 'name' */ 816 (void) snprintf(buf, MAXSTRLEN, "%s", name); 817 } 818 name = buf; 819 820 /* 821 * If this node has children, add the device_type 822 * of the child to the name value of this pci_card-> 823 */ 824 child_name = (char *)get_node_name(pci_card_node->child); 825 if ((pci_card_node->child != NULL) && 826 (child_name != NULL)) { 827 value = get_prop_val(find_prop(pci_card_node->child, 828 "device_type")); 829 if (value != NULL) { 830 /* add device_type of child to name */ 831 (void) snprintf(pci_card->name, MAXSTRLEN, 832 "%s/%s (%s)", 833 name, child_name, 834 (char *)value); 835 } else { 836 /* just add childs name */ 837 (void) snprintf(pci_card->name, MAXSTRLEN, 838 "%s/%s", name, 839 child_name); 840 } 841 } else { 842 (void) snprintf(pci_card->name, MAXSTRLEN, 843 "%s", (char *)name); 844 } 845 846 /* 847 * If this is a pci-bridge, then add the word 848 * 'pci-bridge' to its model. If we can't find 849 * a model, then we just describe what the device 850 * is based on some properties. 851 */ 852 if (pci_bridge) { 853 if (strlen(pci_card->model) == 0) { 854 if (pci_card_node->parent == pci_bridge_node) 855 (void) snprintf(pci_card->model, MAXSTRLEN, 856 "%s", "device on pci-bridge"); 857 else if (pci_card_node->parent 858 == pci_parent_bridge) 859 (void) snprintf(pci_card->model, MAXSTRLEN, 860 "%s", "pci-bridge/pci-bridge"); 861 else 862 (void) snprintf(pci_card->model, MAXSTRLEN, 863 "%s", "PCI-BRIDGE"); 864 } 865 else 866 (void) snprintf(pci_card->model, MAXSTRLEN, 867 "%s/pci-bridge", pci_card->model); 868 } 869 /* insert this pci_card in the list to be displayed later */ 870 871 *pci_card_list = insert_io_card(*pci_card_list, pci_card); 872 873 /* 874 * If we are dealing with a pci-bridge, we need to move 875 * down to the children of this bridge if there are any. 876 * 877 * If we are not, we are either dealing with a regular 878 * card (in which case we move onto the sibling of this 879 * card) or we are dealing with a child of a pci-bridge 880 * (in which case we move onto the child's siblings or 881 * if there are no more siblings for this child, we 882 * move onto the parents siblings). 883 */ 884 pci_card_node = next_pci_card(pci_card_node, &pci_bridge, 885 is_pci, pci_bridge_node, 886 pci_parent_bridge, pci_instance); 887 } /* end-while */ 888 } 889 890 /* 891 * Helper function for fill_pci_card_list(). Indicates which 892 * card node to go to next. 893 * Parameters: 894 * ----------- 895 * Prom_node * curr_card: pointer to the current card node 896 * 897 * int * is_bridge: indicates whether or not the card (is | is on) 898 * a pci bridge 899 * 900 * int is_pcidev: indicates whether or not the current card 901 * is a pci bridge 902 * 903 * Prom_node * curr_bridge: pointer to the current pci bridge. Eg: 904 * curr_card->parent. 905 * 906 * Prom_node * parent_bridge: pointer to the first pci bridge encountered. 907 * we could have nested pci bridges, this would 908 * be the first one. 909 * 910 * Prom_node * pci: pointer to the pci instance that we are attached to. 911 * This would be parent_bridge->parent, or 912 * curr_node->parent, if curr_node is not on a pci bridge. 913 */ 914 static Prom_node * 915 next_pci_card(Prom_node *curr_card, int *is_bridge, int is_pcidev, 916 Prom_node *curr_bridge, Prom_node *parent_bridge, 917 Prom_node *pci) 918 { 919 Prom_node * curr_node = curr_card; 920 if (*is_bridge) { 921 /* 922 * is_pcidev is used to prevent us from following the 923 * children of something like a scsi device. 924 */ 925 if (curr_node->child != NULL && is_pcidev) { 926 curr_node = curr_node->child; 927 } else { 928 curr_node = curr_node->sibling; 929 if (curr_node == NULL) { 930 curr_node = curr_bridge->sibling; 931 while (curr_node == NULL && 932 curr_bridge != parent_bridge && 933 curr_bridge != NULL) { 934 curr_node = 935 curr_bridge->parent->sibling; 936 curr_bridge = curr_bridge->parent; 937 if (curr_node != NULL && 938 curr_node->parent == pci) 939 break; 940 } 941 if (curr_bridge == NULL || 942 curr_node == NULL || 943 curr_node->parent == pci || 944 curr_bridge == parent_bridge || 945 curr_node == parent_bridge) { 946 *is_bridge = FALSE; 947 } 948 } 949 } 950 951 } else { 952 curr_node = curr_node->sibling; 953 } 954 return (curr_node); 955 } 956