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