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