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