11708Sstevel /*
21708Sstevel * CDDL HEADER START
31708Sstevel *
41708Sstevel * The contents of this file are subject to the terms of the
5*3941Svenki * Common Development and Distribution License (the "License").
6*3941Svenki * 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*3941Svenki * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
231708Sstevel * Use is subject to license terms.
241708Sstevel */
251708Sstevel
261708Sstevel #pragma ident "%Z%%M% %I% %E% SMI"
271708Sstevel
281708Sstevel #include <stdio.h>
291708Sstevel #include <stdlib.h>
301708Sstevel #include <string.h>
311708Sstevel #include <fcntl.h>
321708Sstevel #include <dirent.h>
331708Sstevel #include <varargs.h>
341708Sstevel #include <errno.h>
351708Sstevel #include <unistd.h>
361708Sstevel #include <alloca.h>
371708Sstevel #include <sys/systeminfo.h>
381708Sstevel #include <sys/utsname.h>
391708Sstevel #include <sys/openpromio.h>
401708Sstevel #include <kstat.h>
411708Sstevel #include <libintl.h>
421708Sstevel #include "pdevinfo.h"
431708Sstevel #include "display.h"
441708Sstevel #include "display_sun4v.h"
451708Sstevel #include "libprtdiag.h"
461708Sstevel
471708Sstevel #if !defined(TEXT_DOMAIN)
481708Sstevel #define TEXT_DOMAIN "SYS_TEST"
491708Sstevel #endif
501708Sstevel
511708Sstevel /*
521708Sstevel * Global variables
531708Sstevel */
541708Sstevel char *progname;
551708Sstevel char *promdev = "/dev/openprom";
561708Sstevel int print_flag = 1;
571708Sstevel int logging = 0;
581708Sstevel
591708Sstevel /*
601708Sstevel * This file represents the splitting out of some functionality
611708Sstevel * of prtdiag due to the port to the sun4v platform. The PROM
621708Sstevel * tree-walking functions which contain sun4v specifics were moved
631708Sstevel * into this module.
641708Sstevel */
651708Sstevel
661708Sstevel extern int get_id(Prom_node *);
671708Sstevel
681708Sstevel /* Function prototypes */
691708Sstevel Prom_node *sun4v_walk(Sys_tree *, Prom_node *, int);
70*3941Svenki picl_errno_t sun4v_get_node_by_name(picl_nodehdl_t, char *, picl_nodehdl_t *);
71*3941Svenki
721708Sstevel /*
731708Sstevel * do_prominfo() is called from main() in usr/src/cmd/prtdiag/main.c
741708Sstevel *
751708Sstevel * This is the starting point for all platforms. However, this function
761708Sstevel * can be overlayed by writing a do_prominfo() function
771708Sstevel * in the libprtdiag_psr for a particular platform.
781708Sstevel *
791708Sstevel */
801708Sstevel int
do_prominfo(int syserrlog,char * pgname,int log_flag,int prt_flag)811708Sstevel do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag)
821708Sstevel {
831708Sstevel Sys_tree sys_tree; /* system information */
841708Sstevel Prom_node *root_node; /* root node of OBP device tree */
851708Sstevel picl_nodehdl_t rooth; /* root PICL node for IO display */
861708Sstevel picl_nodehdl_t plafh; /* Platform PICL node for IO display */
871708Sstevel
88*3941Svenki picl_errno_t err;
891708Sstevel
901708Sstevel err = picl_initialize();
911708Sstevel if (err != PICL_SUCCESS) {
921708Sstevel (void) fprintf(stderr, EM_INIT_FAIL, picl_strerror(err));
931708Sstevel exit(1);
941708Sstevel }
951708Sstevel
961708Sstevel /* set the global flags */
971708Sstevel progname = pgname;
981708Sstevel logging = log_flag;
991708Sstevel print_flag = prt_flag;
1001708Sstevel
1011708Sstevel /* set the the system tree fields */
1021708Sstevel sys_tree.sys_mem = NULL;
1031708Sstevel sys_tree.boards = NULL;
1041708Sstevel sys_tree.bd_list = NULL;
1051708Sstevel sys_tree.board_cnt = 0;
1061708Sstevel
1071708Sstevel if (promopen(O_RDONLY)) {
1081708Sstevel exit(_error(dgettext(TEXT_DOMAIN, "openeepr device "
1091708Sstevel "open failed")));
1101708Sstevel }
1111708Sstevel
1121708Sstevel if (is_openprom() == 0) {
1131708Sstevel (void) fprintf(stderr, "%s",
1141708Sstevel dgettext(TEXT_DOMAIN, "System architecture "
1151708Sstevel "does not support this option of this "
1161708Sstevel "command.\n"));
1171708Sstevel return (2);
1181708Sstevel }
1191708Sstevel
1201708Sstevel if (next(0) == 0) {
1211708Sstevel return (2);
1221708Sstevel }
1231708Sstevel
1241708Sstevel root_node = sun4v_walk(&sys_tree, NULL, next(0));
1251708Sstevel promclose();
1261708Sstevel
1271708Sstevel err = picl_get_root(&rooth);
1281708Sstevel if (err != PICL_SUCCESS) {
1291708Sstevel (void) fprintf(stderr, EM_GET_ROOT_FAIL, picl_strerror(err));
1301708Sstevel exit(1);
1311708Sstevel }
1321708Sstevel
1331708Sstevel err = sun4v_get_node_by_name(rooth, PICL_NODE_PLATFORM, &plafh);
1341708Sstevel if (err != PICL_SUCCESS)
1351708Sstevel return (err);
1361708Sstevel
1371708Sstevel return (sun4v_display(&sys_tree, root_node, syserrlog, plafh));
1381708Sstevel
1391708Sstevel }
1401708Sstevel
1411708Sstevel /*
1421708Sstevel * sun4v_Walk the PROM device tree and build the system tree and root tree.
1431708Sstevel * Nodes that have a board number property are placed in the board
1441708Sstevel * structures for easier processing later. Child nodes are placed
1451708Sstevel * under their parents.
1461708Sstevel */
1471708Sstevel Prom_node *
sun4v_walk(Sys_tree * tree,Prom_node * root,int id)1481708Sstevel sun4v_walk(Sys_tree *tree, Prom_node *root, int id)
1491708Sstevel {
1501708Sstevel register int curnode;
1511708Sstevel Prom_node *pnode;
1521708Sstevel char *name;
1531708Sstevel char *type;
1541708Sstevel char *compatible;
1551708Sstevel int board_node = 0;
1561708Sstevel
1571708Sstevel /* allocate a node for this level */
1581708Sstevel if ((pnode = (Prom_node *) malloc(sizeof (struct prom_node))) ==
1591708Sstevel NULL) {
1601708Sstevel perror("malloc");
1611708Sstevel exit(2); /* program errors cause exit 2 */
1621708Sstevel }
1631708Sstevel
1641708Sstevel /* assign parent Prom_node */
1651708Sstevel pnode->parent = root;
1661708Sstevel pnode->sibling = NULL;
1671708Sstevel pnode->child = NULL;
1681708Sstevel
1691708Sstevel /* read properties for this node */
1701708Sstevel dump_node(pnode);
1711708Sstevel
1721708Sstevel /*
1731708Sstevel * Place a node in a 'board' if it has 'board'-ness. The definition
1741708Sstevel * is that all nodes that are children of root should have a
1751708Sstevel * board# property. But the PROM tree does not exactly follow
1761708Sstevel * this. This is where we start hacking.
1771708Sstevel *
1781708Sstevel * PCI to PCI bridges also have the name "pci", but with different
1791708Sstevel * model property values. They should not be put under 'board'.
1801708Sstevel */
1811708Sstevel name = get_node_name(pnode);
1821708Sstevel type = get_node_type(pnode);
1831708Sstevel compatible = (char *)get_prop_val(find_prop(pnode, "compatible"));
1841708Sstevel
1851708Sstevel #ifdef DEBUG
1861708Sstevel if (name != NULL)
1871708Sstevel printf("name=%s ", name);
1881708Sstevel if (type != NULL)
1891708Sstevel printf("type=%s ", type);
1901708Sstevel printf("\n");
1911708Sstevel #endif
1921708Sstevel if (compatible == NULL)
1931708Sstevel compatible = "";
1941708Sstevel if (type == NULL)
1951708Sstevel type = "";
1961708Sstevel if (name != NULL) {
1971708Sstevel if (has_board_num(pnode)) {
1981708Sstevel add_node(tree, pnode);
1991708Sstevel board_node = 1;
2001708Sstevel #ifdef DEBUG
2011708Sstevel printf("ADDED BOARD name=%s type=%s compatible=%s\n",
2021708Sstevel name, type, compatible);
2031708Sstevel #endif
2041708Sstevel } else if (strcmp(type, "cpu") == 0) {
2051708Sstevel add_node(tree, pnode);
2061708Sstevel board_node = 1;
2071708Sstevel #ifdef DEBUG
2081708Sstevel printf("ADDED BOARD name=%s type=%s compatible=%s\n",
2091708Sstevel name, type, compatible);
2101708Sstevel #endif
2111708Sstevel }
2121708Sstevel #ifdef DEBUG
2131708Sstevel else
2141708Sstevel printf("node not added: name=%s type=%s\n", name, type);
2151708Sstevel #endif
2161708Sstevel }
2171708Sstevel
2181708Sstevel if (curnode = child(id)) {
2191708Sstevel pnode->child = sun4v_walk(tree, pnode, curnode);
2201708Sstevel }
2211708Sstevel
2221708Sstevel if (curnode = next(id)) {
2231708Sstevel if (board_node) {
2241708Sstevel return (sun4v_walk(tree, root, curnode));
2251708Sstevel } else {
2261708Sstevel pnode->sibling = sun4v_walk(tree, root, curnode);
2271708Sstevel }
2281708Sstevel }
2291708Sstevel
2301708Sstevel if (board_node) {
2311708Sstevel return (NULL);
2321708Sstevel } else {
2331708Sstevel return (pnode);
2341708Sstevel }
2351708Sstevel }
2361708Sstevel
2371708Sstevel /*
2381708Sstevel * search children to get the node by the nodename
2391708Sstevel */
240*3941Svenki picl_errno_t
sun4v_get_node_by_name(picl_nodehdl_t rooth,char * name,picl_nodehdl_t * nodeh)2411708Sstevel sun4v_get_node_by_name(picl_nodehdl_t rooth, char *name,
2421708Sstevel picl_nodehdl_t *nodeh)
2431708Sstevel {
2441708Sstevel picl_nodehdl_t childh;
2451708Sstevel int err;
2461708Sstevel char *nodename;
2471708Sstevel
2481708Sstevel nodename = alloca(strlen(name) + 1);
2491708Sstevel if (nodename == NULL)
2501708Sstevel return (PICL_FAILURE);
2511708Sstevel
2521708Sstevel err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh,
2531708Sstevel sizeof (picl_nodehdl_t));
2541708Sstevel
2551708Sstevel while (err == PICL_SUCCESS) {
2561708Sstevel err = picl_get_propval_by_name(childh, PICL_PROP_NAME,
2571708Sstevel nodename, (strlen(name) + 1));
2581708Sstevel if (err != PICL_SUCCESS) {
2591708Sstevel err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
2601708Sstevel &childh, sizeof (picl_nodehdl_t));
2611708Sstevel continue;
2621708Sstevel }
2631708Sstevel
2641708Sstevel if (strcmp(nodename, name) == 0) {
2651708Sstevel *nodeh = childh;
2661708Sstevel return (PICL_SUCCESS);
2671708Sstevel }
2681708Sstevel
2691708Sstevel err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
2701708Sstevel &childh, sizeof (picl_nodehdl_t));
2711708Sstevel }
2721708Sstevel
2731708Sstevel return (err);
2741708Sstevel }
2751708Sstevel
2761708Sstevel int
get_id(Prom_node * node)2771708Sstevel get_id(Prom_node *node)
2781708Sstevel {
2791708Sstevel #ifdef lint
2801708Sstevel node = node;
2811708Sstevel #endif
2821708Sstevel
2831708Sstevel /*
2841708Sstevel * This function is intentionally empty
2851708Sstevel */
2861708Sstevel return (0);
2871708Sstevel }
288