103831d35Sstevel /* 203831d35Sstevel * CDDL HEADER START 303831d35Sstevel * 403831d35Sstevel * The contents of this file are subject to the terms of the 5*0d63ce2bSvenki * Common Development and Distribution License (the "License"). 6*0d63ce2bSvenki * 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*0d63ce2bSvenki * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 2303831d35Sstevel * Use is subject to license terms. 2403831d35Sstevel */ 2503831d35Sstevel 2603831d35Sstevel #pragma ident "%Z%%M% %I% %E% SMI" 2703831d35Sstevel 2803831d35Sstevel #include <stdio.h> 2903831d35Sstevel #include <stdlib.h> 3003831d35Sstevel #include <string.h> 3103831d35Sstevel #include <fcntl.h> 3203831d35Sstevel #include <dirent.h> 3303831d35Sstevel #include <varargs.h> 3403831d35Sstevel #include <errno.h> 3503831d35Sstevel #include <unistd.h> 3603831d35Sstevel #include <alloca.h> 3703831d35Sstevel #include <sys/systeminfo.h> 3803831d35Sstevel #include <sys/utsname.h> 3903831d35Sstevel #include <sys/openpromio.h> 4003831d35Sstevel #include <kstat.h> 4103831d35Sstevel #include <libintl.h> 4203831d35Sstevel #include "pdevinfo.h" 4303831d35Sstevel #include "display.h" 4403831d35Sstevel #include "display_sun4v.h" 4503831d35Sstevel #include "libprtdiag.h" 4603831d35Sstevel 4703831d35Sstevel #if !defined(TEXT_DOMAIN) 4803831d35Sstevel #define TEXT_DOMAIN "SYS_TEST" 4903831d35Sstevel #endif 5003831d35Sstevel 5103831d35Sstevel /* 5203831d35Sstevel * Global variables 5303831d35Sstevel */ 5403831d35Sstevel char *progname; 5503831d35Sstevel char *promdev = "/dev/openprom"; 5603831d35Sstevel int print_flag = 1; 5703831d35Sstevel int logging = 0; 5803831d35Sstevel 5903831d35Sstevel /* 6003831d35Sstevel * This file represents the splitting out of some functionality 6103831d35Sstevel * of prtdiag due to the port to the sun4v platform. The PROM 6203831d35Sstevel * tree-walking functions which contain sun4v specifics were moved 6303831d35Sstevel * into this module. 6403831d35Sstevel */ 6503831d35Sstevel 6603831d35Sstevel extern int get_id(Prom_node *); 6703831d35Sstevel 6803831d35Sstevel /* Function prototypes */ 6903831d35Sstevel Prom_node *sun4v_walk(Sys_tree *, Prom_node *, int); 70*0d63ce2bSvenki picl_errno_t sun4v_get_node_by_name(picl_nodehdl_t, char *, picl_nodehdl_t *); 71*0d63ce2bSvenki 7203831d35Sstevel /* 7303831d35Sstevel * do_prominfo() is called from main() in usr/src/cmd/prtdiag/main.c 7403831d35Sstevel * 7503831d35Sstevel * This is the starting point for all platforms. However, this function 7603831d35Sstevel * can be overlayed by writing a do_prominfo() function 7703831d35Sstevel * in the libprtdiag_psr for a particular platform. 7803831d35Sstevel * 7903831d35Sstevel */ 8003831d35Sstevel int 8103831d35Sstevel do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag) 8203831d35Sstevel { 8303831d35Sstevel Sys_tree sys_tree; /* system information */ 8403831d35Sstevel Prom_node *root_node; /* root node of OBP device tree */ 8503831d35Sstevel picl_nodehdl_t rooth; /* root PICL node for IO display */ 8603831d35Sstevel picl_nodehdl_t plafh; /* Platform PICL node for IO display */ 8703831d35Sstevel 88*0d63ce2bSvenki picl_errno_t err; 8903831d35Sstevel 9003831d35Sstevel err = picl_initialize(); 9103831d35Sstevel if (err != PICL_SUCCESS) { 9203831d35Sstevel (void) fprintf(stderr, EM_INIT_FAIL, picl_strerror(err)); 9303831d35Sstevel exit(1); 9403831d35Sstevel } 9503831d35Sstevel 9603831d35Sstevel /* set the global flags */ 9703831d35Sstevel progname = pgname; 9803831d35Sstevel logging = log_flag; 9903831d35Sstevel print_flag = prt_flag; 10003831d35Sstevel 10103831d35Sstevel /* set the the system tree fields */ 10203831d35Sstevel sys_tree.sys_mem = NULL; 10303831d35Sstevel sys_tree.boards = NULL; 10403831d35Sstevel sys_tree.bd_list = NULL; 10503831d35Sstevel sys_tree.board_cnt = 0; 10603831d35Sstevel 10703831d35Sstevel if (promopen(O_RDONLY)) { 10803831d35Sstevel exit(_error(dgettext(TEXT_DOMAIN, "openeepr device " 10903831d35Sstevel "open failed"))); 11003831d35Sstevel } 11103831d35Sstevel 11203831d35Sstevel if (is_openprom() == 0) { 11303831d35Sstevel (void) fprintf(stderr, "%s", 11403831d35Sstevel dgettext(TEXT_DOMAIN, "System architecture " 11503831d35Sstevel "does not support this option of this " 11603831d35Sstevel "command.\n")); 11703831d35Sstevel return (2); 11803831d35Sstevel } 11903831d35Sstevel 12003831d35Sstevel if (next(0) == 0) { 12103831d35Sstevel return (2); 12203831d35Sstevel } 12303831d35Sstevel 12403831d35Sstevel root_node = sun4v_walk(&sys_tree, NULL, next(0)); 12503831d35Sstevel promclose(); 12603831d35Sstevel 12703831d35Sstevel err = picl_get_root(&rooth); 12803831d35Sstevel if (err != PICL_SUCCESS) { 12903831d35Sstevel (void) fprintf(stderr, EM_GET_ROOT_FAIL, picl_strerror(err)); 13003831d35Sstevel exit(1); 13103831d35Sstevel } 13203831d35Sstevel 13303831d35Sstevel err = sun4v_get_node_by_name(rooth, PICL_NODE_PLATFORM, &plafh); 13403831d35Sstevel if (err != PICL_SUCCESS) 13503831d35Sstevel return (err); 13603831d35Sstevel 13703831d35Sstevel return (sun4v_display(&sys_tree, root_node, syserrlog, plafh)); 13803831d35Sstevel 13903831d35Sstevel } 14003831d35Sstevel 14103831d35Sstevel /* 14203831d35Sstevel * sun4v_Walk the PROM device tree and build the system tree and root tree. 14303831d35Sstevel * Nodes that have a board number property are placed in the board 14403831d35Sstevel * structures for easier processing later. Child nodes are placed 14503831d35Sstevel * under their parents. 14603831d35Sstevel */ 14703831d35Sstevel Prom_node * 14803831d35Sstevel sun4v_walk(Sys_tree *tree, Prom_node *root, int id) 14903831d35Sstevel { 15003831d35Sstevel register int curnode; 15103831d35Sstevel Prom_node *pnode; 15203831d35Sstevel char *name; 15303831d35Sstevel char *type; 15403831d35Sstevel char *compatible; 15503831d35Sstevel int board_node = 0; 15603831d35Sstevel 15703831d35Sstevel /* allocate a node for this level */ 15803831d35Sstevel if ((pnode = (Prom_node *) malloc(sizeof (struct prom_node))) == 15903831d35Sstevel NULL) { 16003831d35Sstevel perror("malloc"); 16103831d35Sstevel exit(2); /* program errors cause exit 2 */ 16203831d35Sstevel } 16303831d35Sstevel 16403831d35Sstevel /* assign parent Prom_node */ 16503831d35Sstevel pnode->parent = root; 16603831d35Sstevel pnode->sibling = NULL; 16703831d35Sstevel pnode->child = NULL; 16803831d35Sstevel 16903831d35Sstevel /* read properties for this node */ 17003831d35Sstevel dump_node(pnode); 17103831d35Sstevel 17203831d35Sstevel /* 17303831d35Sstevel * Place a node in a 'board' if it has 'board'-ness. The definition 17403831d35Sstevel * is that all nodes that are children of root should have a 17503831d35Sstevel * board# property. But the PROM tree does not exactly follow 17603831d35Sstevel * this. This is where we start hacking. 17703831d35Sstevel * 17803831d35Sstevel * PCI to PCI bridges also have the name "pci", but with different 17903831d35Sstevel * model property values. They should not be put under 'board'. 18003831d35Sstevel */ 18103831d35Sstevel name = get_node_name(pnode); 18203831d35Sstevel type = get_node_type(pnode); 18303831d35Sstevel compatible = (char *)get_prop_val(find_prop(pnode, "compatible")); 18403831d35Sstevel 18503831d35Sstevel #ifdef DEBUG 18603831d35Sstevel if (name != NULL) 18703831d35Sstevel printf("name=%s ", name); 18803831d35Sstevel if (type != NULL) 18903831d35Sstevel printf("type=%s ", type); 19003831d35Sstevel printf("\n"); 19103831d35Sstevel #endif 19203831d35Sstevel if (compatible == NULL) 19303831d35Sstevel compatible = ""; 19403831d35Sstevel if (type == NULL) 19503831d35Sstevel type = ""; 19603831d35Sstevel if (name != NULL) { 19703831d35Sstevel if (has_board_num(pnode)) { 19803831d35Sstevel add_node(tree, pnode); 19903831d35Sstevel board_node = 1; 20003831d35Sstevel #ifdef DEBUG 20103831d35Sstevel printf("ADDED BOARD name=%s type=%s compatible=%s\n", 20203831d35Sstevel name, type, compatible); 20303831d35Sstevel #endif 20403831d35Sstevel } else if (strcmp(type, "cpu") == 0) { 20503831d35Sstevel add_node(tree, pnode); 20603831d35Sstevel board_node = 1; 20703831d35Sstevel #ifdef DEBUG 20803831d35Sstevel printf("ADDED BOARD name=%s type=%s compatible=%s\n", 20903831d35Sstevel name, type, compatible); 21003831d35Sstevel #endif 21103831d35Sstevel } 21203831d35Sstevel #ifdef DEBUG 21303831d35Sstevel else 21403831d35Sstevel printf("node not added: name=%s type=%s\n", name, type); 21503831d35Sstevel #endif 21603831d35Sstevel } 21703831d35Sstevel 21803831d35Sstevel if (curnode = child(id)) { 21903831d35Sstevel pnode->child = sun4v_walk(tree, pnode, curnode); 22003831d35Sstevel } 22103831d35Sstevel 22203831d35Sstevel if (curnode = next(id)) { 22303831d35Sstevel if (board_node) { 22403831d35Sstevel return (sun4v_walk(tree, root, curnode)); 22503831d35Sstevel } else { 22603831d35Sstevel pnode->sibling = sun4v_walk(tree, root, curnode); 22703831d35Sstevel } 22803831d35Sstevel } 22903831d35Sstevel 23003831d35Sstevel if (board_node) { 23103831d35Sstevel return (NULL); 23203831d35Sstevel } else { 23303831d35Sstevel return (pnode); 23403831d35Sstevel } 23503831d35Sstevel } 23603831d35Sstevel 23703831d35Sstevel /* 23803831d35Sstevel * search children to get the node by the nodename 23903831d35Sstevel */ 240*0d63ce2bSvenki picl_errno_t 24103831d35Sstevel sun4v_get_node_by_name(picl_nodehdl_t rooth, char *name, 24203831d35Sstevel picl_nodehdl_t *nodeh) 24303831d35Sstevel { 24403831d35Sstevel picl_nodehdl_t childh; 24503831d35Sstevel int err; 24603831d35Sstevel char *nodename; 24703831d35Sstevel 24803831d35Sstevel nodename = alloca(strlen(name) + 1); 24903831d35Sstevel if (nodename == NULL) 25003831d35Sstevel return (PICL_FAILURE); 25103831d35Sstevel 25203831d35Sstevel err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh, 25303831d35Sstevel sizeof (picl_nodehdl_t)); 25403831d35Sstevel 25503831d35Sstevel while (err == PICL_SUCCESS) { 25603831d35Sstevel err = picl_get_propval_by_name(childh, PICL_PROP_NAME, 25703831d35Sstevel nodename, (strlen(name) + 1)); 25803831d35Sstevel if (err != PICL_SUCCESS) { 25903831d35Sstevel err = picl_get_propval_by_name(childh, PICL_PROP_PEER, 26003831d35Sstevel &childh, sizeof (picl_nodehdl_t)); 26103831d35Sstevel continue; 26203831d35Sstevel } 26303831d35Sstevel 26403831d35Sstevel if (strcmp(nodename, name) == 0) { 26503831d35Sstevel *nodeh = childh; 26603831d35Sstevel return (PICL_SUCCESS); 26703831d35Sstevel } 26803831d35Sstevel 26903831d35Sstevel err = picl_get_propval_by_name(childh, PICL_PROP_PEER, 27003831d35Sstevel &childh, sizeof (picl_nodehdl_t)); 27103831d35Sstevel } 27203831d35Sstevel 27303831d35Sstevel return (err); 27403831d35Sstevel } 27503831d35Sstevel 27603831d35Sstevel int 27703831d35Sstevel get_id(Prom_node *node) 27803831d35Sstevel { 27903831d35Sstevel #ifdef lint 28003831d35Sstevel node = node; 28103831d35Sstevel #endif 28203831d35Sstevel 28303831d35Sstevel /* 28403831d35Sstevel * This function is intentionally empty 28503831d35Sstevel */ 28603831d35Sstevel return (0); 28703831d35Sstevel } 288