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