11708Sstevel /*
21708Sstevel  * CDDL HEADER START
31708Sstevel  *
41708Sstevel  * The contents of this file are subject to the terms of the
5*5019Skd93003  * Common Development and Distribution License (the "License").
6*5019Skd93003  * You may not use this file except in compliance with the License.
71708Sstevel  *
81708Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91708Sstevel  * or http://www.opensolaris.org/os/licensing.
101708Sstevel  * See the License for the specific language governing permissions
111708Sstevel  * and limitations under the License.
121708Sstevel  *
131708Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
141708Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151708Sstevel  * If applicable, add the following below this CDDL HEADER, with the
161708Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
171708Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
181708Sstevel  *
191708Sstevel  * CDDL HEADER END
201708Sstevel  */
211708Sstevel /*
22*5019Skd93003  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
231708Sstevel  * Use is subject to license terms.
241708Sstevel  *
251708Sstevel  * Cherrystone platform-specific functions that aren't platform specific
261708Sstevel  *
271708Sstevel  */
281708Sstevel 
291708Sstevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
301708Sstevel 
31*5019Skd93003 #include <psvc_objects.h>
321708Sstevel #include <libprtdiag.h>
331708Sstevel #include <sys/mc.h>
341708Sstevel 
35*5019Skd93003 /* prtdiag exit codes */
36*5019Skd93003 #define	PD_SUCCESS		0
37*5019Skd93003 #define	PD_SYSTEM_FAILURE	1
38*5019Skd93003 #define	PD_INTERNAL_FAILURE	2
39*5019Skd93003 
40*5019Skd93003 static int exit_code = PD_SUCCESS;
411708Sstevel 
421708Sstevel static Prom_node *dev_next_node_by_compat(Prom_node *root, char *model);
431708Sstevel static Prom_node *dev_find_node_by_compat(Prom_node *root, char *model);
441708Sstevel 
451708Sstevel void	print_us3_memory_line(int portid,
461708Sstevel 				int bank_id,
471708Sstevel 				uint64_t bank_size,
481708Sstevel 				char *bank_status,
491708Sstevel 				uint64_t dimm_size,
501708Sstevel 				uint32_t intlv,
511708Sstevel 				int seg_id);
521708Sstevel 
531708Sstevel void	add_node(Sys_tree *root, Prom_node *pnode);
541708Sstevel int	do_prominfo(int syserrlog,
551708Sstevel 		    char *pgname,
561708Sstevel 		    int log_flag,
571708Sstevel 		    int prt_flag);
581708Sstevel 
591708Sstevel void	*get_prop_val(Prop *prop);
601708Sstevel Prop	*find_prop(Prom_node *pnode, char *name);
611708Sstevel char	*get_node_name(Prom_node *pnode);
621708Sstevel char	*get_node_type(Prom_node *pnode);
631708Sstevel 
641708Sstevel void	fill_pci_card_list(Prom_node *pci_instance,
651708Sstevel 			    Prom_node *pci_card_node,
661708Sstevel 			    struct io_card *pci_card,
671708Sstevel 			    struct io_card **pci_card_list,
681708Sstevel 			    char **pci_slot_name_arr);
691708Sstevel 
701708Sstevel static Prom_node	*next_pci_card(Prom_node *curr_card, int *is_bridge,
711708Sstevel 				int is_pcidev, Prom_node *curr_bridge,
721708Sstevel 				Prom_node * parent_bridge, Prom_node *pci);
731708Sstevel 
741708Sstevel #define	HZ_TO_MHZ(x)	(((x) + 500000) / 1000000)
751708Sstevel 
761708Sstevel /*
771708Sstevel  * Start from the current node and return the next node besides
781708Sstevel  * the current one which has the requested model property.
791708Sstevel  */
801708Sstevel static Prom_node *
dev_next_node_by_compat(Prom_node * root,char * compat)811708Sstevel dev_next_node_by_compat(Prom_node *root, char *compat)
821708Sstevel {
831708Sstevel 	Prom_node *node;
841708Sstevel 
851708Sstevel 	if (root == NULL)
86*5019Skd93003 		return (NULL);
871708Sstevel 
881708Sstevel 	/* look at your children first */
891708Sstevel 	if ((node = dev_find_node_by_compat(root->child, compat)) != NULL)
90*5019Skd93003 		return (node);
911708Sstevel 
921708Sstevel 	/* now look at your siblings */
931708Sstevel 	if ((node = dev_find_node_by_compat(root->sibling, compat)) != NULL)
94*5019Skd93003 		return (node);
951708Sstevel 
961708Sstevel 	return (NULL);  /* not found */
971708Sstevel }
981708Sstevel 
991708Sstevel /*
1001708Sstevel  * Do a depth-first walk of a device tree and
1011708Sstevel  * return the first node with the matching model.
1021708Sstevel  */
1031708Sstevel static Prom_node *
dev_find_node_by_compat(Prom_node * root,char * compat)1041708Sstevel dev_find_node_by_compat(Prom_node *root, char *compat)
1051708Sstevel {
1061708Sstevel 	Prom_node	*node;
1071708Sstevel 	char		*compatible;
1081708Sstevel 	char		*name;
1091708Sstevel 
1101708Sstevel 	if (root == NULL)
1111708Sstevel 		return (NULL);
1121708Sstevel 
1131708Sstevel 	if (compat == NULL)
1141708Sstevel 		return (NULL);
1151708Sstevel 
1161708Sstevel 	name = get_node_name(root);
1171708Sstevel 	if (name == NULL)
1181708Sstevel 		name = "";
1191708Sstevel 
1201708Sstevel 	compatible = (char *)get_prop_val(find_prop(root, "compatible"));
1211708Sstevel 
1221708Sstevel 	if (compatible == NULL)
123*5019Skd93003 		return (NULL);
1241708Sstevel 
1251708Sstevel 	if ((strcmp(name, "pci") == 0) && (compatible != NULL) &&
1261708Sstevel 	    (strcmp(compatible, compat) == 0)) {
1271708Sstevel 		return (root); /* found a match */
1281708Sstevel 	}
1291708Sstevel 
1301708Sstevel 	/* look at your children first */
1311708Sstevel 	if ((node = dev_find_node_by_compat(root->child, compat)) != NULL)
132*5019Skd93003 		return (node);
1331708Sstevel 
1341708Sstevel 	/* now look at your siblings */
1351708Sstevel 	if ((node = dev_find_node_by_compat(root->sibling, compat)) != NULL)
136*5019Skd93003 		return (node);
1371708Sstevel 
1381708Sstevel 	return (NULL);  /* not found */
1391708Sstevel }
1401708Sstevel 
1411708Sstevel int32_t
find_child_device(picl_nodehdl_t parent,char * child_name,picl_nodehdl_t * child)1421708Sstevel find_child_device(picl_nodehdl_t parent, char *child_name,
1431708Sstevel 		picl_nodehdl_t *child)
1441708Sstevel {
1451708Sstevel 	int32_t		err;
1461708Sstevel 	char		name[PICL_PROPNAMELEN_MAX];
1471708Sstevel 
1481708Sstevel 	err = picl_get_propval_by_name(parent, PICL_PROP_CHILD, &(*child),
149*5019Skd93003 	    sizeof (picl_nodehdl_t));
1501708Sstevel 	switch (err) {
1511708Sstevel 	case PICL_SUCCESS:
1521708Sstevel 		break;
1531708Sstevel 	case PICL_PROPNOTFOUND:
1541708Sstevel 		err = PICL_INVALIDHANDLE;
1551708Sstevel 		return (err);
1561708Sstevel 	default:
1571708Sstevel #ifdef WORKFILE_DEBUG
1581708Sstevel 		log_printf(dgettext(TEXT_DOMAIN,
1591708Sstevel 		    "Failed picl_get_propval_by_name with %s\n"),
1601708Sstevel 		    picl_strerror(err));
1611708Sstevel #endif
1621708Sstevel 		return (err);
1631708Sstevel 	}
1641708Sstevel 
1651708Sstevel 	err = picl_get_propval_by_name(*child, PICL_PROP_NAME, name,
1661708Sstevel 	    PICL_PROPNAMELEN_MAX);
1671708Sstevel 
1681708Sstevel #ifdef WORKFILE_DEBUG
1691708Sstevel 	if (err != PICL_SUCCESS) {
1701708Sstevel 		log_printf(dgettext(TEXT_DOMAIN,
1711708Sstevel 		    "failed the get name for root\n"));
1721708Sstevel 		log_printf(dgettext(TEXT_DOMAIN, "%s\n"), picl_strerror(err));
1731708Sstevel 	}
1741708Sstevel #endif
1751708Sstevel 
1761708Sstevel 	if (strcmp(name, child_name) == 0)
1771708Sstevel 		return (err);
1781708Sstevel 
1791708Sstevel 	while (err != PICL_PROPNOTFOUND) {
1801708Sstevel #ifdef WORKFILE_DEBUG
1811708Sstevel 		log_printf(dgettext(TEXT_DOMAIN, "child name is %s\n"), name);
1821708Sstevel #endif
1831708Sstevel 		err = picl_get_propval_by_name(*child, PICL_PROP_PEER,
184*5019Skd93003 		    &(*child), sizeof (picl_nodehdl_t));
1851708Sstevel 		switch (err) {
1861708Sstevel 		case PICL_SUCCESS:
1871708Sstevel 			err = picl_get_propval_by_name(*child, PICL_PROP_NAME,
1881708Sstevel 			    name, PICL_PROPNAMELEN_MAX);
1891708Sstevel 			if (strcmp(name, child_name) == 0)
1901708Sstevel 				return (err);
1911708Sstevel 			break;
1921708Sstevel 		case PICL_PROPNOTFOUND:
1931708Sstevel 			break;
1941708Sstevel 		default:
1951708Sstevel #ifdef WORKFILE_DEBUG
1961708Sstevel 			log_printf(dgettext(TEXT_DOMAIN,
1971708Sstevel 			    "Failed picl_get_propval_by_name with %s\n"),
1981708Sstevel 			    picl_strerror(err));
1991708Sstevel #endif
2001708Sstevel 			return (err);
2011708Sstevel 		}
2021708Sstevel 	}
2031708Sstevel 	err = PICL_INVALIDHANDLE;
2041708Sstevel 	return (err);
2051708Sstevel }
2061708Sstevel 
2071708Sstevel int32_t
fill_device_from_id(picl_nodehdl_t device_id,char * assoc_id,picl_nodehdl_t * device)2081708Sstevel fill_device_from_id(picl_nodehdl_t device_id, char *assoc_id,
2091708Sstevel 		picl_nodehdl_t *device)
2101708Sstevel {
2111708Sstevel 	int32_t		err;
2121708Sstevel 	picl_prophdl_t	tbl_hdl;
2131708Sstevel 	picl_prophdl_t	reference_property;
2141708Sstevel 
2151708Sstevel 	err = picl_get_propval_by_name(device_id, assoc_id, &tbl_hdl,
216*5019Skd93003 	    sizeof (picl_prophdl_t));
2171708Sstevel 	if (err != PICL_SUCCESS) {
2181708Sstevel #ifdef WORKFILE_DEBUG
2191708Sstevel 		if (err != PICL_INVALIDHANDLE) {
2201708Sstevel 			log_printf(dgettext(TEXT_DOMAIN,
2211708Sstevel 			"fill_device_from_id failure in "
2221708Sstevel 			"picl_get_propval_by_name err is %s\n"),
2231708Sstevel 			    picl_strerror(err));
2241708Sstevel 		}
2251708Sstevel #endif
2261708Sstevel 		return (err);
2271708Sstevel 	}
2281708Sstevel 
2291708Sstevel 	err = picl_get_next_by_row(tbl_hdl, &reference_property);
2301708Sstevel 	if (err != PICL_SUCCESS) {
2311708Sstevel #ifdef WORKFILE_DEBUG
2321708Sstevel 		log_printf(dgettext(TEXT_DOMAIN,
2331708Sstevel 		    "fill_device_from_id failure in picl_get_next_by_row"
2341708Sstevel 		    " err is %s\n"), picl_strerror(err));
2351708Sstevel #endif
2361708Sstevel 		return (err);
2371708Sstevel 	}
2381708Sstevel 
2391708Sstevel 	/* get node associated with reference property */
2401708Sstevel 	err = picl_get_propval(reference_property, &(*device),
241*5019Skd93003 	    sizeof (picl_nodehdl_t));
2421708Sstevel 
2431708Sstevel #ifdef WORKFILE_DEBUG
2441708Sstevel 	if (err != 0) {
2451708Sstevel 		log_printf(dgettext(TEXT_DOMAIN,
2461708Sstevel 		"fill_device_from_id failure in picl_get_propval"
2471708Sstevel 		" err is %s\n"), picl_strerror(err));
2481708Sstevel 	}
2491708Sstevel #endif
2501708Sstevel 
2511708Sstevel 	return (err);
2521708Sstevel }
2531708Sstevel 
2541708Sstevel 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[])2551708Sstevel fill_device_array_from_id(picl_nodehdl_t device_id, char *assoc_id,
2561708Sstevel 	int32_t *number_of_devices, picl_nodehdl_t *device_array[])
2571708Sstevel {
2581708Sstevel 	int32_t		err;
2591708Sstevel 	int		i;
2601708Sstevel 	picl_prophdl_t	tbl_hdl;
2611708Sstevel 	picl_prophdl_t	entry;
2621708Sstevel 	int		devs = 0;
2631708Sstevel 
2641708Sstevel 	err = picl_get_propval_by_name(device_id, assoc_id, &tbl_hdl,
265*5019Skd93003 	    sizeof (picl_prophdl_t));
2661708Sstevel 	if ((err != PICL_SUCCESS) && (err != PICL_INVALIDHANDLE)) {
2671708Sstevel #ifdef WORKFILE_DEBUG
268*5019Skd93003 		log_printf(dgettext(TEXT_DOMAIN,
269*5019Skd93003 		    "fill_device_array_from_id failure in "
270*5019Skd93003 		    "picl_get_propval_by_name err is %s\n"),
271*5019Skd93003 		    picl_strerror(err));
2721708Sstevel #endif
273*5019Skd93003 		return (err);
2741708Sstevel 	}
2751708Sstevel 
2761708Sstevel 	entry = tbl_hdl;
2771708Sstevel 	while (picl_get_next_by_row(entry, &entry) == 0)
2781708Sstevel 		++devs;
2791708Sstevel 
2801708Sstevel 	*device_array = calloc((devs), sizeof (picl_nodehdl_t));
2811708Sstevel 	if (*device_array == NULL) {
2821708Sstevel 
2831708Sstevel #ifdef WORFILE_DEBUG
2841708Sstevel 		log_printf(dgettext(TEXT_DOMAIN,
2851708Sstevel 		"fill_device_array_from_id failure getting memory"
2861708Sstevel 		" for array\n"));
2871708Sstevel #endif
2881708Sstevel 		return (PICL_FAILURE);
2891708Sstevel 	}
2901708Sstevel 
2911708Sstevel 	entry = tbl_hdl;
2921708Sstevel 	for (i = 0; i < devs; i++) {
2931708Sstevel 		err = picl_get_next_by_row(entry, &entry);
2941708Sstevel 		if (err != 0) {
2951708Sstevel #ifdef WORKFILE_DEBUG
2961708Sstevel 			log_printf(dgettext(TEXT_DOMAIN,
2971708Sstevel 			"fill_device_array_from_id failure in "
2981708Sstevel 			"picl_get_next_by_row err is %s\n"),
2991708Sstevel 			    picl_strerror(err));
3001708Sstevel #endif
3011708Sstevel 			return (err);
3021708Sstevel 		}
3031708Sstevel 
3041708Sstevel 		/* get node associated with reference property */
3051708Sstevel 		err = picl_get_propval(entry, &((*device_array)[i]),
306*5019Skd93003 		    sizeof (picl_nodehdl_t));
3071708Sstevel 		if (err != 0) {
3081708Sstevel #ifdef WORKFILE_DEBUG
3091708Sstevel 			log_printf(dgettext(TEXT_DOMAIN,
3101708Sstevel 			"fill_device_array_from_id failure in "
3111708Sstevel 			"picl_get_propval err is %s\n"), picl_strerror(err));
3121708Sstevel #endif
3131708Sstevel 
3141708Sstevel 			return (err);
3151708Sstevel 		}
3161708Sstevel 	}
3171708Sstevel 	*number_of_devices = devs;
3181708Sstevel 	return (err);
3191708Sstevel }
3201708Sstevel 
3211708Sstevel /*
3221708Sstevel  * add_node
3231708Sstevel  *
3241708Sstevel  * This function adds a board node to the board structure where that
3251708Sstevel  * that node's physical component lives.
3261708Sstevel  */
3271708Sstevel void
add_node(Sys_tree * root,Prom_node * pnode)3281708Sstevel add_node(Sys_tree *root, Prom_node *pnode)
3291708Sstevel {
3301708Sstevel 	int	board	= -1;
3311708Sstevel 	int	portid	= -1;
3321708Sstevel 
3331708Sstevel 	void		*value	= NULL;
3341708Sstevel 	Board_node	*bnode	= NULL;
3351708Sstevel 	Prom_node	*p	= NULL;
3361708Sstevel 
3371708Sstevel 	/* Get the board number of this board from the portid prop */
3381708Sstevel 	value = get_prop_val(find_prop(pnode, "portid"));
3391708Sstevel 	if (value != NULL) {
3401708Sstevel 		portid = *(int *)value;
3411708Sstevel 	}
3421708Sstevel 
3431708Sstevel 	board = CHERRYSTONE_GETSLOT(portid);
3441708Sstevel 
3451708Sstevel 	if ((bnode = find_board(root, board)) == NULL) {
3461708Sstevel 		bnode = insert_board(root, board);
3471708Sstevel 	}
3481708Sstevel 
3491708Sstevel 	/* now attach this prom node to the board list */
3501708Sstevel 	/* Insert this node at the end of the list */
3511708Sstevel 	pnode->sibling = NULL;
3521708Sstevel 	if (bnode->nodes == NULL)
3531708Sstevel 		bnode->nodes = pnode;
3541708Sstevel 	else {
3551708Sstevel 		p = bnode->nodes;
3561708Sstevel 		while (p->sibling != NULL)
3571708Sstevel 			p = p->sibling;
3581708Sstevel 		p->sibling = pnode;
3591708Sstevel 	}
3601708Sstevel }
3611708Sstevel 
3621708Sstevel /*
3631708Sstevel  * This function provides formatting of the memory config
3641708Sstevel  * information that get_us3_mem_regs() and display_us3_banks() code has
3651708Sstevel  * gathered. It overrides the generic print_us3_memory_line() code
3661708Sstevel  * which prints an error message.
3671708Sstevel  */
3681708Sstevel 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)3691708Sstevel print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
3701708Sstevel 	char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id)
3711708Sstevel {
3721708Sstevel 	log_printf(dgettext(TEXT_DOMAIN,
373*5019Skd93003 	    "\n %-1c   %2d    %2d      %4lldMB   %11-s  %4lldMB "
374*5019Skd93003 	    "   %2d-way        %d"),
375*5019Skd93003 	    CHERRYSTONE_GETSLOT_LABEL(portid), portid,
376*5019Skd93003 	    (bank_id % 4), bank_size, bank_status, dimm_size,
377*5019Skd93003 	    intlv, seg_id, 0);
3781708Sstevel }
3791708Sstevel 
3801708Sstevel /*
381*5019Skd93003  * We call do_devinfo() in order to use the libdevinfo device tree instead of
382*5019Skd93003  * OBP's device tree. Ignore its return value and use our exit_code instead.
383*5019Skd93003  * Its return value comes from calling error_check() which is not implemented
384*5019Skd93003  * because the device tree does not keep track of the status property for the
385*5019Skd93003  * 480/490. The exit_code we return is set while do_devinfo() calls our local
386*5019Skd93003  * functions to gather/print data. That way we can report both internal and
387*5019Skd93003  * device failures.
3881708Sstevel  */
3891708Sstevel int
do_prominfo(int syserrlog,char * pgname,int log_flag,int prt_flag)3901708Sstevel do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag)
3911708Sstevel {
392*5019Skd93003 	(void) do_devinfo(syserrlog, pgname, log_flag, prt_flag);
393*5019Skd93003 	return (exit_code);
3941708Sstevel }
3951708Sstevel 
3961708Sstevel /*
3971708Sstevel  * return the property value for the Prop
3981708Sstevel  * passed in. (When using libdevinfo)
3991708Sstevel  */
4001708Sstevel void *
get_prop_val(Prop * prop)4011708Sstevel get_prop_val(Prop *prop)
4021708Sstevel {
4031708Sstevel 	if (prop == NULL)
4041708Sstevel 		return (NULL);
4051708Sstevel 
4061708Sstevel 	return ((void *)(prop->value.val_ptr));
4071708Sstevel }
4081708Sstevel 
4091708Sstevel /*
4101708Sstevel  * Search a Prom node and retrieve the property with the correct
4111708Sstevel  * name. (When using libdevinfo)
4121708Sstevel  */
4131708Sstevel Prop *
find_prop(Prom_node * pnode,char * name)4141708Sstevel find_prop(Prom_node *pnode, char *name)
4151708Sstevel {
4161708Sstevel 	Prop *prop;
4171708Sstevel 
4181708Sstevel 	if (pnode  == NULL)
4191708Sstevel 		return (NULL);
4201708Sstevel 
4211708Sstevel 	if (pnode->props == NULL)
4221708Sstevel 		return (NULL);
4231708Sstevel 
4241708Sstevel 	prop = pnode->props;
4251708Sstevel 	if (prop == NULL)
4261708Sstevel 		return (NULL);
4271708Sstevel 
4281708Sstevel 	if (prop->name.val_ptr == NULL)
4291708Sstevel 		return (NULL);
4301708Sstevel 
4311708Sstevel 	while ((prop != NULL) && (strcmp((char *)(prop->name.val_ptr), name))) {
4321708Sstevel 		prop = prop->next;
4331708Sstevel 	}
4341708Sstevel 	return (prop);
4351708Sstevel }
4361708Sstevel 
4371708Sstevel /*
4381708Sstevel  * This function searches through the properties of the node passed in
4391708Sstevel  * and returns a pointer to the value of the name property.
4401708Sstevel  * (When using libdevinfo)
4411708Sstevel  */
4421708Sstevel char *
get_node_name(Prom_node * pnode)4431708Sstevel get_node_name(Prom_node *pnode)
4441708Sstevel {
4451708Sstevel 	Prop *prop;
4461708Sstevel 
4471708Sstevel 	if (pnode == NULL) {
4481708Sstevel 		return (NULL);
4491708Sstevel 	}
4501708Sstevel 
4511708Sstevel 	prop = pnode->props;
4521708Sstevel 	while (prop != NULL) {
4531708Sstevel 		if (strcmp("name", (char *)prop->name.val_ptr) == 0)
4541708Sstevel 			return (prop->value.val_ptr);
4551708Sstevel 		prop = prop->next;
4561708Sstevel 	}
4571708Sstevel 	return (NULL);
4581708Sstevel }
4591708Sstevel 
4601708Sstevel /*
4611708Sstevel  * This function searches through the properties of the node passed in
4621708Sstevel  * and returns a pointer to the value of the device_type property.
4631708Sstevel  * (When using libdevinfo)
4641708Sstevel  */
4651708Sstevel char *
get_node_type(Prom_node * pnode)4661708Sstevel get_node_type(Prom_node *pnode)
4671708Sstevel {
4681708Sstevel 	Prop *prop;
4691708Sstevel 
4701708Sstevel 	if (pnode == NULL) {
4711708Sstevel 		return (NULL);
4721708Sstevel 	}
4731708Sstevel 
4741708Sstevel 	prop = pnode->props;
4751708Sstevel 	while (prop != NULL) {
4761708Sstevel 		if (strcmp("device_type", (char *)prop->name.val_ptr) == 0)
4771708Sstevel 			return (prop->value.val_ptr);
4781708Sstevel 		prop = prop->next;
4791708Sstevel 	}
4801708Sstevel 	return (NULL);
4811708Sstevel }
4821708Sstevel 
4831708Sstevel 
4841708Sstevel /*
4851708Sstevel  * Fills in the i/o card list to be displayed later in display_pci();
4861708Sstevel  */
4871708Sstevel 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)4881708Sstevel fill_pci_card_list(Prom_node * pci_instance, Prom_node * pci_card_node,
4891708Sstevel 			struct io_card *pci_card,
4901708Sstevel 			struct io_card **pci_card_list, char **slot_name_arr)
4911708Sstevel {
4921708Sstevel 	Prom_node	*pci_bridge_node;
4931708Sstevel 	Prom_node	*pci_parent_bridge;
4941708Sstevel 	int		*int_val;
4951708Sstevel 	int		pci_bridge = FALSE;
4961708Sstevel 	int		pci_bridge_dev_no = -1;
4971708Sstevel 	int		portid;
4981708Sstevel 	int		pci_bus;
4991708Sstevel 	char		buf[MAXSTRLEN];
5001708Sstevel 	char		*slot_name = NULL;	/* info in "slot-names" prop */
5011708Sstevel 	char		*child_name;
5021708Sstevel 	char		*name;
5031708Sstevel 	char		*type;
5041708Sstevel 	void		*value;
5051708Sstevel 
5061708Sstevel 	while (pci_card_node != NULL) {
5071708Sstevel 		int is_pci = FALSE;
5081708Sstevel 		type = NULL;
5091708Sstevel 		name = NULL;
5101708Sstevel 		/* If it doesn't have a name, skip it */
5111708Sstevel 		name = (char *)get_prop_val(
512*5019Skd93003 		    find_prop(pci_card_node, "name"));
5131708Sstevel 		if (name == NULL) {
5141708Sstevel 			pci_card_node = pci_card_node->sibling;
5151708Sstevel 			continue;
5161708Sstevel 		}
5171708Sstevel 
5181708Sstevel 		/*
5191708Sstevel 		 * Get the portid of the schizo that this card
5201708Sstevel 		 * lives under.
5211708Sstevel 		 */
5221708Sstevel 		portid = -1;
5231708Sstevel 		value = get_prop_val(find_prop(pci_instance, "portid"));
5241708Sstevel 		if (value != NULL) {
5251708Sstevel 			portid = *(int *)value;
5261708Sstevel 		}
5271708Sstevel 		pci_card->schizo_portid = portid;
5281708Sstevel 		if (pci_card->schizo_portid != 8) {
5291708Sstevel 			/*
5301708Sstevel 			 * Schizo0 (portid 8) has no slots on Cherrystone.
5311708Sstevel 			 * So if that's who we're looking at, we're done.
5321708Sstevel 			 */
5331708Sstevel 			return;
5341708Sstevel 		}
5351708Sstevel 
5361708Sstevel 		/*
5371708Sstevel 		 * Find out whether this is PCI bus A or B
5381708Sstevel 		 * using the 'reg' property.
5391708Sstevel 		 */
5401708Sstevel 		int_val = (int *)get_prop_val(find_prop(pci_instance, "reg"));
5411708Sstevel 
5421708Sstevel 		if (int_val != NULL) {
5431708Sstevel 			int_val++; /* skip over first integer */
5441708Sstevel 			pci_bus = ((*int_val) & 0x7f0000);
5451708Sstevel 			if (pci_bus == 0x600000)
5461708Sstevel 				pci_card->pci_bus = 'A';
5471708Sstevel 			else if (pci_bus == 0x700000)
5481708Sstevel 				pci_card->pci_bus = 'B';
5491708Sstevel 			else {
5501708Sstevel 				assert(0); /* should never happen */
5511708Sstevel 				pci_card->pci_bus = '-';
5521708Sstevel 			}
5531708Sstevel 		} else {
5541708Sstevel 			assert(0); /* should never happen */
5551708Sstevel 			pci_card->pci_bus = '-';
5561708Sstevel 		}
5571708Sstevel 
5581708Sstevel 		/*
5591708Sstevel 		 * get dev# and func# for this card from the
5601708Sstevel 		 * 'reg' property.
5611708Sstevel 		 */
5621708Sstevel 		int_val = (int *)get_prop_val(
563*5019Skd93003 		    find_prop(pci_card_node, "reg"));
5641708Sstevel 		if (int_val != NULL) {
5651708Sstevel 			pci_card->dev_no = (((*int_val) & 0xF800) >> 11);
5661708Sstevel 			pci_card->func_no = (((*int_val) & 0x700) >> 8);
5671708Sstevel 		} else {
5681708Sstevel 			pci_card->dev_no = -1;
5691708Sstevel 			pci_card->func_no = -1;
5701708Sstevel 		}
5711708Sstevel 
5721708Sstevel 		switch (pci_card->pci_bus) {
5731708Sstevel 		case 'A':
5741708Sstevel 			if ((pci_card->dev_no < 1 || pci_card->dev_no > 2) &&
575*5019Skd93003 			    (!pci_bridge)) {
5761708Sstevel 				pci_card_node = pci_card_node->sibling;
5771708Sstevel 				continue;
5781708Sstevel 			}
5791708Sstevel 			break;
5801708Sstevel 		case 'B':
5811708Sstevel 			if ((pci_card->dev_no < 2 || pci_card->dev_no > 5) &&
582*5019Skd93003 			    (!pci_bridge)) {
5831708Sstevel 				pci_card_node = pci_card_node->sibling;
5841708Sstevel 				continue;
5851708Sstevel 			}
5861708Sstevel 			break;
5871708Sstevel 		default:
5881708Sstevel 			pci_card_node = pci_card_node->sibling;
5891708Sstevel 			continue;
5901708Sstevel 		}
5911708Sstevel 
5921708Sstevel 		type = (char *)get_prop_val(
593*5019Skd93003 		    find_prop(pci_card_node, "device_type"));
5941708Sstevel 		/*
5951708Sstevel 		 * If this is a pci-bridge, then store its dev#
5961708Sstevel 		 * as its children nodes need this to get their slot#.
5971708Sstevel 		 * We set the pci_bridge flag so that we know we are
5981708Sstevel 		 * looking at a pci-bridge node. This flag gets reset
5991708Sstevel 		 * every time we enter this while loop.
6001708Sstevel 		 */
6011708Sstevel 
6021708Sstevel 		/*
6031708Sstevel 		 * Check for a PCI-PCI Bridge for PCI and cPCI
6041708Sstevel 		 * IO Boards using the name and type properties.
6051708Sstevel 		 */
6061708Sstevel 		if ((type != NULL) && (strncmp(name, "pci", 3) == 0) &&
6071708Sstevel 		    (strcmp(type, "pci") == 0)) {
6081708Sstevel 			pci_bridge_node = pci_card_node;
6091708Sstevel 			is_pci = TRUE;
6101708Sstevel 			if (!pci_bridge) {
6111708Sstevel 				pci_bridge_dev_no = pci_card->dev_no;
6121708Sstevel 				pci_parent_bridge = pci_bridge_node;
6131708Sstevel 				pci_bridge = TRUE;
6141708Sstevel 			}
6151708Sstevel 		}
6161708Sstevel 
6171708Sstevel 		/*
6181708Sstevel 		 * Get slot-names property from slot_names_arr.
6191708Sstevel 		 * If we are the child of a pci_bridge we use the
6201708Sstevel 		 * dev# of the pci_bridge as an index to get
6211708Sstevel 		 * the slot number. We know that we are a child of
6221708Sstevel 		 * a pci-bridge if our parent is the same as the last
6231708Sstevel 		 * pci_bridge node found above.
6241708Sstevel 		 */
6251708Sstevel 		if (pci_card->dev_no != -1) {
6261708Sstevel 			/*
6271708Sstevel 			 * We compare this cards parent node with the
6281708Sstevel 			 * pci_bridge_node to see if it's a child.
6291708Sstevel 			 */
6301708Sstevel 			if (pci_card_node->parent != pci_instance &&
6311708Sstevel 			    pci_bridge) {
6321708Sstevel 				/* use dev_no of pci_bridge */
6331708Sstevel 				if (pci_card->pci_bus == 'B') {
6341708Sstevel 					slot_name =
6351708Sstevel 					    slot_name_arr[pci_bridge_dev_no -2];
6361708Sstevel 				} else {
6371708Sstevel 					slot_name =
6381708Sstevel 					    slot_name_arr[pci_bridge_dev_no -1];
6391708Sstevel 				}
6401708Sstevel 			} else {
6411708Sstevel 				if (pci_card->pci_bus == 'B') {
6421708Sstevel 				slot_name =
643*5019Skd93003 				    slot_name_arr[pci_card->dev_no-2];
6441708Sstevel 				} else {
6451708Sstevel 				slot_name =
646*5019Skd93003 				    slot_name_arr[pci_card->dev_no-1];
6471708Sstevel 				}
6481708Sstevel 			}
6491708Sstevel 
6501708Sstevel 			if (slot_name != NULL &&
6511708Sstevel 			    strlen(slot_name) != 0) {
6521708Sstevel 				/* Slot num is last char in string */
6531708Sstevel 				(void) snprintf(pci_card->slot_str, MAXSTRLEN,
6541708Sstevel 				    "%c", slot_name[strlen(slot_name) - 1]);
6551708Sstevel 			} else {
6561708Sstevel 				(void) snprintf(pci_card->slot_str, MAXSTRLEN,
6571708Sstevel 				    "-");
6581708Sstevel 			}
6591708Sstevel 
6601708Sstevel 		} else {
6611708Sstevel 			(void) snprintf(pci_card->slot_str, MAXSTRLEN,
6621708Sstevel 			    "%c", '-');
6631708Sstevel 		}
6641708Sstevel 
6651708Sstevel 		/*
6661708Sstevel 		 * Check for failed status.
6671708Sstevel 		 */
6681708Sstevel 		if (node_failed(pci_card_node))
669*5019Skd93003 			(void) strcpy(pci_card->status, "fail");
6701708Sstevel 		else
671*5019Skd93003 			(void) strcpy(pci_card->status, "ok");
6721708Sstevel 
6731708Sstevel 		/* Get the model of this pci_card */
6741708Sstevel 		value = get_prop_val(find_prop(pci_card_node, "model"));
6751708Sstevel 		if (value == NULL)
6761708Sstevel 			pci_card->model[0] = '\0';
6771708Sstevel 		else {
6781708Sstevel 			(void) snprintf(pci_card->model, MAXSTRLEN, "%s",
679*5019Skd93003 			    (char *)value);
6801708Sstevel 		}
6811708Sstevel 		/*
6821708Sstevel 		 * The card may have a "clock-frequency" but we
6831708Sstevel 		 * are not interested in that. Instead we get the
6841708Sstevel 		 * "clock-frequency" of the PCI Bus that the card
6851708Sstevel 		 * resides on. PCI-A can operate at 33Mhz or 66Mhz
6861708Sstevel 		 * depending on what card is plugged into the Bus.
6871708Sstevel 		 * PCI-B always operates at 33Mhz.
6881708Sstevel 		 */
6891708Sstevel 		int_val = get_prop_val(find_prop(pci_instance,
690*5019Skd93003 		    "clock-frequency"));
6911708Sstevel 		if (int_val != NULL) {
6921708Sstevel 			pci_card->freq = HZ_TO_MHZ(*int_val);
6931708Sstevel 		} else {
6941708Sstevel 			pci_card->freq = -1;
6951708Sstevel 		}
6961708Sstevel 
6971708Sstevel 		/*
6981708Sstevel 		 * Figure out how we want to display the name
6991708Sstevel 		 */
7001708Sstevel 		value = get_prop_val(find_prop(pci_card_node,
701*5019Skd93003 		    "compatible"));
7021708Sstevel 		if (value != NULL) {
7031708Sstevel 			/* use 'name'-'compatible' */
7041708Sstevel 			(void) snprintf(buf, MAXSTRLEN, "%s-%s", name,
705*5019Skd93003 			    (char *)value);
7061708Sstevel 		} else {
7071708Sstevel 			/* just use 'name' */
7081708Sstevel 			(void) snprintf(buf, MAXSTRLEN, "%s", name);
7091708Sstevel 		}
7101708Sstevel 		name = buf;
7111708Sstevel 
7121708Sstevel 		/*
7131708Sstevel 		 * If this node has children, add the device_type
7141708Sstevel 		 * of the child to the name value of this pci_card->
7151708Sstevel 		 */
7161708Sstevel 		child_name = (char *)get_node_name(pci_card_node->child);
7171708Sstevel 		if ((pci_card_node->child != NULL) &&
718*5019Skd93003 		    (child_name != NULL)) {
7191708Sstevel 			value = get_prop_val(find_prop(pci_card_node->child,
720*5019Skd93003 			    "device_type"));
7211708Sstevel 			if (value != NULL) {
7221708Sstevel 				/* add device_type of child to name */
7231708Sstevel 				(void) snprintf(pci_card->name, MAXSTRLEN,
7241708Sstevel 				    "%s/%s (%s)", name, child_name,
725*5019Skd93003 				    (char *)value);
7261708Sstevel 			} else {
7271708Sstevel 				/* just add childs name */
7281708Sstevel 				(void) snprintf(pci_card->name, MAXSTRLEN,
7291708Sstevel 				    "%s/%s", name, child_name);
7301708Sstevel 			}
7311708Sstevel 		} else {
7321708Sstevel 			(void) snprintf(pci_card->name, MAXSTRLEN, "%s",
7331708Sstevel 			    (char *)name);
7341708Sstevel 		}
7351708Sstevel 
7361708Sstevel 		/*
7371708Sstevel 		 * If this is a pci-bridge, then add the word
7381708Sstevel 		 * 'pci-bridge' to its model.  If we can't find
7391708Sstevel 		 * a model, then we just describe what the device
7401708Sstevel 		 * is based on some properties.
7411708Sstevel 		 */
7421708Sstevel 		if (pci_bridge) {
7431708Sstevel 			if (strlen(pci_card->model) == 0) {
744*5019Skd93003 				if (pci_card_node->parent == pci_bridge_node)
745*5019Skd93003 					(void) snprintf(pci_card->model,
746*5019Skd93003 					    MAXSTRLEN,
747*5019Skd93003 					    "%s", "device on pci-bridge");
748*5019Skd93003 				else if (pci_card_node->parent
749*5019Skd93003 				    == pci_parent_bridge)
750*5019Skd93003 					(void) snprintf(pci_card->model,
751*5019Skd93003 					    MAXSTRLEN,
752*5019Skd93003 					    "%s", "pci-bridge/pci-bridge");
753*5019Skd93003 				else
754*5019Skd93003 					(void) snprintf(pci_card->model,
755*5019Skd93003 					    MAXSTRLEN,
756*5019Skd93003 					    "%s", "PCI-BRIDGE");
7571708Sstevel 			}
7581708Sstevel 			else
7591708Sstevel 				(void) snprintf(pci_card->model, MAXSTRLEN,
7601708Sstevel 				    "%s/pci-bridge", pci_card->model);
7611708Sstevel 		}
7621708Sstevel 		/* insert this pci_card in the list to be displayed later */
7631708Sstevel 
7641708Sstevel 		*pci_card_list = insert_io_card(*pci_card_list, pci_card);
7651708Sstevel 
7661708Sstevel 		/*
7671708Sstevel 		 * If we are dealing with a pci-bridge, we need to move
7681708Sstevel 		 * down to the children of this bridge if there are any.
7691708Sstevel 		 *
7701708Sstevel 		 * If we are not, we are either dealing with a regular
7711708Sstevel 		 * card (in which case we move onto the sibling of this
7721708Sstevel 		 * card) or we are dealing with a child of a pci-bridge
7731708Sstevel 		 * (in which case we move onto the child's siblings or
7741708Sstevel 		 * if there are no more siblings for this child, we
7751708Sstevel 		 * move onto the parents siblings).
7761708Sstevel 		 */
7771708Sstevel 		pci_card_node = next_pci_card(pci_card_node, &pci_bridge,
778*5019Skd93003 		    is_pci, pci_bridge_node,
779*5019Skd93003 		    pci_parent_bridge, pci_instance);
7801708Sstevel 	} /* end-while */
7811708Sstevel }
7821708Sstevel 
7831708Sstevel /*
7841708Sstevel  * Helper function for fill_pci_card_list().  Indicates which
7851708Sstevel  * card node to go to next.
7861708Sstevel  * Parameters:
7871708Sstevel  * -----------
7881708Sstevel  * Prom_node * curr_card: pointer to the current card node
7891708Sstevel  *
7901708Sstevel  * int * is_bridge: indicates whether or not the card (is | is on)
7911708Sstevel  *                  a pci bridge
7921708Sstevel  *
7931708Sstevel  * int is_pcidev: indicates whether or not the current card
7941708Sstevel  *                is a pci bridge
7951708Sstevel  *
7961708Sstevel  * Prom_node * curr_bridge: pointer to the current pci bridge.  Eg:
7971708Sstevel  *                          curr_card->parent.
7981708Sstevel  *
7991708Sstevel  * Prom_node * parent_bridge: pointer to the first pci bridge encountered.
8001708Sstevel  *			      we could have nested pci bridges, this would
8011708Sstevel  *			      be the first one.
8021708Sstevel  *
8031708Sstevel  * Prom_node * pci: pointer to the pci instance that we are attached to.
8041708Sstevel  *		    This would be parent_bridge->parent, or
8051708Sstevel  *		    curr_node->parent, if curr_node is not on a pci bridge.
8061708Sstevel  */
8071708Sstevel 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)8081708Sstevel next_pci_card(Prom_node *curr_card, int *is_bridge, int is_pcidev,
8091708Sstevel 		Prom_node *curr_bridge, Prom_node *parent_bridge,
8101708Sstevel 		Prom_node *pci)
8111708Sstevel {
8121708Sstevel 	Prom_node * curr_node = curr_card;
8131708Sstevel 	if (*is_bridge) {
8141708Sstevel 		/*
8151708Sstevel 		 * is_pcidev is used to prevent us from following the
8161708Sstevel 		 * children of something like a scsi device.
8171708Sstevel 		 */
8181708Sstevel 		if (curr_node->child != NULL && is_pcidev) {
8191708Sstevel 			curr_node = curr_node->child;
8201708Sstevel 		} else {
8211708Sstevel 			curr_node = curr_node->sibling;
8221708Sstevel 			if (curr_node == NULL) {
8231708Sstevel 				curr_node = curr_bridge->sibling;
8241708Sstevel 				while (curr_node == NULL &&
825*5019Skd93003 				    curr_bridge != parent_bridge &&
826*5019Skd93003 				    curr_bridge != NULL) {
8271708Sstevel 					curr_node =
828*5019Skd93003 					    curr_bridge->parent->sibling;
8291708Sstevel 					curr_bridge = curr_bridge->parent;
8301708Sstevel 					if (curr_node != NULL &&
8311708Sstevel 					    curr_node->parent == pci)
8321708Sstevel 						break;
8331708Sstevel 				}
8341708Sstevel 				if (curr_bridge == NULL ||
8351708Sstevel 				    curr_node == NULL ||
8361708Sstevel 				    curr_node->parent == pci ||
8371708Sstevel 				    curr_bridge == parent_bridge ||
8381708Sstevel 				    curr_node == parent_bridge) {
8391708Sstevel 					*is_bridge = FALSE;
8401708Sstevel 				}
8411708Sstevel 			}
8421708Sstevel 		}
8431708Sstevel 
8441708Sstevel 	} else {
8451708Sstevel 		curr_node = curr_node->sibling;
8461708Sstevel 	}
8471708Sstevel 	return (curr_node);
8481708Sstevel }
849