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