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