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 */ 54 char *progname; 55 char *promdev = "/dev/openprom"; 56 int print_flag = 1; 57 int 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 66 extern int get_id(Prom_node *); 67 68 /* Function prototypes */ 69 Prom_node *sun4v_walk(Sys_tree *, Prom_node *, int); 70 picl_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 */ 80 int 81 do_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 */ 147 Prom_node * 148 sun4v_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 */ 240 picl_errno_t 241 sun4v_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 276 int 277 get_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