1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21/* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26#pragma ident "%Z%%M% %I% %E% SMI" 27 28#include <stdio.h> 29#include <stdlib.h> 30#include <string.h> 31#include <fcntl.h> 32#include <dirent.h> 33#include <varargs.h> 34#include <errno.h> 35#include <unistd.h> 36#include <alloca.h> 37#include <sys/systeminfo.h> 38#include <sys/utsname.h> 39#include <sys/openpromio.h> 40#include <kstat.h> 41#include <libintl.h> 42#include "pdevinfo.h" 43#include "display.h" 44#include "display_sun4v.h" 45#include "libprtdiag.h" 46 47#if !defined(TEXT_DOMAIN) 48#define TEXT_DOMAIN "SYS_TEST" 49#endif 50 51/* 52 * Global variables 53 */ 54char *progname; 55char *promdev = "/dev/openprom"; 56int print_flag = 1; 57int logging = 0; 58 59/* 60 * This file represents the splitting out of some functionality 61 * of prtdiag due to the port to the sun4v platform. The PROM 62 * tree-walking functions which contain sun4v specifics were moved 63 * into this module. 64 */ 65 66extern int get_id(Prom_node *); 67 68/* Function prototypes */ 69Prom_node *sun4v_walk(Sys_tree *, Prom_node *, int); 70picl_errno_t sun4v_get_node_by_name(picl_nodehdl_t, char *, picl_nodehdl_t *); 71 72/* 73 * do_prominfo() is called from main() in usr/src/cmd/prtdiag/main.c 74 * 75 * This is the starting point for all platforms. However, this function 76 * can be overlayed by writing a do_prominfo() function 77 * in the libprtdiag_psr for a particular platform. 78 * 79 */ 80int 81do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag) 82{ 83 Sys_tree sys_tree; /* system information */ 84 Prom_node *root_node; /* root node of OBP device tree */ 85 picl_nodehdl_t rooth; /* root PICL node for IO display */ 86 picl_nodehdl_t plafh; /* Platform PICL node for IO display */ 87 88 picl_errno_t err; 89 90 err = picl_initialize(); 91 if (err != PICL_SUCCESS) { 92 (void) fprintf(stderr, EM_INIT_FAIL, picl_strerror(err)); 93 exit(1); 94 } 95 96 /* set the global flags */ 97 progname = pgname; 98 logging = log_flag; 99 print_flag = prt_flag; 100 101 /* set the the system tree fields */ 102 sys_tree.sys_mem = NULL; 103 sys_tree.boards = NULL; 104 sys_tree.bd_list = NULL; 105 sys_tree.board_cnt = 0; 106 107 if (promopen(O_RDONLY)) { 108 exit(_error(dgettext(TEXT_DOMAIN, "openeepr device " 109 "open failed"))); 110 } 111 112 if (is_openprom() == 0) { 113 (void) fprintf(stderr, "%s", 114 dgettext(TEXT_DOMAIN, "System architecture " 115 "does not support this option of this " 116 "command.\n")); 117 return (2); 118 } 119 120 if (next(0) == 0) { 121 return (2); 122 } 123 124 root_node = sun4v_walk(&sys_tree, NULL, next(0)); 125 promclose(); 126 127 err = picl_get_root(&rooth); 128 if (err != PICL_SUCCESS) { 129 (void) fprintf(stderr, EM_GET_ROOT_FAIL, picl_strerror(err)); 130 exit(1); 131 } 132 133 err = sun4v_get_node_by_name(rooth, PICL_NODE_PLATFORM, &plafh); 134 if (err != PICL_SUCCESS) 135 return (err); 136 137 return (sun4v_display(&sys_tree, root_node, syserrlog, plafh)); 138 139} 140 141/* 142 * sun4v_Walk the PROM device tree and build the system tree and root tree. 143 * Nodes that have a board number property are placed in the board 144 * structures for easier processing later. Child nodes are placed 145 * under their parents. 146 */ 147Prom_node * 148sun4v_walk(Sys_tree *tree, Prom_node *root, int id) 149{ 150 register int curnode; 151 Prom_node *pnode; 152 char *name; 153 char *type; 154 char *compatible; 155 int board_node = 0; 156 157 /* allocate a node for this level */ 158 if ((pnode = (Prom_node *) malloc(sizeof (struct prom_node))) == 159 NULL) { 160 perror("malloc"); 161 exit(2); /* program errors cause exit 2 */ 162 } 163 164 /* assign parent Prom_node */ 165 pnode->parent = root; 166 pnode->sibling = NULL; 167 pnode->child = NULL; 168 169 /* read properties for this node */ 170 dump_node(pnode); 171 172 /* 173 * Place a node in a 'board' if it has 'board'-ness. The definition 174 * is that all nodes that are children of root should have a 175 * board# property. But the PROM tree does not exactly follow 176 * this. This is where we start hacking. 177 * 178 * PCI to PCI bridges also have the name "pci", but with different 179 * model property values. They should not be put under 'board'. 180 */ 181 name = get_node_name(pnode); 182 type = get_node_type(pnode); 183 compatible = (char *)get_prop_val(find_prop(pnode, "compatible")); 184 185#ifdef DEBUG 186 if (name != NULL) 187 printf("name=%s ", name); 188 if (type != NULL) 189 printf("type=%s ", type); 190 printf("\n"); 191#endif 192 if (compatible == NULL) 193 compatible = ""; 194 if (type == NULL) 195 type = ""; 196 if (name != NULL) { 197 if (has_board_num(pnode)) { 198 add_node(tree, pnode); 199 board_node = 1; 200#ifdef DEBUG 201 printf("ADDED BOARD name=%s type=%s compatible=%s\n", 202 name, type, compatible); 203#endif 204 } else if (strcmp(type, "cpu") == 0) { 205 add_node(tree, pnode); 206 board_node = 1; 207#ifdef DEBUG 208 printf("ADDED BOARD name=%s type=%s compatible=%s\n", 209 name, type, compatible); 210#endif 211 } 212#ifdef DEBUG 213 else 214 printf("node not added: name=%s type=%s\n", name, type); 215#endif 216 } 217 218 if (curnode = child(id)) { 219 pnode->child = sun4v_walk(tree, pnode, curnode); 220 } 221 222 if (curnode = next(id)) { 223 if (board_node) { 224 return (sun4v_walk(tree, root, curnode)); 225 } else { 226 pnode->sibling = sun4v_walk(tree, root, curnode); 227 } 228 } 229 230 if (board_node) { 231 return (NULL); 232 } else { 233 return (pnode); 234 } 235} 236 237/* 238 * search children to get the node by the nodename 239 */ 240picl_errno_t 241sun4v_get_node_by_name(picl_nodehdl_t rooth, char *name, 242 picl_nodehdl_t *nodeh) 243{ 244 picl_nodehdl_t childh; 245 int err; 246 char *nodename; 247 248 nodename = alloca(strlen(name) + 1); 249 if (nodename == NULL) 250 return (PICL_FAILURE); 251 252 err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh, 253 sizeof (picl_nodehdl_t)); 254 255 while (err == PICL_SUCCESS) { 256 err = picl_get_propval_by_name(childh, PICL_PROP_NAME, 257 nodename, (strlen(name) + 1)); 258 if (err != PICL_SUCCESS) { 259 err = picl_get_propval_by_name(childh, PICL_PROP_PEER, 260 &childh, sizeof (picl_nodehdl_t)); 261 continue; 262 } 263 264 if (strcmp(nodename, name) == 0) { 265 *nodeh = childh; 266 return (PICL_SUCCESS); 267 } 268 269 err = picl_get_propval_by_name(childh, PICL_PROP_PEER, 270 &childh, sizeof (picl_nodehdl_t)); 271 } 272 273 return (err); 274} 275 276int 277get_id(Prom_node *node) 278{ 279#ifdef lint 280 node = node; 281#endif 282 283 /* 284 * This function is intentionally empty 285 */ 286 return (0); 287} 288