103831d35Sstevel /*
203831d35Sstevel * CDDL HEADER START
303831d35Sstevel *
403831d35Sstevel * The contents of this file are subject to the terms of the
5*6def3553Skd * Common Development and Distribution License (the "License").
6*6def3553Skd * You may not use this file except in compliance with the License.
703831d35Sstevel *
803831d35Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
903831d35Sstevel * or http://www.opensolaris.org/os/licensing.
1003831d35Sstevel * See the License for the specific language governing permissions
1103831d35Sstevel * and limitations under the License.
1203831d35Sstevel *
1303831d35Sstevel * When distributing Covered Code, include this CDDL HEADER in each
1403831d35Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1503831d35Sstevel * If applicable, add the following below this CDDL HEADER, with the
1603831d35Sstevel * fields enclosed by brackets "[]" replaced with your own identifying
1703831d35Sstevel * information: Portions Copyright [yyyy] [name of copyright owner]
1803831d35Sstevel *
1903831d35Sstevel * CDDL HEADER END
2003831d35Sstevel */
2103831d35Sstevel /*
22*6def3553Skd * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
2303831d35Sstevel * Use is subject to license terms.
2403831d35Sstevel *
2503831d35Sstevel * Cherrystone platform-specific functions that aren't platform specific
2603831d35Sstevel *
2703831d35Sstevel */
2803831d35Sstevel
29*6def3553Skd #include <psvc_objects.h>
3003831d35Sstevel #include <libprtdiag.h>
3103831d35Sstevel #include <sys/mc.h>
3203831d35Sstevel
33*6def3553Skd /* prtdiag exit codes */
34*6def3553Skd #define PD_SUCCESS 0
35*6def3553Skd #define PD_SYSTEM_FAILURE 1
36*6def3553Skd #define PD_INTERNAL_FAILURE 2
37*6def3553Skd
38*6def3553Skd static int exit_code = PD_SUCCESS;
3903831d35Sstevel
4003831d35Sstevel static Prom_node *dev_next_node_by_compat(Prom_node *root, char *model);
4103831d35Sstevel static Prom_node *dev_find_node_by_compat(Prom_node *root, char *model);
4203831d35Sstevel
4303831d35Sstevel void print_us3_memory_line(int portid,
4403831d35Sstevel int bank_id,
4503831d35Sstevel uint64_t bank_size,
4603831d35Sstevel char *bank_status,
4703831d35Sstevel uint64_t dimm_size,
4803831d35Sstevel uint32_t intlv,
4903831d35Sstevel int seg_id);
5003831d35Sstevel
5103831d35Sstevel void add_node(Sys_tree *root, Prom_node *pnode);
5203831d35Sstevel int do_prominfo(int syserrlog,
5303831d35Sstevel char *pgname,
5403831d35Sstevel int log_flag,
5503831d35Sstevel int prt_flag);
5603831d35Sstevel
5703831d35Sstevel void *get_prop_val(Prop *prop);
5803831d35Sstevel Prop *find_prop(Prom_node *pnode, char *name);
5903831d35Sstevel char *get_node_name(Prom_node *pnode);
6003831d35Sstevel char *get_node_type(Prom_node *pnode);
6103831d35Sstevel
6203831d35Sstevel void fill_pci_card_list(Prom_node *pci_instance,
6303831d35Sstevel Prom_node *pci_card_node,
6403831d35Sstevel struct io_card *pci_card,
6503831d35Sstevel struct io_card **pci_card_list,
6603831d35Sstevel char **pci_slot_name_arr);
6703831d35Sstevel
6803831d35Sstevel static Prom_node *next_pci_card(Prom_node *curr_card, int *is_bridge,
6903831d35Sstevel int is_pcidev, Prom_node *curr_bridge,
7003831d35Sstevel Prom_node * parent_bridge, Prom_node *pci);
7103831d35Sstevel
7203831d35Sstevel #define HZ_TO_MHZ(x) (((x) + 500000) / 1000000)
7303831d35Sstevel
7403831d35Sstevel /*
7503831d35Sstevel * Start from the current node and return the next node besides
7603831d35Sstevel * the current one which has the requested model property.
7703831d35Sstevel */
7803831d35Sstevel static Prom_node *
dev_next_node_by_compat(Prom_node * root,char * compat)7903831d35Sstevel dev_next_node_by_compat(Prom_node *root, char *compat)
8003831d35Sstevel {
8103831d35Sstevel Prom_node *node;
8203831d35Sstevel
8303831d35Sstevel if (root == NULL)
84*6def3553Skd return (NULL);
8503831d35Sstevel
8603831d35Sstevel /* look at your children first */
8703831d35Sstevel if ((node = dev_find_node_by_compat(root->child, compat)) != NULL)
88*6def3553Skd return (node);
8903831d35Sstevel
9003831d35Sstevel /* now look at your siblings */
9103831d35Sstevel if ((node = dev_find_node_by_compat(root->sibling, compat)) != NULL)
92*6def3553Skd return (node);
9303831d35Sstevel
9403831d35Sstevel return (NULL); /* not found */
9503831d35Sstevel }
9603831d35Sstevel
9703831d35Sstevel /*
9803831d35Sstevel * Do a depth-first walk of a device tree and
9903831d35Sstevel * return the first node with the matching model.
10003831d35Sstevel */
10103831d35Sstevel static Prom_node *
dev_find_node_by_compat(Prom_node * root,char * compat)10203831d35Sstevel dev_find_node_by_compat(Prom_node *root, char *compat)
10303831d35Sstevel {
10403831d35Sstevel Prom_node *node;
10503831d35Sstevel char *compatible;
10603831d35Sstevel char *name;
10703831d35Sstevel
10803831d35Sstevel if (root == NULL)
10903831d35Sstevel return (NULL);
11003831d35Sstevel
11103831d35Sstevel if (compat == NULL)
11203831d35Sstevel return (NULL);
11303831d35Sstevel
11403831d35Sstevel name = get_node_name(root);
11503831d35Sstevel if (name == NULL)
11603831d35Sstevel name = "";
11703831d35Sstevel
11803831d35Sstevel compatible = (char *)get_prop_val(find_prop(root, "compatible"));
11903831d35Sstevel
12003831d35Sstevel if (compatible == NULL)
121*6def3553Skd return (NULL);
12203831d35Sstevel
12303831d35Sstevel if ((strcmp(name, "pci") == 0) && (compatible != NULL) &&
12403831d35Sstevel (strcmp(compatible, compat) == 0)) {
12503831d35Sstevel return (root); /* found a match */
12603831d35Sstevel }
12703831d35Sstevel
12803831d35Sstevel /* look at your children first */
12903831d35Sstevel if ((node = dev_find_node_by_compat(root->child, compat)) != NULL)
130*6def3553Skd return (node);
13103831d35Sstevel
13203831d35Sstevel /* now look at your siblings */
13303831d35Sstevel if ((node = dev_find_node_by_compat(root->sibling, compat)) != NULL)
134*6def3553Skd return (node);
13503831d35Sstevel
13603831d35Sstevel return (NULL); /* not found */
13703831d35Sstevel }
13803831d35Sstevel
13903831d35Sstevel int32_t
find_child_device(picl_nodehdl_t parent,char * child_name,picl_nodehdl_t * child)14003831d35Sstevel find_child_device(picl_nodehdl_t parent, char *child_name,
14103831d35Sstevel picl_nodehdl_t *child)
14203831d35Sstevel {
14303831d35Sstevel int32_t err;
14403831d35Sstevel char name[PICL_PROPNAMELEN_MAX];
14503831d35Sstevel
14603831d35Sstevel err = picl_get_propval_by_name(parent, PICL_PROP_CHILD, &(*child),
147*6def3553Skd sizeof (picl_nodehdl_t));
14803831d35Sstevel switch (err) {
14903831d35Sstevel case PICL_SUCCESS:
15003831d35Sstevel break;
15103831d35Sstevel case PICL_PROPNOTFOUND:
15203831d35Sstevel err = PICL_INVALIDHANDLE;
15303831d35Sstevel return (err);
15403831d35Sstevel default:
15503831d35Sstevel #ifdef WORKFILE_DEBUG
15603831d35Sstevel log_printf(dgettext(TEXT_DOMAIN,
15703831d35Sstevel "Failed picl_get_propval_by_name with %s\n"),
15803831d35Sstevel picl_strerror(err));
15903831d35Sstevel #endif
16003831d35Sstevel return (err);
16103831d35Sstevel }
16203831d35Sstevel
16303831d35Sstevel err = picl_get_propval_by_name(*child, PICL_PROP_NAME, name,
16403831d35Sstevel PICL_PROPNAMELEN_MAX);
16503831d35Sstevel
16603831d35Sstevel #ifdef WORKFILE_DEBUG
16703831d35Sstevel if (err != PICL_SUCCESS) {
16803831d35Sstevel log_printf(dgettext(TEXT_DOMAIN,
16903831d35Sstevel "failed the get name for root\n"));
17003831d35Sstevel log_printf(dgettext(TEXT_DOMAIN, "%s\n"), picl_strerror(err));
17103831d35Sstevel }
17203831d35Sstevel #endif
17303831d35Sstevel
17403831d35Sstevel if (strcmp(name, child_name) == 0)
17503831d35Sstevel return (err);
17603831d35Sstevel
17703831d35Sstevel while (err != PICL_PROPNOTFOUND) {
17803831d35Sstevel #ifdef WORKFILE_DEBUG
17903831d35Sstevel log_printf(dgettext(TEXT_DOMAIN, "child name is %s\n"), name);
18003831d35Sstevel #endif
18103831d35Sstevel err = picl_get_propval_by_name(*child, PICL_PROP_PEER,
182*6def3553Skd &(*child), sizeof (picl_nodehdl_t));
18303831d35Sstevel switch (err) {
18403831d35Sstevel case PICL_SUCCESS:
18503831d35Sstevel err = picl_get_propval_by_name(*child, PICL_PROP_NAME,
18603831d35Sstevel name, PICL_PROPNAMELEN_MAX);
18703831d35Sstevel if (strcmp(name, child_name) == 0)
18803831d35Sstevel return (err);
18903831d35Sstevel break;
19003831d35Sstevel case PICL_PROPNOTFOUND:
19103831d35Sstevel break;
19203831d35Sstevel default:
19303831d35Sstevel #ifdef WORKFILE_DEBUG
19403831d35Sstevel log_printf(dgettext(TEXT_DOMAIN,
19503831d35Sstevel "Failed picl_get_propval_by_name with %s\n"),
19603831d35Sstevel picl_strerror(err));
19703831d35Sstevel #endif
19803831d35Sstevel return (err);
19903831d35Sstevel }
20003831d35Sstevel }
20103831d35Sstevel err = PICL_INVALIDHANDLE;
20203831d35Sstevel return (err);
20303831d35Sstevel }
20403831d35Sstevel
20503831d35Sstevel int32_t
fill_device_from_id(picl_nodehdl_t device_id,char * assoc_id,picl_nodehdl_t * device)20603831d35Sstevel fill_device_from_id(picl_nodehdl_t device_id, char *assoc_id,
20703831d35Sstevel picl_nodehdl_t *device)
20803831d35Sstevel {
20903831d35Sstevel int32_t err;
21003831d35Sstevel picl_prophdl_t tbl_hdl;
21103831d35Sstevel picl_prophdl_t reference_property;
21203831d35Sstevel
21303831d35Sstevel err = picl_get_propval_by_name(device_id, assoc_id, &tbl_hdl,
214*6def3553Skd sizeof (picl_prophdl_t));
21503831d35Sstevel if (err != PICL_SUCCESS) {
21603831d35Sstevel #ifdef WORKFILE_DEBUG
21703831d35Sstevel if (err != PICL_INVALIDHANDLE) {
21803831d35Sstevel log_printf(dgettext(TEXT_DOMAIN,
21903831d35Sstevel "fill_device_from_id failure in "
22003831d35Sstevel "picl_get_propval_by_name err is %s\n"),
22103831d35Sstevel picl_strerror(err));
22203831d35Sstevel }
22303831d35Sstevel #endif
22403831d35Sstevel return (err);
22503831d35Sstevel }
22603831d35Sstevel
22703831d35Sstevel err = picl_get_next_by_row(tbl_hdl, &reference_property);
22803831d35Sstevel if (err != PICL_SUCCESS) {
22903831d35Sstevel #ifdef WORKFILE_DEBUG
23003831d35Sstevel log_printf(dgettext(TEXT_DOMAIN,
23103831d35Sstevel "fill_device_from_id failure in picl_get_next_by_row"
23203831d35Sstevel " err is %s\n"), picl_strerror(err));
23303831d35Sstevel #endif
23403831d35Sstevel return (err);
23503831d35Sstevel }
23603831d35Sstevel
23703831d35Sstevel /* get node associated with reference property */
23803831d35Sstevel err = picl_get_propval(reference_property, &(*device),
239*6def3553Skd sizeof (picl_nodehdl_t));
24003831d35Sstevel
24103831d35Sstevel #ifdef WORKFILE_DEBUG
24203831d35Sstevel if (err != 0) {
24303831d35Sstevel log_printf(dgettext(TEXT_DOMAIN,
24403831d35Sstevel "fill_device_from_id failure in picl_get_propval"
24503831d35Sstevel " err is %s\n"), picl_strerror(err));
24603831d35Sstevel }
24703831d35Sstevel #endif
24803831d35Sstevel
24903831d35Sstevel return (err);
25003831d35Sstevel }
25103831d35Sstevel
25203831d35Sstevel 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[])25303831d35Sstevel fill_device_array_from_id(picl_nodehdl_t device_id, char *assoc_id,
25403831d35Sstevel int32_t *number_of_devices, picl_nodehdl_t *device_array[])
25503831d35Sstevel {
25603831d35Sstevel int32_t err;
25703831d35Sstevel int i;
25803831d35Sstevel picl_prophdl_t tbl_hdl;
25903831d35Sstevel picl_prophdl_t entry;
26003831d35Sstevel int devs = 0;
26103831d35Sstevel
26203831d35Sstevel err = picl_get_propval_by_name(device_id, assoc_id, &tbl_hdl,
263*6def3553Skd sizeof (picl_prophdl_t));
26403831d35Sstevel if ((err != PICL_SUCCESS) && (err != PICL_INVALIDHANDLE)) {
26503831d35Sstevel #ifdef WORKFILE_DEBUG
266*6def3553Skd log_printf(dgettext(TEXT_DOMAIN,
267*6def3553Skd "fill_device_array_from_id failure in "
268*6def3553Skd "picl_get_propval_by_name err is %s\n"),
269*6def3553Skd picl_strerror(err));
27003831d35Sstevel #endif
271*6def3553Skd return (err);
27203831d35Sstevel }
27303831d35Sstevel
27403831d35Sstevel entry = tbl_hdl;
27503831d35Sstevel while (picl_get_next_by_row(entry, &entry) == 0)
27603831d35Sstevel ++devs;
27703831d35Sstevel
27803831d35Sstevel *device_array = calloc((devs), sizeof (picl_nodehdl_t));
27903831d35Sstevel if (*device_array == NULL) {
28003831d35Sstevel
28103831d35Sstevel #ifdef WORFILE_DEBUG
28203831d35Sstevel log_printf(dgettext(TEXT_DOMAIN,
28303831d35Sstevel "fill_device_array_from_id failure getting memory"
28403831d35Sstevel " for array\n"));
28503831d35Sstevel #endif
28603831d35Sstevel return (PICL_FAILURE);
28703831d35Sstevel }
28803831d35Sstevel
28903831d35Sstevel entry = tbl_hdl;
29003831d35Sstevel for (i = 0; i < devs; i++) {
29103831d35Sstevel err = picl_get_next_by_row(entry, &entry);
29203831d35Sstevel if (err != 0) {
29303831d35Sstevel #ifdef WORKFILE_DEBUG
29403831d35Sstevel log_printf(dgettext(TEXT_DOMAIN,
29503831d35Sstevel "fill_device_array_from_id failure in "
29603831d35Sstevel "picl_get_next_by_row err is %s\n"),
29703831d35Sstevel picl_strerror(err));
29803831d35Sstevel #endif
29903831d35Sstevel return (err);
30003831d35Sstevel }
30103831d35Sstevel
30203831d35Sstevel /* get node associated with reference property */
30303831d35Sstevel err = picl_get_propval(entry, &((*device_array)[i]),
304*6def3553Skd sizeof (picl_nodehdl_t));
30503831d35Sstevel if (err != 0) {
30603831d35Sstevel #ifdef WORKFILE_DEBUG
30703831d35Sstevel log_printf(dgettext(TEXT_DOMAIN,
30803831d35Sstevel "fill_device_array_from_id failure in "
30903831d35Sstevel "picl_get_propval err is %s\n"), picl_strerror(err));
31003831d35Sstevel #endif
31103831d35Sstevel
31203831d35Sstevel return (err);
31303831d35Sstevel }
31403831d35Sstevel }
31503831d35Sstevel *number_of_devices = devs;
31603831d35Sstevel return (err);
31703831d35Sstevel }
31803831d35Sstevel
31903831d35Sstevel /*
32003831d35Sstevel * add_node
32103831d35Sstevel *
32203831d35Sstevel * This function adds a board node to the board structure where that
32303831d35Sstevel * that node's physical component lives.
32403831d35Sstevel */
32503831d35Sstevel void
add_node(Sys_tree * root,Prom_node * pnode)32603831d35Sstevel add_node(Sys_tree *root, Prom_node *pnode)
32703831d35Sstevel {
32803831d35Sstevel int board = -1;
32903831d35Sstevel int portid = -1;
33003831d35Sstevel
33103831d35Sstevel void *value = NULL;
33203831d35Sstevel Board_node *bnode = NULL;
33303831d35Sstevel Prom_node *p = NULL;
33403831d35Sstevel
33503831d35Sstevel /* Get the board number of this board from the portid prop */
33603831d35Sstevel value = get_prop_val(find_prop(pnode, "portid"));
33703831d35Sstevel if (value != NULL) {
33803831d35Sstevel portid = *(int *)value;
33903831d35Sstevel }
34003831d35Sstevel
34103831d35Sstevel board = CHERRYSTONE_GETSLOT(portid);
34203831d35Sstevel
34303831d35Sstevel if ((bnode = find_board(root, board)) == NULL) {
34403831d35Sstevel bnode = insert_board(root, board);
34503831d35Sstevel }
34603831d35Sstevel
34703831d35Sstevel /* now attach this prom node to the board list */
34803831d35Sstevel /* Insert this node at the end of the list */
34903831d35Sstevel pnode->sibling = NULL;
35003831d35Sstevel if (bnode->nodes == NULL)
35103831d35Sstevel bnode->nodes = pnode;
35203831d35Sstevel else {
35303831d35Sstevel p = bnode->nodes;
35403831d35Sstevel while (p->sibling != NULL)
35503831d35Sstevel p = p->sibling;
35603831d35Sstevel p->sibling = pnode;
35703831d35Sstevel }
35803831d35Sstevel }
35903831d35Sstevel
36003831d35Sstevel /*
36103831d35Sstevel * This function provides formatting of the memory config
36203831d35Sstevel * information that get_us3_mem_regs() and display_us3_banks() code has
36303831d35Sstevel * gathered. It overrides the generic print_us3_memory_line() code
36403831d35Sstevel * which prints an error message.
36503831d35Sstevel */
36603831d35Sstevel 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)36703831d35Sstevel print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
36803831d35Sstevel char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id)
36903831d35Sstevel {
37003831d35Sstevel log_printf(dgettext(TEXT_DOMAIN,
371*6def3553Skd "\n %-1c %2d %2d %4lldMB %11-s %4lldMB "
372*6def3553Skd " %2d-way %d"),
373*6def3553Skd CHERRYSTONE_GETSLOT_LABEL(portid), portid,
374*6def3553Skd (bank_id % 4), bank_size, bank_status, dimm_size,
375*6def3553Skd intlv, seg_id, 0);
37603831d35Sstevel }
37703831d35Sstevel
37803831d35Sstevel /*
379*6def3553Skd * We call do_devinfo() in order to use the libdevinfo device tree instead of
380*6def3553Skd * OBP's device tree. Ignore its return value and use our exit_code instead.
381*6def3553Skd * Its return value comes from calling error_check() which is not implemented
382*6def3553Skd * because the device tree does not keep track of the status property for the
383*6def3553Skd * 480/490. The exit_code we return is set while do_devinfo() calls our local
384*6def3553Skd * functions to gather/print data. That way we can report both internal and
385*6def3553Skd * device failures.
38603831d35Sstevel */
38703831d35Sstevel int
do_prominfo(int syserrlog,char * pgname,int log_flag,int prt_flag)38803831d35Sstevel do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag)
38903831d35Sstevel {
390*6def3553Skd (void) do_devinfo(syserrlog, pgname, log_flag, prt_flag);
391*6def3553Skd return (exit_code);
39203831d35Sstevel }
39303831d35Sstevel
39403831d35Sstevel /*
39503831d35Sstevel * return the property value for the Prop
39603831d35Sstevel * passed in. (When using libdevinfo)
39703831d35Sstevel */
39803831d35Sstevel void *
get_prop_val(Prop * prop)39903831d35Sstevel get_prop_val(Prop *prop)
40003831d35Sstevel {
40103831d35Sstevel if (prop == NULL)
40203831d35Sstevel return (NULL);
40303831d35Sstevel
40403831d35Sstevel return ((void *)(prop->value.val_ptr));
40503831d35Sstevel }
40603831d35Sstevel
40703831d35Sstevel /*
40803831d35Sstevel * Search a Prom node and retrieve the property with the correct
40903831d35Sstevel * name. (When using libdevinfo)
41003831d35Sstevel */
41103831d35Sstevel Prop *
find_prop(Prom_node * pnode,char * name)41203831d35Sstevel find_prop(Prom_node *pnode, char *name)
41303831d35Sstevel {
41403831d35Sstevel Prop *prop;
41503831d35Sstevel
41603831d35Sstevel if (pnode == NULL)
41703831d35Sstevel return (NULL);
41803831d35Sstevel
41903831d35Sstevel if (pnode->props == NULL)
42003831d35Sstevel return (NULL);
42103831d35Sstevel
42203831d35Sstevel prop = pnode->props;
42303831d35Sstevel if (prop == NULL)
42403831d35Sstevel return (NULL);
42503831d35Sstevel
42603831d35Sstevel if (prop->name.val_ptr == NULL)
42703831d35Sstevel return (NULL);
42803831d35Sstevel
42903831d35Sstevel while ((prop != NULL) && (strcmp((char *)(prop->name.val_ptr), name))) {
43003831d35Sstevel prop = prop->next;
43103831d35Sstevel }
43203831d35Sstevel return (prop);
43303831d35Sstevel }
43403831d35Sstevel
43503831d35Sstevel /*
43603831d35Sstevel * This function searches through the properties of the node passed in
43703831d35Sstevel * and returns a pointer to the value of the name property.
43803831d35Sstevel * (When using libdevinfo)
43903831d35Sstevel */
44003831d35Sstevel char *
get_node_name(Prom_node * pnode)44103831d35Sstevel get_node_name(Prom_node *pnode)
44203831d35Sstevel {
44303831d35Sstevel Prop *prop;
44403831d35Sstevel
44503831d35Sstevel if (pnode == NULL) {
44603831d35Sstevel return (NULL);
44703831d35Sstevel }
44803831d35Sstevel
44903831d35Sstevel prop = pnode->props;
45003831d35Sstevel while (prop != NULL) {
45103831d35Sstevel if (strcmp("name", (char *)prop->name.val_ptr) == 0)
45203831d35Sstevel return (prop->value.val_ptr);
45303831d35Sstevel prop = prop->next;
45403831d35Sstevel }
45503831d35Sstevel return (NULL);
45603831d35Sstevel }
45703831d35Sstevel
45803831d35Sstevel /*
45903831d35Sstevel * This function searches through the properties of the node passed in
46003831d35Sstevel * and returns a pointer to the value of the device_type property.
46103831d35Sstevel * (When using libdevinfo)
46203831d35Sstevel */
46303831d35Sstevel char *
get_node_type(Prom_node * pnode)46403831d35Sstevel get_node_type(Prom_node *pnode)
46503831d35Sstevel {
46603831d35Sstevel Prop *prop;
46703831d35Sstevel
46803831d35Sstevel if (pnode == NULL) {
46903831d35Sstevel return (NULL);
47003831d35Sstevel }
47103831d35Sstevel
47203831d35Sstevel prop = pnode->props;
47303831d35Sstevel while (prop != NULL) {
47403831d35Sstevel if (strcmp("device_type", (char *)prop->name.val_ptr) == 0)
47503831d35Sstevel return (prop->value.val_ptr);
47603831d35Sstevel prop = prop->next;
47703831d35Sstevel }
47803831d35Sstevel return (NULL);
47903831d35Sstevel }
48003831d35Sstevel
48103831d35Sstevel
48203831d35Sstevel /*
48303831d35Sstevel * Fills in the i/o card list to be displayed later in display_pci();
48403831d35Sstevel */
48503831d35Sstevel 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)48603831d35Sstevel fill_pci_card_list(Prom_node * pci_instance, Prom_node * pci_card_node,
48703831d35Sstevel struct io_card *pci_card,
48803831d35Sstevel struct io_card **pci_card_list, char **slot_name_arr)
48903831d35Sstevel {
49003831d35Sstevel Prom_node *pci_bridge_node;
49103831d35Sstevel Prom_node *pci_parent_bridge;
49203831d35Sstevel int *int_val;
49303831d35Sstevel int pci_bridge = FALSE;
49403831d35Sstevel int pci_bridge_dev_no = -1;
49503831d35Sstevel int portid;
49603831d35Sstevel int pci_bus;
49703831d35Sstevel char buf[MAXSTRLEN];
49803831d35Sstevel char *slot_name = NULL; /* info in "slot-names" prop */
49903831d35Sstevel char *child_name;
50003831d35Sstevel char *name;
50103831d35Sstevel char *type;
50203831d35Sstevel void *value;
50303831d35Sstevel
50403831d35Sstevel while (pci_card_node != NULL) {
50503831d35Sstevel int is_pci = FALSE;
50603831d35Sstevel type = NULL;
50703831d35Sstevel name = NULL;
50803831d35Sstevel /* If it doesn't have a name, skip it */
50903831d35Sstevel name = (char *)get_prop_val(
510*6def3553Skd find_prop(pci_card_node, "name"));
51103831d35Sstevel if (name == NULL) {
51203831d35Sstevel pci_card_node = pci_card_node->sibling;
51303831d35Sstevel continue;
51403831d35Sstevel }
51503831d35Sstevel
51603831d35Sstevel /*
51703831d35Sstevel * Get the portid of the schizo that this card
51803831d35Sstevel * lives under.
51903831d35Sstevel */
52003831d35Sstevel portid = -1;
52103831d35Sstevel value = get_prop_val(find_prop(pci_instance, "portid"));
52203831d35Sstevel if (value != NULL) {
52303831d35Sstevel portid = *(int *)value;
52403831d35Sstevel }
52503831d35Sstevel pci_card->schizo_portid = portid;
52603831d35Sstevel if (pci_card->schizo_portid != 8) {
52703831d35Sstevel /*
52803831d35Sstevel * Schizo0 (portid 8) has no slots on Cherrystone.
52903831d35Sstevel * So if that's who we're looking at, we're done.
53003831d35Sstevel */
53103831d35Sstevel return;
53203831d35Sstevel }
53303831d35Sstevel
53403831d35Sstevel /*
53503831d35Sstevel * Find out whether this is PCI bus A or B
53603831d35Sstevel * using the 'reg' property.
53703831d35Sstevel */
53803831d35Sstevel int_val = (int *)get_prop_val(find_prop(pci_instance, "reg"));
53903831d35Sstevel
54003831d35Sstevel if (int_val != NULL) {
54103831d35Sstevel int_val++; /* skip over first integer */
54203831d35Sstevel pci_bus = ((*int_val) & 0x7f0000);
54303831d35Sstevel if (pci_bus == 0x600000)
54403831d35Sstevel pci_card->pci_bus = 'A';
54503831d35Sstevel else if (pci_bus == 0x700000)
54603831d35Sstevel pci_card->pci_bus = 'B';
54703831d35Sstevel else {
54803831d35Sstevel assert(0); /* should never happen */
54903831d35Sstevel pci_card->pci_bus = '-';
55003831d35Sstevel }
55103831d35Sstevel } else {
55203831d35Sstevel assert(0); /* should never happen */
55303831d35Sstevel pci_card->pci_bus = '-';
55403831d35Sstevel }
55503831d35Sstevel
55603831d35Sstevel /*
55703831d35Sstevel * get dev# and func# for this card from the
55803831d35Sstevel * 'reg' property.
55903831d35Sstevel */
56003831d35Sstevel int_val = (int *)get_prop_val(
561*6def3553Skd find_prop(pci_card_node, "reg"));
56203831d35Sstevel if (int_val != NULL) {
56303831d35Sstevel pci_card->dev_no = (((*int_val) & 0xF800) >> 11);
56403831d35Sstevel pci_card->func_no = (((*int_val) & 0x700) >> 8);
56503831d35Sstevel } else {
56603831d35Sstevel pci_card->dev_no = -1;
56703831d35Sstevel pci_card->func_no = -1;
56803831d35Sstevel }
56903831d35Sstevel
57003831d35Sstevel switch (pci_card->pci_bus) {
57103831d35Sstevel case 'A':
57203831d35Sstevel if ((pci_card->dev_no < 1 || pci_card->dev_no > 2) &&
573*6def3553Skd (!pci_bridge)) {
57403831d35Sstevel pci_card_node = pci_card_node->sibling;
57503831d35Sstevel continue;
57603831d35Sstevel }
57703831d35Sstevel break;
57803831d35Sstevel case 'B':
57903831d35Sstevel if ((pci_card->dev_no < 2 || pci_card->dev_no > 5) &&
580*6def3553Skd (!pci_bridge)) {
58103831d35Sstevel pci_card_node = pci_card_node->sibling;
58203831d35Sstevel continue;
58303831d35Sstevel }
58403831d35Sstevel break;
58503831d35Sstevel default:
58603831d35Sstevel pci_card_node = pci_card_node->sibling;
58703831d35Sstevel continue;
58803831d35Sstevel }
58903831d35Sstevel
59003831d35Sstevel type = (char *)get_prop_val(
591*6def3553Skd find_prop(pci_card_node, "device_type"));
59203831d35Sstevel /*
59303831d35Sstevel * If this is a pci-bridge, then store its dev#
59403831d35Sstevel * as its children nodes need this to get their slot#.
59503831d35Sstevel * We set the pci_bridge flag so that we know we are
59603831d35Sstevel * looking at a pci-bridge node. This flag gets reset
59703831d35Sstevel * every time we enter this while loop.
59803831d35Sstevel */
59903831d35Sstevel
60003831d35Sstevel /*
60103831d35Sstevel * Check for a PCI-PCI Bridge for PCI and cPCI
60203831d35Sstevel * IO Boards using the name and type properties.
60303831d35Sstevel */
60403831d35Sstevel if ((type != NULL) && (strncmp(name, "pci", 3) == 0) &&
60503831d35Sstevel (strcmp(type, "pci") == 0)) {
60603831d35Sstevel pci_bridge_node = pci_card_node;
60703831d35Sstevel is_pci = TRUE;
60803831d35Sstevel if (!pci_bridge) {
60903831d35Sstevel pci_bridge_dev_no = pci_card->dev_no;
61003831d35Sstevel pci_parent_bridge = pci_bridge_node;
61103831d35Sstevel pci_bridge = TRUE;
61203831d35Sstevel }
61303831d35Sstevel }
61403831d35Sstevel
61503831d35Sstevel /*
61603831d35Sstevel * Get slot-names property from slot_names_arr.
61703831d35Sstevel * If we are the child of a pci_bridge we use the
61803831d35Sstevel * dev# of the pci_bridge as an index to get
61903831d35Sstevel * the slot number. We know that we are a child of
62003831d35Sstevel * a pci-bridge if our parent is the same as the last
62103831d35Sstevel * pci_bridge node found above.
62203831d35Sstevel */
62303831d35Sstevel if (pci_card->dev_no != -1) {
62403831d35Sstevel /*
62503831d35Sstevel * We compare this cards parent node with the
62603831d35Sstevel * pci_bridge_node to see if it's a child.
62703831d35Sstevel */
62803831d35Sstevel if (pci_card_node->parent != pci_instance &&
62903831d35Sstevel pci_bridge) {
63003831d35Sstevel /* use dev_no of pci_bridge */
63103831d35Sstevel if (pci_card->pci_bus == 'B') {
63203831d35Sstevel slot_name =
63303831d35Sstevel slot_name_arr[pci_bridge_dev_no -2];
63403831d35Sstevel } else {
63503831d35Sstevel slot_name =
63603831d35Sstevel slot_name_arr[pci_bridge_dev_no -1];
63703831d35Sstevel }
63803831d35Sstevel } else {
63903831d35Sstevel if (pci_card->pci_bus == 'B') {
64003831d35Sstevel slot_name =
641*6def3553Skd slot_name_arr[pci_card->dev_no-2];
64203831d35Sstevel } else {
64303831d35Sstevel slot_name =
644*6def3553Skd slot_name_arr[pci_card->dev_no-1];
64503831d35Sstevel }
64603831d35Sstevel }
64703831d35Sstevel
64803831d35Sstevel if (slot_name != NULL &&
64903831d35Sstevel strlen(slot_name) != 0) {
65003831d35Sstevel /* Slot num is last char in string */
65103831d35Sstevel (void) snprintf(pci_card->slot_str, MAXSTRLEN,
65203831d35Sstevel "%c", slot_name[strlen(slot_name) - 1]);
65303831d35Sstevel } else {
65403831d35Sstevel (void) snprintf(pci_card->slot_str, MAXSTRLEN,
65503831d35Sstevel "-");
65603831d35Sstevel }
65703831d35Sstevel
65803831d35Sstevel } else {
65903831d35Sstevel (void) snprintf(pci_card->slot_str, MAXSTRLEN,
66003831d35Sstevel "%c", '-');
66103831d35Sstevel }
66203831d35Sstevel
66303831d35Sstevel /*
66403831d35Sstevel * Check for failed status.
66503831d35Sstevel */
66603831d35Sstevel if (node_failed(pci_card_node))
667*6def3553Skd (void) strcpy(pci_card->status, "fail");
66803831d35Sstevel else
669*6def3553Skd (void) strcpy(pci_card->status, "ok");
67003831d35Sstevel
67103831d35Sstevel /* Get the model of this pci_card */
67203831d35Sstevel value = get_prop_val(find_prop(pci_card_node, "model"));
67303831d35Sstevel if (value == NULL)
67403831d35Sstevel pci_card->model[0] = '\0';
67503831d35Sstevel else {
67603831d35Sstevel (void) snprintf(pci_card->model, MAXSTRLEN, "%s",
677*6def3553Skd (char *)value);
67803831d35Sstevel }
67903831d35Sstevel /*
68003831d35Sstevel * The card may have a "clock-frequency" but we
68103831d35Sstevel * are not interested in that. Instead we get the
68203831d35Sstevel * "clock-frequency" of the PCI Bus that the card
68303831d35Sstevel * resides on. PCI-A can operate at 33Mhz or 66Mhz
68403831d35Sstevel * depending on what card is plugged into the Bus.
68503831d35Sstevel * PCI-B always operates at 33Mhz.
68603831d35Sstevel */
68703831d35Sstevel int_val = get_prop_val(find_prop(pci_instance,
688*6def3553Skd "clock-frequency"));
68903831d35Sstevel if (int_val != NULL) {
69003831d35Sstevel pci_card->freq = HZ_TO_MHZ(*int_val);
69103831d35Sstevel } else {
69203831d35Sstevel pci_card->freq = -1;
69303831d35Sstevel }
69403831d35Sstevel
69503831d35Sstevel /*
69603831d35Sstevel * Figure out how we want to display the name
69703831d35Sstevel */
69803831d35Sstevel value = get_prop_val(find_prop(pci_card_node,
699*6def3553Skd "compatible"));
70003831d35Sstevel if (value != NULL) {
70103831d35Sstevel /* use 'name'-'compatible' */
70203831d35Sstevel (void) snprintf(buf, MAXSTRLEN, "%s-%s", name,
703*6def3553Skd (char *)value);
70403831d35Sstevel } else {
70503831d35Sstevel /* just use 'name' */
70603831d35Sstevel (void) snprintf(buf, MAXSTRLEN, "%s", name);
70703831d35Sstevel }
70803831d35Sstevel name = buf;
70903831d35Sstevel
71003831d35Sstevel /*
71103831d35Sstevel * If this node has children, add the device_type
71203831d35Sstevel * of the child to the name value of this pci_card->
71303831d35Sstevel */
71403831d35Sstevel child_name = (char *)get_node_name(pci_card_node->child);
71503831d35Sstevel if ((pci_card_node->child != NULL) &&
716*6def3553Skd (child_name != NULL)) {
71703831d35Sstevel value = get_prop_val(find_prop(pci_card_node->child,
718*6def3553Skd "device_type"));
71903831d35Sstevel if (value != NULL) {
72003831d35Sstevel /* add device_type of child to name */
72103831d35Sstevel (void) snprintf(pci_card->name, MAXSTRLEN,
72203831d35Sstevel "%s/%s (%s)", name, child_name,
723*6def3553Skd (char *)value);
72403831d35Sstevel } else {
72503831d35Sstevel /* just add childs name */
72603831d35Sstevel (void) snprintf(pci_card->name, MAXSTRLEN,
72703831d35Sstevel "%s/%s", name, child_name);
72803831d35Sstevel }
72903831d35Sstevel } else {
73003831d35Sstevel (void) snprintf(pci_card->name, MAXSTRLEN, "%s",
73103831d35Sstevel (char *)name);
73203831d35Sstevel }
73303831d35Sstevel
73403831d35Sstevel /*
73503831d35Sstevel * If this is a pci-bridge, then add the word
73603831d35Sstevel * 'pci-bridge' to its model. If we can't find
73703831d35Sstevel * a model, then we just describe what the device
73803831d35Sstevel * is based on some properties.
73903831d35Sstevel */
74003831d35Sstevel if (pci_bridge) {
74103831d35Sstevel if (strlen(pci_card->model) == 0) {
742*6def3553Skd if (pci_card_node->parent == pci_bridge_node)
743*6def3553Skd (void) snprintf(pci_card->model,
744*6def3553Skd MAXSTRLEN,
745*6def3553Skd "%s", "device on pci-bridge");
746*6def3553Skd else if (pci_card_node->parent
747*6def3553Skd == pci_parent_bridge)
748*6def3553Skd (void) snprintf(pci_card->model,
749*6def3553Skd MAXSTRLEN,
750*6def3553Skd "%s", "pci-bridge/pci-bridge");
751*6def3553Skd else
752*6def3553Skd (void) snprintf(pci_card->model,
753*6def3553Skd MAXSTRLEN,
754*6def3553Skd "%s", "PCI-BRIDGE");
75503831d35Sstevel }
75603831d35Sstevel else
75703831d35Sstevel (void) snprintf(pci_card->model, MAXSTRLEN,
75803831d35Sstevel "%s/pci-bridge", pci_card->model);
75903831d35Sstevel }
76003831d35Sstevel /* insert this pci_card in the list to be displayed later */
76103831d35Sstevel
76203831d35Sstevel *pci_card_list = insert_io_card(*pci_card_list, pci_card);
76303831d35Sstevel
76403831d35Sstevel /*
76503831d35Sstevel * If we are dealing with a pci-bridge, we need to move
76603831d35Sstevel * down to the children of this bridge if there are any.
76703831d35Sstevel *
76803831d35Sstevel * If we are not, we are either dealing with a regular
76903831d35Sstevel * card (in which case we move onto the sibling of this
77003831d35Sstevel * card) or we are dealing with a child of a pci-bridge
77103831d35Sstevel * (in which case we move onto the child's siblings or
77203831d35Sstevel * if there are no more siblings for this child, we
77303831d35Sstevel * move onto the parents siblings).
77403831d35Sstevel */
77503831d35Sstevel pci_card_node = next_pci_card(pci_card_node, &pci_bridge,
776*6def3553Skd is_pci, pci_bridge_node,
777*6def3553Skd pci_parent_bridge, pci_instance);
77803831d35Sstevel } /* end-while */
77903831d35Sstevel }
78003831d35Sstevel
78103831d35Sstevel /*
78203831d35Sstevel * Helper function for fill_pci_card_list(). Indicates which
78303831d35Sstevel * card node to go to next.
78403831d35Sstevel * Parameters:
78503831d35Sstevel * -----------
78603831d35Sstevel * Prom_node * curr_card: pointer to the current card node
78703831d35Sstevel *
78803831d35Sstevel * int * is_bridge: indicates whether or not the card (is | is on)
78903831d35Sstevel * a pci bridge
79003831d35Sstevel *
79103831d35Sstevel * int is_pcidev: indicates whether or not the current card
79203831d35Sstevel * is a pci bridge
79303831d35Sstevel *
79403831d35Sstevel * Prom_node * curr_bridge: pointer to the current pci bridge. Eg:
79503831d35Sstevel * curr_card->parent.
79603831d35Sstevel *
79703831d35Sstevel * Prom_node * parent_bridge: pointer to the first pci bridge encountered.
79803831d35Sstevel * we could have nested pci bridges, this would
79903831d35Sstevel * be the first one.
80003831d35Sstevel *
80103831d35Sstevel * Prom_node * pci: pointer to the pci instance that we are attached to.
80203831d35Sstevel * This would be parent_bridge->parent, or
80303831d35Sstevel * curr_node->parent, if curr_node is not on a pci bridge.
80403831d35Sstevel */
80503831d35Sstevel 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)80603831d35Sstevel next_pci_card(Prom_node *curr_card, int *is_bridge, int is_pcidev,
80703831d35Sstevel Prom_node *curr_bridge, Prom_node *parent_bridge,
80803831d35Sstevel Prom_node *pci)
80903831d35Sstevel {
81003831d35Sstevel Prom_node * curr_node = curr_card;
81103831d35Sstevel if (*is_bridge) {
81203831d35Sstevel /*
81303831d35Sstevel * is_pcidev is used to prevent us from following the
81403831d35Sstevel * children of something like a scsi device.
81503831d35Sstevel */
81603831d35Sstevel if (curr_node->child != NULL && is_pcidev) {
81703831d35Sstevel curr_node = curr_node->child;
81803831d35Sstevel } else {
81903831d35Sstevel curr_node = curr_node->sibling;
82003831d35Sstevel if (curr_node == NULL) {
82103831d35Sstevel curr_node = curr_bridge->sibling;
82203831d35Sstevel while (curr_node == NULL &&
823*6def3553Skd curr_bridge != parent_bridge &&
824*6def3553Skd curr_bridge != NULL) {
82503831d35Sstevel curr_node =
826*6def3553Skd curr_bridge->parent->sibling;
82703831d35Sstevel curr_bridge = curr_bridge->parent;
82803831d35Sstevel if (curr_node != NULL &&
82903831d35Sstevel curr_node->parent == pci)
83003831d35Sstevel break;
83103831d35Sstevel }
83203831d35Sstevel if (curr_bridge == NULL ||
83303831d35Sstevel curr_node == NULL ||
83403831d35Sstevel curr_node->parent == pci ||
83503831d35Sstevel curr_bridge == parent_bridge ||
83603831d35Sstevel curr_node == parent_bridge) {
83703831d35Sstevel *is_bridge = FALSE;
83803831d35Sstevel }
83903831d35Sstevel }
84003831d35Sstevel }
84103831d35Sstevel
84203831d35Sstevel } else {
84303831d35Sstevel curr_node = curr_node->sibling;
84403831d35Sstevel }
84503831d35Sstevel return (curr_node);
84603831d35Sstevel }
847