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