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