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