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