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 1999-2003 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 <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 "pdevinfo_sun4u.h" 44 #include "display.h" 45 #include "display_sun4u.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 sun4u platform. The PROM 63 * tree-walking functions which contain sun4u specifics were moved 64 * into this module. 65 */ 66 67 extern int get_id(Prom_node *); 68 69 /* Function prototypes */ 70 Prom_node *walk(Sys_tree *, Prom_node *, int); 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 struct system_kstat_data sys_kstat; /* kstats for non-OBP data */ 86 87 88 /* set the global flags */ 89 progname = pgname; 90 logging = log_flag; 91 print_flag = prt_flag; 92 93 /* set the the system tree fields */ 94 sys_tree.sys_mem = NULL; 95 sys_tree.boards = NULL; 96 sys_tree.bd_list = NULL; 97 sys_tree.board_cnt = 0; 98 99 if (promopen(O_RDONLY)) { 100 exit(_error(dgettext(TEXT_DOMAIN, "openeepr device " 101 "open failed"))); 102 } 103 104 if (is_openprom() == 0) { 105 (void) fprintf(stderr, "%s", 106 dgettext(TEXT_DOMAIN, "System architecture " 107 "does not support this option of this " 108 "command.\n")); 109 return (2); 110 } 111 112 if (next(0) == 0) { 113 return (2); 114 } 115 116 root_node = walk(&sys_tree, NULL, next(0)); 117 promclose(); 118 119 /* resolve the board types now */ 120 resolve_board_types(&sys_tree); 121 122 read_sun4u_kstats(&sys_tree, &sys_kstat); 123 124 return (display(&sys_tree, root_node, &sys_kstat, syserrlog)); 125 126 } 127 128 int 129 get_id(Prom_node *node) 130 { 131 int *value; 132 133 /* 134 * check for upa-portid on UI and UII systems 135 */ 136 if ((value = (int *)get_prop_val(find_prop(node, "upa-portid"))) 137 == NULL) { 138 /* 139 * check for portid on UIII systems 140 */ 141 if ((value = (int *)get_prop_val(find_prop(node, "portid"))) 142 == NULL) { 143 return (-1); 144 } 145 } 146 return (*value); 147 } 148 149 150 151 /* 152 * Walk the PROM device tree and build the system tree and root tree. 153 * Nodes that have a board number property are placed in the board 154 * structures for easier processing later. Child nodes are placed 155 * under their parents. ffb (Fusion Frame Buffer) nodes are handled 156 * specially, because they do not contain board number properties. 157 * This was requested from OBP, but was not granted. So this code 158 * must parse the MID of the FFB to find the board#. 159 * 160 */ 161 Prom_node * 162 walk(Sys_tree *tree, Prom_node *root, int id) 163 { 164 register int curnode; 165 Prom_node *pnode; 166 char *name; 167 char *type; 168 char *model; 169 int board_node = 0; 170 171 /* allocate a node for this level */ 172 if ((pnode = (Prom_node *) malloc(sizeof (struct prom_node))) == 173 NULL) { 174 perror("malloc"); 175 exit(2); /* program errors cause exit 2 */ 176 } 177 178 /* assign parent Prom_node */ 179 pnode->parent = root; 180 pnode->sibling = NULL; 181 pnode->child = NULL; 182 183 /* read properties for this node */ 184 dump_node(pnode); 185 186 /* 187 * Place a node in a 'board' if it has 'board'-ness. The definition 188 * is that all nodes that are children of root should have a 189 * board# property. But the PROM tree does not exactly follow 190 * this. This is where we start hacking. The name 'ffb' can 191 * change, so watch out for this. 192 * 193 * The UltraSPARC, sbus, pci and ffb nodes will exit in 194 * the desktops and will not have board# properties. These 195 * cases must be handled here. 196 * 197 * PCI to PCI bridges also have the name "pci", but with different 198 * model property values. They should not be put under 'board'. 199 */ 200 name = get_node_name(pnode); 201 type = get_node_type(pnode); 202 model = (char *)get_prop_val(find_prop(pnode, "model")); 203 #ifdef DEBUG 204 if (name != NULL) 205 printf("name=%s ", name); 206 if (type != NULL) 207 printf("type=%s ", type); 208 if (model != NULL) 209 printf("model=%s", model); 210 printf("\n"); 211 #endif 212 if (model == NULL) 213 model = ""; 214 if (type == NULL) 215 type = ""; 216 if (name != NULL) { 217 if (has_board_num(pnode)) { 218 add_node(tree, pnode); 219 board_node = 1; 220 #ifdef DEBUG 221 printf("ADDED BOARD name=%s type=%s model=%s\n", 222 name, type, model); 223 #endif 224 } else if ((strcmp(name, FFB_NAME) == 0) || 225 (strcmp(name, AFB_NAME) == 0) || 226 (strcmp(type, "cpu") == 0) || 227 228 ((strcmp(type, "memory-controller") == 0) && 229 (strcmp(name, "ac") != 0)) || 230 231 ((strcmp(name, "pci") == 0) && 232 (strcmp(model, "SUNW,psycho") == 0)) || 233 234 ((strcmp(name, "pci") == 0) && 235 (strcmp(model, "SUNW,sabre") == 0)) || 236 237 ((strcmp(name, "pci") == 0) && 238 (strcmp(model, "SUNW,schizo") == 0)) || 239 240 ((strcmp(name, "pci") == 0) && 241 (strcmp(model, "SUNW,xmits") == 0)) || 242 243 (strcmp(name, "counter-timer") == 0) || 244 (strcmp(name, "sbus") == 0)) { 245 add_node(tree, pnode); 246 board_node = 1; 247 #ifdef DEBUG 248 printf("ADDED BOARD name=%s type=%s model=%s\n", 249 name, type, model); 250 #endif 251 } 252 #ifdef DEBUG 253 else 254 printf("node not added: name=%s type=%s\n", name, type); 255 #endif 256 } 257 258 if (curnode = child(id)) { 259 pnode->child = walk(tree, pnode, curnode); 260 } 261 262 if (curnode = next(id)) { 263 if (board_node) { 264 return (walk(tree, root, curnode)); 265 } else { 266 pnode->sibling = walk(tree, root, curnode); 267 } 268 } 269 270 if (board_node) { 271 return (NULL); 272 } else { 273 return (pnode); 274 } 275 } 276