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