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