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 *
dev_next_node_by_compat(Prom_node * root,char * compat)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 *
dev_find_node_by_compat(Prom_node * root,char * compat)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
find_child_device(picl_nodehdl_t parent,char * child_name,picl_nodehdl_t * child)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
fill_device_from_id(picl_nodehdl_t device_id,char * assoc_id,picl_nodehdl_t * device)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
fill_device_array_from_id(picl_nodehdl_t device_id,char * assoc_id,int32_t * number_of_devices,picl_nodehdl_t * device_array[])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 *
littleneck_insert_board(Sys_tree * root,int board)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 *
littleneck_find_board(Sys_tree * root,int board)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
add_node(Sys_tree * root,Prom_node * pnode)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
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)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
do_prominfo(int syserrlog,char * pgname,int log_flag,int prt_flag)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 *
get_prop_val(Prop * prop)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 *
find_prop(Prom_node * pnode,char * name)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 *
get_node_name(Prom_node * pnode)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 *
get_node_type(Prom_node * pnode)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
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)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 *
next_pci_card(Prom_node * curr_card,int * is_bridge,int is_pcidev,Prom_node * curr_bridge,Prom_node * parent_bridge,Prom_node * pci)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