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
do_prominfo(int syserrlog,char * pgname,int log_flag,int prt_flag)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 *
sun4v_walk(Sys_tree * tree,Prom_node * root,int id)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
sun4v_get_node_by_name(picl_nodehdl_t rooth,char * name,picl_nodehdl_t * nodeh)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
get_id(Prom_node * node)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