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