xref: /titanic_50/usr/src/cmd/prtconf/prt_xxx.c (revision c2e7b48d563d0e56b74d853118918af352e75cbb)
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 2005 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 <stddef.h>
31 #include <fcntl.h>
32 #include <string.h>
33 #include <libdevinfo.h>
34 #include <sys/pctypes.h>
35 #include <sys/pcmcia.h>
36 #include <sys/utsname.h>
37 #include <sys/avintr.h>
38 
39 #include "prtconf.h"
40 
41 struct priv_data {
42 	char *drv_name;		/* parent name */
43 	void (*pd_print)(uintptr_t, int);	/* print function */
44 };
45 
46 extern void indent_to_level();
47 static void obio_printregs(struct regspec *, int);
48 static void obio_printranges(struct rangespec *, int);
49 static void obio_printintr(struct intrspec *, int);
50 static void obio_print(uintptr_t, int);
51 static void pcmcia_printregs(struct pcm_regs *, int);
52 static void pcmcia_printintr(struct intrspec *, int);
53 static void pcmcia_print(uintptr_t, int);
54 static void sbus_print(uintptr_t, int);
55 static struct priv_data *match_priv_data(di_node_t);
56 
57 /*
58  * This is a hardcoded list of drivers we print parent private
59  * data as of Solaris 7.
60  */
61 static struct di_priv_format ppd_format[] = {
62 	{
63 		/*
64 		 * obio format: applies the following list
65 		 * of nexus drivers. Note that obio driver
66 		 * went away with sun4m.
67 		 */
68 		"central dma ebus fhc isa pci pci_pci rootnex",
69 		sizeof (struct ddi_parent_private_data),
70 
71 		sizeof (struct regspec),		/* first pointer */
72 		offsetof(struct ddi_parent_private_data, par_reg),
73 		offsetof(struct ddi_parent_private_data, par_nreg),
74 
75 		sizeof (struct intrspec),		/* second pointer */
76 		offsetof(struct ddi_parent_private_data, par_intr),
77 		offsetof(struct ddi_parent_private_data, par_nintr),
78 
79 		sizeof (struct rangespec),		/* third pointer */
80 		offsetof(struct ddi_parent_private_data, par_rng),
81 		offsetof(struct ddi_parent_private_data, par_nrng),
82 
83 		0, 0, 0,	/* no more pointers */
84 		0, 0, 0
85 	},
86 
87 	{	/* pcmcia format */
88 		"pcic stp4020",
89 		sizeof (struct pcmcia_parent_private),
90 
91 		sizeof (struct pcm_regs),		/* first pointer */
92 		offsetof(struct pcmcia_parent_private, ppd_reg),
93 		offsetof(struct pcmcia_parent_private, ppd_nreg),
94 
95 		sizeof (struct intrspec),		/* second pointer */
96 		offsetof(struct pcmcia_parent_private, ppd_intrspec),
97 		offsetof(struct pcmcia_parent_private, ppd_intr),
98 
99 		0, 0, 0,	/* no more pointers */
100 		0, 0, 0,
101 		0, 0, 0
102 	},
103 
104 	{	/* sbus format--it's different on sun4u!! */
105 		"sbus",
106 		sizeof (struct ddi_parent_private_data),
107 
108 		sizeof (struct regspec),		/* first pointer */
109 		offsetof(struct ddi_parent_private_data, par_reg),
110 		offsetof(struct ddi_parent_private_data, par_nreg),
111 
112 		sizeof (struct intrspec),		/* second pointer */
113 		offsetof(struct ddi_parent_private_data, par_intr),
114 		offsetof(struct ddi_parent_private_data, par_nintr),
115 
116 		sizeof (struct rangespec),		/* third pointer */
117 		offsetof(struct ddi_parent_private_data, par_rng),
118 		offsetof(struct ddi_parent_private_data, par_nrng),
119 
120 		0, 0, 0,	/* no more pointers */
121 		0, 0, 0
122 	}
123 };
124 
125 static struct priv_data prt_priv_data[] = {
126 	{ ppd_format[0].drv_name, obio_print},
127 	{ ppd_format[1].drv_name, pcmcia_print},
128 	{ ppd_format[2].drv_name, sbus_print}
129 };
130 
131 static int nprt_priv_data = sizeof (prt_priv_data)/sizeof (struct priv_data);
132 
133 void
134 init_priv_data(struct di_priv_data *fetch)
135 {
136 	/* no driver private data */
137 	fetch->version = DI_PRIVDATA_VERSION_0;
138 	fetch->n_driver = 0;
139 	fetch->driver = NULL;
140 
141 	fetch->n_parent = nprt_priv_data;
142 	fetch->parent = ppd_format;
143 }
144 
145 static void
146 obio_printregs(struct regspec *rp, int ilev)
147 {
148 	indent_to_level(ilev);
149 	(void) printf("    Bus Type=0x%x, Address=0x%x, Size=0x%x\n",
150 	    rp->regspec_bustype, rp->regspec_addr, rp->regspec_size);
151 }
152 
153 static void
154 obio_printranges(struct rangespec *rp, int ilev)
155 {
156 	indent_to_level(ilev);
157 	(void) printf("    Ch: %.2x,%.8x Pa: %.2x,%.8x, Sz: %x\n",
158 	    rp->rng_cbustype, rp->rng_coffset,
159 	    rp->rng_bustype, rp->rng_offset,
160 	    rp->rng_size);
161 }
162 
163 static void
164 obio_printintr(struct intrspec *ip, int ilev)
165 {
166 	indent_to_level(ilev);
167 	(void) printf("    Interrupt Priority=0x%x (ipl %d)",
168 	    ip->intrspec_pri, INT_IPL(ip->intrspec_pri));
169 	if (ip->intrspec_vec)
170 		(void) printf(", vector=0x%x (%d)",
171 		    ip->intrspec_vec, ip->intrspec_vec);
172 	(void) printf("\n");
173 }
174 
175 static void
176 obio_print(uintptr_t data, int ilev)
177 {
178 	int i, nreg, nrng, nintr;
179 	struct ddi_parent_private_data *dp;
180 	struct regspec *reg;
181 	struct intrspec *intr;
182 	struct rangespec *rng;
183 
184 	dp = (struct ddi_parent_private_data *)data;
185 #ifdef DEBUG
186 	dprintf("obio parent private data: nreg = 0x%x offset = 0x%x"
187 	    " nintr = 0x%x offset = 0x%x nrng = 0x%x offset = %x\n",
188 	    dp->par_nreg, *((di_off_t *)(&dp->par_reg)),
189 	    dp->par_nintr, *((di_off_t *)(&dp->par_intr)),
190 	    dp->par_nrng, *((di_off_t *)(&dp->par_rng)));
191 #endif /* DEBUG */
192 	nreg = dp->par_nreg;
193 	nintr = dp->par_nintr;
194 	nrng = dp->par_nrng;
195 
196 	/*
197 	 * All pointers are translated to di_off_t by the devinfo driver.
198 	 * This is a private agreement between libdevinfo and prtconf.
199 	 */
200 	if (nreg != 0) {
201 		indent_to_level(ilev);
202 		(void) printf("Register Specifications:\n");
203 
204 		reg = (struct regspec *)(data + *(di_off_t *)(&dp->par_reg));
205 		for (i = 0; i < nreg; ++i)
206 			obio_printregs(reg + i, ilev);
207 	}
208 
209 	if (nrng != 0) {
210 		indent_to_level(ilev);
211 		(void) printf("Range Specifications:\n");
212 
213 		rng = (struct rangespec *)(data + *(di_off_t *)(&dp->par_rng));
214 		for (i = 0; i < nrng; ++i)
215 			obio_printranges(rng + i, ilev);
216 	}
217 
218 	if (nintr != 0) {
219 		indent_to_level(ilev);
220 		(void) printf("Interrupt Specifications:\n");
221 
222 		intr = (struct intrspec *)(data + *(di_off_t *)(&dp->par_intr));
223 		for (i = 0; i < nintr; ++i)
224 			obio_printintr(intr + i, ilev);
225 	}
226 }
227 
228 static void
229 pcmcia_printregs(struct pcm_regs *rp, int ilev)
230 {
231 	indent_to_level(ilev);
232 	(void) printf("    Phys hi=0x%x, Phys lo=0x%x, Phys len=%x\n",
233 	    rp->phys_hi, rp->phys_lo, rp->phys_len);
234 }
235 
236 static void
237 pcmcia_printintr(struct intrspec *ip, int ilev)
238 {
239 	obio_printintr(ip, ilev);
240 }
241 
242 static void
243 pcmcia_print(uintptr_t data, int ilev)
244 {
245 	int i, nreg, nintr;
246 	struct pcmcia_parent_private *dp;
247 	struct pcm_regs *reg;
248 	struct intrspec *intr;
249 
250 	dp = (struct pcmcia_parent_private *)data;
251 #ifdef DEBUG
252 	dprintf("pcmcia parent private data: nreg = 0x%x offset = 0x%x"
253 	    " intr = 0x%x offset = %x\n",
254 	    dp->ppd_nreg, *(di_off_t *)(&dp->ppd_reg),
255 	    dp->ppd_intr, *(di_off_t *)(&dp->ppd_intrspec));
256 #endif /* DEBUG */
257 	nreg = dp->ppd_nreg;
258 	nintr = dp->ppd_intr;
259 
260 	/*
261 	 * All pointers are translated to di_off_t by the devinfo driver.
262 	 * This is a private agreement between libdevinfo and prtconf.
263 	 */
264 	if (nreg != 0)  {
265 		indent_to_level(ilev);
266 		(void) printf("Register Specifications:\n");
267 
268 		reg = (struct pcm_regs *)(data + *(di_off_t *)(&dp->ppd_reg));
269 		for (i = 0; i < nreg; ++i)
270 			pcmcia_printregs(reg + i, ilev);
271 	}
272 
273 	if (nintr != 0)  {
274 		indent_to_level(ilev);
275 		(void) printf("Interrupt Specifications:\n");
276 
277 		intr = (struct intrspec *)
278 		    (data + *(di_off_t *)(&dp->ppd_intrspec));
279 		for (i = 0; i < nintr; ++i)
280 			pcmcia_printintr(intr + i, ilev);
281 	}
282 }
283 
284 static void
285 sbus_print(uintptr_t data, int ilev)
286 {
287 	int i, nreg, nrng, nintr;
288 	struct ddi_parent_private_data *dp;
289 	struct regspec *reg;
290 	struct intrspec *intr;
291 	struct rangespec *rng;
292 
293 	dp = (struct ddi_parent_private_data *)data;
294 #ifdef DEBUG
295 	dprintf("sbus parent private data: nreg = 0x%x offset = 0x%x"
296 	    " nintr = 0x%x offset = 0x%x nrng = 0x%x offset = %x\n",
297 	    dp->par_nreg, *((di_off_t *)(&dp->par_reg)),
298 	    dp->par_nintr, *((di_off_t *)(&dp->par_intr)),
299 	    dp->par_nrng, *((di_off_t *)(&dp->par_rng)));
300 #endif /* DEBUG */
301 	nreg = dp->par_nreg;
302 	nintr = dp->par_nintr;
303 	nrng = dp->par_nrng;
304 
305 	/*
306 	 * All pointers are translated to di_off_t by the devinfo driver.
307 	 * This is a private agreement between libdevinfo and prtconf.
308 	 */
309 	if (nreg != 0) {
310 		indent_to_level(ilev);
311 		(void) printf("Register Specifications:\n");
312 
313 		reg = (struct regspec *)(data + *(di_off_t *)(&dp->par_reg));
314 		for (i = 0; i < nreg; ++i)
315 			obio_printregs(reg + i, ilev);
316 	}
317 
318 
319 	if (nrng != 0) {
320 		indent_to_level(ilev);
321 		(void) printf("Range Specifications:\n");
322 
323 		rng = (struct rangespec *)(data + *(di_off_t *)(&dp->par_rng));
324 		for (i = 0; i < nrng; ++i)
325 			obio_printranges(rng + i, ilev);
326 	}
327 
328 	/*
329 	 * To print interrupt property for children of sbus on sun4u requires
330 	 * definitions in sysiosbus.h.
331 	 *
332 	 * We can't #include <sys/sysiosbus.h> to have the build work on
333 	 * non sun4u machines. It's not right either to
334 	 *	#include "../../uts/sun4u/sys/sysiosbus.h"
335 	 * As a result, we will not print the information.
336 	 */
337 	if ((nintr != 0) && (strcmp(opts.o_uts.machine, "sun4u") != 0)) {
338 		indent_to_level(ilev);
339 		(void) printf("Interrupt Specifications:\n");
340 
341 		for (i = 0; i < nintr; ++i) {
342 			intr = (struct intrspec *)
343 			    (data + *(di_off_t *)(&dp->par_intr));
344 			obio_printintr(intr + i, ilev);
345 		}
346 	}
347 }
348 
349 static struct priv_data *
350 match_priv_data(di_node_t node)
351 {
352 	int i;
353 	size_t len;
354 	char *drv_name, *tmp;
355 	di_node_t parent;
356 	struct priv_data *pdp;
357 
358 	if ((parent = di_parent_node(node)) == DI_NODE_NIL)
359 		return (NULL);
360 
361 	if ((drv_name = di_driver_name(parent)) == NULL)
362 		return (NULL);
363 
364 	pdp = prt_priv_data;
365 	len = strlen(drv_name);
366 	for (i = 0; i < nprt_priv_data; ++i, ++pdp) {
367 		tmp = pdp->drv_name;
368 		while (tmp && (*tmp != '\0')) {
369 			if (strncmp(tmp, drv_name, len) == 0) {
370 #ifdef	DEBUG
371 				dprintf("matched parent private data"
372 				    " at Node <%s> parent driver <%s>\n",
373 				    di_node_name(node), drv_name);
374 #endif	/* DEBUG */
375 				return (pdp);
376 			}
377 			/*
378 			 * skip a white space
379 			 */
380 			if (tmp = strchr(tmp, ' '))
381 				tmp++;
382 		}
383 	}
384 
385 	return (NULL);
386 }
387 
388 void
389 dump_priv_data(int ilev, di_node_t node)
390 {
391 	uintptr_t priv;
392 	struct priv_data *pdp;
393 
394 	if ((priv = (uintptr_t)di_parent_private_data(node)) == NULL)
395 		return;
396 
397 	if ((pdp = match_priv_data(node)) == NULL) {
398 #ifdef DEBUG
399 		dprintf("Error: parent private data format unknown\n");
400 #endif /* DEBUG */
401 		return;
402 	}
403 
404 	pdp->pd_print(priv, ilev);
405 
406 	/* ignore driver private data for now */
407 }
408