xref: /illumos-gate/usr/src/lib/libprtdiag_psr/sparc/opl/common/opl_picl.c (revision 7800901e60d340b6af88e94a2149805dcfcaaf56)
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  * Opl platform specific PICL functions.
26  *
27  * 	called when :
28  *	machine_type == MTYPE_OPL
29  */
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <kstat.h>
37 #include <fcntl.h>
38 #include <string.h>
39 #include <assert.h>
40 #include <libintl.h>
41 #include <note.h>
42 #include <dlfcn.h>
43 #include <errno.h>
44 #include <sys/systeminfo.h>
45 #include <sys/openpromio.h>
46 #include <sys/sysmacros.h>
47 #include <picl.h>
48 #include "picldefs.h"
49 #include <pdevinfo.h>
50 #include <display.h>
51 #include <libprtdiag.h>
52 #include <alloca.h>
53 #include "opl_picl.h"
54 #include <sys/pci.h>
55 #include <sys/pci_tools.h>
56 #include <sys/types.h>
57 
58 #if !defined(TEXT_DOMAIN)
59 #define	TEXT_DOMAIN	"SYS_TEST"
60 #endif
61 
62 static picl_errno_t do_walk(picl_nodehdl_t rooth, const char *classname,
63     void *c_args, picl_errno_t (*callback_fn)(picl_nodehdl_t hdl, void *args));
64 static int opl_get_node_by_name(picl_nodehdl_t rooth, char *name,
65     picl_nodehdl_t *nodeh);
66 static picl_errno_t get_lane_width(char *device_path, int bus_no, int func_no,
67     int dev_no, int *actual, int *maximum, uint32_t *speed_max,
68     uint32_t *speed_at, int *type);
69 static int	opl_display_pci(int syserrlog, picl_nodehdl_t plafh);
70 static picl_errno_t opl_pci_callback(picl_nodehdl_t pcih, void *args);
71 static int opl_get_first_compatible_value(picl_nodehdl_t nodeh,
72     char **outbuf);
73 static int picldiag_get_clock_freq(picl_nodehdl_t modh,
74     uint32_t *freq);
75 static uint64_t picldiag_get_uint_propval(picl_nodehdl_t modh,
76     char *prop_name, int *ret);
77 static uint32_t	read_long(int fd, int bus, int dev, int func,
78     int offset, int *ret);
79 static uint8_t read_byte(int fd, int bus, int dev, int func, int offset,
80     int *ret);
81 static uint16_t read_word(int fd, int bus, int dev, int func, int offset,
82     int *ret);
83 
84 
85 /*
86  * Collect I/O nodes information.
87  */
88 /* ARGSUSED */
89 static picl_errno_t
90 opl_pci_callback(picl_nodehdl_t pcih, void *args)
91 {
92 	picl_errno_t	err = PICL_SUCCESS;
93 	picl_nodehdl_t	nodeh;
94 	picl_prophdl_t  proph;
95 	picl_propinfo_t pinfo;
96 	char		path[MAXSTRLEN];
97 	char		parent_path[MAXSTRLEN];
98 	static char	root_path[MAXSTRLEN];
99 	char		piclclass[PICL_CLASSNAMELEN_MAX];
100 	char		name[MAXSTRLEN];
101 	char		model[MAXSTRLEN];
102 	char		*compatible;
103 	char		binding_name[MAXSTRLEN];
104 	struct io_card	pci_card;
105 	char		status[6] = "N/A";
106 	int		portid = PROP_INVALID;
107 	int		*reg_val;
108 	int		board = PROP_INVALID;
109 	static int	saved_board = PROP_INVALID;
110 	static int	saved_portid = PROP_INVALID;
111 	int 		actual = PROP_INVALID, maximum = PROP_INVALID;
112 	int 		bus_type;
113 	int 		rev_id = PROP_INVALID, dev_id = PROP_INVALID;
114 	int		ven_id = PROP_INVALID;
115 	size_t		prop_size;
116 
117 	(void) memset(&pci_card, 0, sizeof (pci_card));
118 
119 	err = picl_get_propval_by_name(pcih, PICL_PROP_CLASSNAME,
120 	    piclclass, sizeof (piclclass));
121 
122 	if (err !=  PICL_SUCCESS)
123 		/* Do not proceed to parse this branch */
124 		return (err);
125 
126 	if (!IS_PCI(piclclass))
127 		/* Do not parse non-pci nodes */
128 		return (PICL_INVALIDARG);
129 
130 	err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, parent_path,
131 	    sizeof (parent_path));
132 	if (err != PICL_SUCCESS)
133 		/* Do not proceed to parse this branch */
134 		return (err);
135 	err = picl_get_propval_by_name(pcih, OBP_PROP_BOARD_NUM, &board,
136 	    sizeof (board));
137 
138 	if (err == PICL_NORESPONSE)
139 		/* Do not proceed to parse this branch */
140 		return (err);
141 	else if (err != PICL_PROPNOTFOUND) {
142 		saved_board = board;
143 		/* Save board node's pathname */
144 		prop_size = sizeof (parent_path) + 1;
145 		if (prop_size > MAXSTRLEN)
146 			prop_size = MAXSTRLEN;
147 		(void) strlcpy(root_path, parent_path, prop_size);
148 	}
149 
150 	err = picl_get_propval_by_name
151 	    (pcih, OBP_PROP_PORTID, &portid, sizeof (portid));
152 
153 	if (err != PICL_PROPNOTFOUND)
154 		saved_portid = portid;
155 
156 	/* Walk through the children */
157 
158 	err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
159 	    sizeof (picl_nodehdl_t));
160 
161 	while (err == PICL_SUCCESS) {
162 		uint32_t	freq_max = 0, freq_at = 0;
163 
164 		err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
165 		    piclclass, sizeof (piclclass));
166 		if (err !=  PICL_SUCCESS)
167 			/* Do not proceed to parse this node */
168 			return (err);
169 
170 		if (IS_EBUS(piclclass)) {
171 			err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
172 			    &nodeh, sizeof (picl_nodehdl_t));
173 			continue;
174 		}
175 
176 		err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH,
177 		    path, sizeof (path));
178 		if (err != PICL_SUCCESS) {
179 			/* Do not proceed to parse this node */
180 			return (err);
181 		}
182 
183 		prop_size = sizeof (path) + 1;
184 		if (prop_size > MAXSTRLEN)
185 			prop_size = MAXSTRLEN;
186 		(void) strlcpy(pci_card.notes, path, prop_size);
187 
188 		pci_card.board = saved_board;
189 		pci_card.schizo_portid = saved_portid;
190 
191 		/*
192 		 * Get bus#, dev# and func# for this card from 'reg' property.
193 		 */
194 
195 		err = picl_get_propinfo_by_name
196 		    (nodeh, OBP_PROP_REG, &pinfo, &proph);
197 		if (err == PICL_SUCCESS) {
198 			/* All of the array of bytes of "reg" have to be read */
199 			reg_val = malloc(pinfo.size);
200 			if (reg_val == NULL)
201 				return (PICL_FAILURE);
202 
203 
204 			err = picl_get_propval_by_name
205 			    (nodeh, OBP_PROP_REG, reg_val, pinfo.size);
206 
207 			if (err != PICL_SUCCESS) {
208 				free(reg_val);
209 				/* Do not proceed to parse this node */
210 				return (err);
211 			}
212 
213 			if (reg_val[0] != 0) {
214 				pci_card.dev_no =
215 				    (((reg_val[0]) & PCI_DEV_MASK) >> 11);
216 				pci_card.func_no =
217 				    (((reg_val[0]) & PCI_FUNC_MASK) >> 8);
218 				pci_card.slot =
219 				    (((reg_val[0]) & PCI_BUS_MASK) >> 16);
220 			} else
221 				free(reg_val);
222 		}
223 
224 		err = get_lane_width(root_path, pci_card.slot, pci_card.dev_no,
225 		    pci_card.func_no, &actual, &maximum, &freq_max, &freq_at,
226 		    &bus_type);
227 
228 		if (err != PICL_SUCCESS) {
229 			/* Move on to next node */
230 			log_printf("Getting lane width failed for path %s\n",
231 			    pci_card.notes);
232 			err = picl_get_propval_by_name
233 			    (nodeh, PICL_PROP_PEER, &nodeh,
234 			    sizeof (picl_nodehdl_t));
235 			continue;
236 		}
237 
238 
239 		err = picl_get_propval_by_name
240 		    (nodeh, PICL_PROP_NAME, name, sizeof (name));
241 		if (err != PICL_SUCCESS)
242 			(void) strcpy(name, "");
243 
244 		/*
245 		 * Get the name of this card. If binding_name is found,
246 		 * name will be <nodename>-<binding_name>
247 		 */
248 
249 		err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
250 		    binding_name, sizeof (binding_name));
251 		if (err == PICL_PROPNOTFOUND) {
252 			/*
253 			 * if compatible prop is found, name will be
254 			 * <nodename>-<compatible>
255 			 */
256 			err = opl_get_first_compatible_value(nodeh,
257 			    &compatible);
258 			if (err == PICL_SUCCESS) {
259 				(void) strlcat(name, "-", MAXSTRLEN);
260 				(void) strlcat(name, compatible, MAXSTRLEN);
261 				free(compatible);
262 			}
263 		} else if (err != PICL_SUCCESS) {
264 			/* No binding-name or compatible */
265 			(void) strcpy(binding_name, "N/A");
266 		} else if (strcmp(name, binding_name) != 0) {
267 			(void) strlcat(name, "-", MAXSTRLEN);
268 			(void) strlcat(name, binding_name, MAXSTRLEN);
269 		}
270 
271 
272 		prop_size = sizeof (name) + 1;
273 		if (prop_size > MAXSTRLEN)
274 			prop_size =  MAXSTRLEN;
275 		(void) strlcpy(pci_card.name, name, prop_size);
276 
277 		/* Get the status of the card */
278 		err = picl_get_propval_by_name
279 		    (nodeh, PICL_PROP_STATUS, status, sizeof (status));
280 
281 
282 		/* Get the model of this card */
283 
284 		err = picl_get_propval_by_name
285 		    (nodeh, OBP_PROP_MODEL, model, sizeof (model));
286 		prop_size = sizeof (model) + 1;
287 		if (prop_size > MAXSTRLEN)
288 			prop_size =  MAXSTRLEN;
289 		if (err != PICL_SUCCESS)
290 			(void) strcpy(model, "N/A");
291 		(void) strlcpy(pci_card.model, model, prop_size);
292 
293 		if (bus_type == PCI)
294 			(void) strlcpy(pci_card.bus_type,
295 			    "PCI", sizeof (pci_card.bus_type));
296 		else if (bus_type == PCIX)
297 			(void) strlcpy(pci_card.bus_type,
298 			    "PCIx", sizeof (pci_card.bus_type));
299 		else if (bus_type == PCIE)
300 			(void) strlcpy(pci_card.bus_type,
301 			    "PCIe", sizeof (pci_card.bus_type));
302 		else
303 			(void) strlcpy(pci_card.bus_type,
304 			    "UNKN", sizeof (pci_card.bus_type));
305 
306 		/* Get revision id */
307 		err = picl_get_propval_by_name
308 		    (nodeh, OBP_PROP_REVISION_ID, &rev_id, sizeof (rev_id));
309 
310 		/* Get device id */
311 		err = picl_get_propval_by_name
312 		    (nodeh, OBP_PROP_DEVICE_ID, &dev_id, sizeof (dev_id));
313 
314 		/* Get vendor id */
315 		err = picl_get_propval_by_name
316 		    (nodeh, OBP_PROP_VENDOR_ID, &ven_id, sizeof (ven_id));
317 
318 		/*
319 		 * prtdiag -v prints all devices
320 		 */
321 
322 		/* Print board number */
323 		log_printf("%02d  ", pci_card.board);
324 		/* Print IO Type */
325 		log_printf("%-5.5s ", pci_card.bus_type);
326 
327 		log_printf("%-3d  ", pci_card.schizo_portid);
328 		log_printf("%4x, %4x, %4x     ", rev_id, dev_id, ven_id);
329 
330 		log_printf("%3d, %2d, %2d",
331 		    pci_card.slot, pci_card.dev_no, pci_card.func_no);
332 
333 		/* Print status */
334 		log_printf("  %-5.5s ", status);
335 
336 		/* Print Lane widths, Max/Sup Freq, Speed */
337 		if (bus_type == PCIE) {
338 			PRINT_FMT(actual, maximum);
339 		} else if (bus_type == PCIX) {
340 			PRINT_FREQ_FMT(freq_at, freq_max);
341 		} else if (bus_type == PCI) {
342 			err = picldiag_get_clock_freq(nodeh, &freq_at);
343 			PRINT_FREQ_FMT(freq_at, freq_max);
344 		} else
345 			log_printf(" -- , --   ");
346 
347 		/* Print Card Name */
348 		log_printf("%-30.30s", pci_card.name);
349 
350 		/* Print Card Model */
351 		log_printf(" %-20.20s", pci_card.model);
352 
353 		log_printf("\n");
354 
355 		log_printf("%4s%-100.100s", " ", pci_card.notes);
356 		log_printf("\n");
357 		log_printf("\n");
358 
359 
360 		err = picl_get_propval_by_name
361 		    (nodeh, PICL_PROP_PEER, &nodeh, sizeof (picl_nodehdl_t));
362 
363 	}
364 
365 	return (PICL_WALK_CONTINUE);
366 }
367 
368 /*
369  * opl_display_pci
370  * Display all the PCI IO cards on this board.
371  */
372 static int
373 opl_display_pci(int syserrlog, picl_nodehdl_t plafh)
374 {
375 	picl_errno_t err;
376 	char	*fmt = "%-3s %-5s %-4s %-20s %-11s %-5s %-11s %-30s %-20s";
377 	char 	*fmt2 = "%-16s";
378 	static int banner = FALSE; /* Have we printed the column headings? */
379 
380 	if (banner == FALSE) {
381 		log_printf("\n", 0);
382 		log_printf("=========================", 0);
383 		log_printf(dgettext(TEXT_DOMAIN, " IO Devices "), 0);
384 		log_printf("=========================", 0);
385 		log_printf("\n", 0);
386 		log_printf("\n", 0);
387 		log_printf(fmt, "", "IO", "", "", "", "", "Lane/Frq",
388 		    "", "", 0);
389 		log_printf("\n", 0);
390 
391 		log_printf(fmt, "LSB", "Type", "LPID", "  RvID,DvID,VnID",
392 		    "  BDF", "State", "Act,  Max", "Name", "Model", 0);
393 
394 		log_printf("\n");
395 
396 		log_printf(fmt,
397 		    "---", "-----", "----", "  ------------------",
398 		    "  ---------", "-----", "-----------",
399 		    "------------------------------",
400 		    "--------------------", 0);
401 		log_printf("\n");
402 		log_printf(fmt2, "    Logical Path");
403 		log_printf("\n");
404 		log_printf(fmt2, "    ------------");
405 		log_printf("\n");
406 		banner = TRUE;
407 	}
408 
409 	err = do_walk(plafh, PICL_CLASS_PCI, PICL_CLASS_PCI, opl_pci_callback);
410 	return (err);
411 }
412 
413 
414 /*
415  * return the first compatible value
416  */
417 static int
418 opl_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
419 {
420 	picl_errno_t	err;
421 	picl_prophdl_t	proph;
422 	picl_propinfo_t	pinfo;
423 	picl_prophdl_t	tblh;
424 	picl_prophdl_t	rowproph;
425 	char		*pval;
426 
427 	err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
428 	    &pinfo, &proph);
429 	if (err != PICL_SUCCESS)
430 		return (err);
431 
432 	if (pinfo.type == PICL_PTYPE_CHARSTRING) {
433 		pval = malloc(pinfo.size);
434 		if (pval == NULL)
435 			return (PICL_FAILURE);
436 		err = picl_get_propval(proph, pval, pinfo.size);
437 		if (err != PICL_SUCCESS) {
438 			free(pval);
439 			return (err);
440 		}
441 		*outbuf = pval;
442 		return (PICL_SUCCESS);
443 	}
444 
445 	if (pinfo.type != PICL_PTYPE_TABLE)
446 		return (PICL_FAILURE);
447 
448 	/* get first string from table */
449 	err = picl_get_propval(proph, &tblh, pinfo.size);
450 	if (err != PICL_SUCCESS)
451 		return (err);
452 
453 	err = picl_get_next_by_row(tblh, &rowproph);
454 	if (err != PICL_SUCCESS)
455 		return (err);
456 
457 	err = picl_get_propinfo(rowproph, &pinfo);
458 	if (err != PICL_SUCCESS)
459 		return (err);
460 
461 	pval = malloc(pinfo.size);
462 	if (pval == NULL)
463 		return (PICL_FAILURE);
464 
465 	err = picl_get_propval(rowproph, pval, pinfo.size);
466 	if (err != PICL_SUCCESS) {
467 		free(pval);
468 		return (err);
469 	}
470 
471 	*outbuf = pval;
472 	return (PICL_SUCCESS);
473 }
474 
475 int
476 do_piclinfo(int syserrlog)
477 {
478 	picl_nodehdl_t rooth;		/* root PICL node for IO display */
479 	picl_nodehdl_t plafh;		/* Platform PICL node for IO display */
480 
481 	picl_errno_t err;
482 
483 	err = picl_initialize();
484 	if (err != PICL_SUCCESS) {
485 		(void) log_printf("picl_initialize failed: %s\n",
486 		    picl_strerror(err));
487 		return (err);
488 	}
489 
490 
491 	err = picl_get_root(&rooth);
492 	if (err != PICL_SUCCESS) {
493 		(void) log_printf("Getting root node failed: %s\n",
494 		    picl_strerror(err));
495 		return (err);
496 	}
497 
498 	err = opl_get_node_by_name(rooth, PICL_NODE_PLATFORM, &plafh);
499 
500 	if (err != PICL_SUCCESS) {
501 		(void) log_printf("Getting nodes by name failed: %s\n",
502 		    picl_strerror(err));
503 		return (err);
504 	}
505 
506 	err = opl_display_pci(syserrlog, plafh);
507 
508 	(void) picl_shutdown();
509 
510 	return (err);
511 }
512 
513 /*
514  * search children to get the node by the nodename
515  */
516 static int
517 opl_get_node_by_name(picl_nodehdl_t rooth, char *name,
518     picl_nodehdl_t *nodeh)
519 {
520 	picl_nodehdl_t	childh;
521 	int		err;
522 	char		*nodename;
523 
524 	nodename = alloca(strlen(name) + 1);
525 	if (nodename == NULL)
526 		return (PICL_FAILURE);
527 
528 	err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh,
529 	    sizeof (picl_nodehdl_t));
530 
531 	while (err == PICL_SUCCESS) {
532 		err = picl_get_propval_by_name(childh, PICL_PROP_NAME,
533 		    nodename, (strlen(name) + 1));
534 		if (err != PICL_SUCCESS) {
535 			err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
536 			    &childh, sizeof (picl_nodehdl_t));
537 			continue;
538 		}
539 
540 		if (strcmp(nodename, name) == 0) {
541 			*nodeh = childh;
542 			return (PICL_SUCCESS);
543 		}
544 
545 		err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
546 		    &childh, sizeof (picl_nodehdl_t));
547 	}
548 
549 	return (err);
550 }
551 
552 static int
553 open_root_complex(char *root_complex)
554 {
555 	char *path;
556 	static char device_str[] = {"/devices"};
557 	static char devctl_str[] = {":reg"};
558 	int fd;
559 
560 	path = malloc(
561 	    strlen(root_complex) + sizeof (device_str) + sizeof (devctl_str));
562 	if (path == NULL)
563 		return (PICL_FAILURE);
564 	(void) strcpy(path, device_str);
565 	(void) strcat(path, root_complex);
566 	(void) strcat(path, devctl_str);
567 
568 	if ((fd = open(path, O_RDWR)) == -1) {
569 		return (-1);
570 	}
571 	return (fd);
572 }
573 
574 static uint32_t
575 read_long(int fd, int bus, int dev, int func, int offset, int *ret)
576 {
577 	int rval;
578 	pcitool_reg_t prg;
579 
580 	prg.user_version = PCITOOL_VERSION;
581 	prg.barnum = 0;
582 	prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 +
583 	    PCITOOL_ACC_ATTR_ENDN_LTL;
584 	prg.bus_no = bus;
585 	prg.dev_no = dev;
586 	prg.func_no = func;
587 	prg.offset = offset;
588 	rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg);
589 	if (rval != 0) {
590 		log_printf("DEV_GET failed %d %s\n", rval, strerror(errno));
591 		log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
592 	}
593 	*ret = rval;
594 	return ((uint32_t)prg.data);
595 }
596 
597 static uint16_t
598 read_word(int fd, int bus, int dev, int func, int offset, int *ret)
599 {
600 	int rval;
601 	pcitool_reg_t prg;
602 
603 	prg.user_version = PCITOOL_VERSION;
604 	prg.barnum = 0;
605 	prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_2 +
606 	    PCITOOL_ACC_ATTR_ENDN_LTL;
607 	prg.bus_no = bus;
608 	prg.dev_no = dev;
609 	prg.func_no = func;
610 	prg.offset = offset;
611 	rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg);
612 	if (rval != 0) {
613 		log_printf("DEV_GET failed %d %s\n", rval, strerror(errno));
614 		log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
615 	}
616 	*ret = rval;
617 	return ((uint16_t)prg.data);
618 }
619 
620 static uint8_t
621 read_byte(int fd, int bus, int dev, int func, int offset, int *ret)
622 {
623 	int rval;
624 	pcitool_reg_t prg;
625 
626 	prg.user_version = PCITOOL_VERSION;
627 	prg.barnum = 0;
628 	prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_1 +
629 	    PCITOOL_ACC_ATTR_ENDN_LTL;
630 	prg.bus_no = bus;
631 	prg.dev_no = dev;
632 	prg.func_no = func;
633 	prg.offset = offset;
634 	rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg);
635 	if (rval != 0) {
636 		log_printf("DEV_GET failed %d %s\n", rval, strerror(errno));
637 		log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
638 	}
639 	*ret = rval;
640 	return ((uint8_t)prg.data);
641 }
642 
643 
644 static picl_errno_t
645 get_lane_width
646 	(char *device_path, int bus, int dev, int func, int *actual,
647 	int *maximum, uint32_t *speed_max, uint32_t *speed_at, int *type)
648 {
649 	uint_t cap_ptr, cap_reg, link_status, link_cap, capid;
650 	int fd, ret;
651 
652 	if (device_path == NULL)
653 		return (PICL_FAILURE);
654 
655 	fd = open_root_complex(device_path);
656 	if (fd == -1)
657 		return (PICL_FAILURE);
658 
659 	/*
660 	 * Link Capabilities and Link Status registers are in the
661 	 * PCI-E capabilities register.  They are at offset
662 	 * 0xc and 0x12 respectively. They are documented in section
663 	 * 7.8 of the PCI Express Base Specification. The address of
664 	 * that structure is not fixed, it's kind of a linked list.
665 	 * The Capabilities Pointer reg (8 bits) is always at 0x34.
666 	 * It contains a pointer to the first capabilities structure.
667 	 * For each capability structure, the first 8 bits is the capability
668 	 * ID. The next 8 bits is the pointer to the next structure.
669 	 * If the Next Cap register is zero, it's the end of the list.
670 	 * The capability ID for the PCI-E strucutre is 0x10.  The idea
671 	 * is to follow the links until you find a Cap ID of 0x10, then
672 	 * read the registers at 0xc and 0x12 from there.
673 	 * If there's no Cap ID 0x10, then it's not a PCI-E device.
674 	 */
675 
676 	cap_ptr = read_byte(fd, bus, dev, func, PCI_CONF_CAP_PTR, &ret);
677 	if (ret != 0) {
678 		/* ioctl failure */
679 		return (PICL_FAILURE);
680 	}
681 	cap_reg = read_word(fd, bus, dev, func, cap_ptr, &ret);
682 	if (ret != 0) {
683 		/* ioctl failure */
684 		return (PICL_FAILURE);
685 	}
686 	capid = cap_reg & PCI_CAP_MASK;
687 	while (cap_ptr != 0) {
688 
689 		if (capid == PCI_CAP_ID_PCI_E) {
690 			link_cap = read_long(fd, bus, dev, func, cap_ptr +
691 			    PCIE_LINKCAP, &ret);
692 			if (ret != 0) {
693 				return (PICL_FAILURE);
694 			}
695 			link_status = read_word(fd, bus, dev, func,
696 			    cap_ptr + PCIE_LINKSTS, &ret);
697 			if (ret != 0) {
698 				return (PICL_FAILURE);
699 			}
700 			*actual = ((link_status >> PCI_LINK_SHIFT) &
701 			    PCI_LINK_MASK);
702 			*maximum = ((link_cap >> PCI_LINK_SHIFT) &
703 			    PCI_LINK_MASK);
704 			*type = PCIE;
705 		}
706 		if (capid == PCI_CAP_ID_PCIX) {
707 			uint32_t pcix_status;
708 			uint8_t hdr_type;
709 			int max_speed = PCI_FREQ_66;
710 
711 			hdr_type = read_byte
712 			    (fd, bus, dev, func, PCI_CONF_HEADER, &ret);
713 			if (ret != 0) {
714 				/* ioctl failure */
715 				return (PICL_FAILURE);
716 			}
717 			if ((hdr_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
718 				/* This is a PCI-X bridge */
719 				uint16_t sec_status, mode;
720 				sec_status = read_word(fd, bus, dev, func,
721 				    cap_ptr + PCI_PCIX_SEC_STATUS, &ret);
722 				if (ret != 0) {
723 					/* ioctl failure */
724 					return (PICL_FAILURE);
725 				}
726 				if (sec_status & PCI_SEC_133)
727 					max_speed = PCI_FREQ_133;
728 				if (sec_status & PCI_SEC_266)
729 					max_speed = PCI_FREQ_266;
730 				if (sec_status & PCI_SEC_533)
731 					max_speed = PCI_FREQ_533;
732 				*speed_max = max_speed;
733 				*type = PCIX;
734 				mode = (sec_status >> PCI_CLASS_BRIDGE) &
735 				    PCI_BRIDGE_MC;
736 				if (mode) {
737 					int speed;
738 					if (mode == PCI_MODE_66)
739 						speed = PCI_FREQ_66;
740 					else if (mode == PCI_MODE_100)
741 						speed = PCI_FREQ_100;
742 					else if (mode == PCI_MODE_133)
743 						speed = PCI_FREQ_133;
744 					*speed_at = speed;
745 				}
746 
747 			} else {  /* Leaf device */
748 				pcix_status = read_long(fd, bus, dev, func,
749 				    cap_ptr + PCI_PCIX_STATUS, &ret);
750 				if (ret != 0) {
751 					/* ioctl failure */
752 					return (PICL_FAILURE);
753 				}
754 				if (pcix_status &
755 				    (PCI_LEAF_ULONG << PCI_SHIFT_133))
756 					max_speed = PCI_FREQ_133;
757 				if (pcix_status &
758 				    (PCI_LEAF_ULONG << PCI_SHIFT_266))
759 					max_speed = PCI_FREQ_266;
760 				if (pcix_status &
761 				    (PCI_LEAF_ULONG << PCI_SHIFT_533))
762 					max_speed = PCI_FREQ_533;
763 				*speed_max = max_speed;
764 				*type = PCI;
765 			}
766 		}
767 		cap_ptr = (cap_reg >> PCI_REG_FUNC_SHIFT);
768 		cap_reg = read_word(fd, bus, dev, func, cap_ptr, &ret);
769 		if (ret != 0) {
770 			/* ioctl failure */
771 			return (PICL_FAILURE);
772 		}
773 		capid = cap_reg & PCI_CAP_MASK;
774 	}
775 
776 	return (PICL_SUCCESS);
777 }
778 
779 /*
780  * get the clock frequency
781  */
782 static int
783 picldiag_get_clock_freq(picl_nodehdl_t modh, uint32_t *freq)
784 {
785 	int		err;
786 	uint64_t	clk_freq;
787 
788 	clk_freq = picldiag_get_uint_propval(modh, OBP_PROP_CLOCK_FREQ, &err);
789 	if (err != PICL_SUCCESS)
790 		return (err);
791 
792 	*freq = ROUND_TO_MHZ(clk_freq);
793 
794 	return (PICL_SUCCESS);
795 }
796 
797 static uint64_t
798 picldiag_get_uint_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
799 {
800 	int		err;
801 	picl_prophdl_t	proph;
802 	picl_propinfo_t pinfo;
803 	uint8_t		uint8v;
804 	uint16_t	uint16v;
805 	uint32_t	uint32v;
806 	uint64_t	uint64v;
807 
808 	err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
809 	if (err != PICL_SUCCESS) {
810 		*ret = err;
811 		return (0);
812 	}
813 
814 	/*
815 	 * If it is not an int or uint prop, return failure
816 	 */
817 	if ((pinfo.type != PICL_PTYPE_INT) &&
818 	    (pinfo.type != PICL_PTYPE_UNSIGNED_INT)) {
819 		*ret = PICL_FAILURE;
820 		return (0);
821 	}
822 
823 
824 	/* uint prop */
825 
826 	switch (pinfo.size) {
827 	case sizeof (uint8_t):
828 		err = picl_get_propval(proph, &uint8v, sizeof (uint8v));
829 		*ret = err;
830 		return (uint8v);
831 	case sizeof (uint16_t):
832 		err = picl_get_propval(proph, &uint16v, sizeof (uint16v));
833 		*ret = err;
834 		return (uint16v);
835 	case sizeof (uint32_t):
836 		err = picl_get_propval(proph, &uint32v, sizeof (uint32v));
837 		*ret = err;
838 		return (uint32v);
839 	case sizeof (uint64_t):
840 		err = picl_get_propval(proph, &uint64v, sizeof (uint64v));
841 		*ret = err;
842 		return (uint64v);
843 	default:	/* not supported size */
844 		*ret = PICL_FAILURE;
845 		return (0);
846 	}
847 }
848 
849 /*
850  * recursively visit all nodes
851  */
852 static picl_errno_t
853 do_walk(picl_nodehdl_t rooth, const char *classname,
854     void *c_args, picl_errno_t (*callback_fn)(picl_nodehdl_t hdl, void *args))
855 {
856 	picl_errno_t	err;
857 	picl_nodehdl_t  chdh;
858 	char		classval[PICL_CLASSNAMELEN_MAX];
859 
860 	err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh,
861 	    sizeof (chdh));
862 	while (err == PICL_SUCCESS) {
863 		err = picl_get_propval_by_name(chdh, PICL_PROP_NAME,
864 		    classval, sizeof (classval));
865 		if (err != PICL_SUCCESS)
866 			return (err);
867 
868 		err = callback_fn(chdh, c_args);
869 
870 		if ((err = do_walk(chdh, classname, c_args, callback_fn)) !=
871 		    PICL_WALK_CONTINUE)
872 			return (err);
873 
874 		err = picl_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
875 		    sizeof (chdh));
876 	}
877 	if (err == PICL_PROPNOTFOUND)   /* end of a branch */
878 		return (PICL_WALK_CONTINUE);
879 	return (err);
880 }
881 
882 int
883 get_proc_mode(void)
884 {
885 	picl_nodehdl_t nodeh;
886 	picl_prophdl_t  proph;
887 	picl_errno_t err;
888 
889 	err = picl_initialize();
890 	if (err != PICL_SUCCESS) {
891 		(void) log_printf("picl_initialize failed: %s\n",
892 		    picl_strerror(err));
893 		return (err);
894 	}
895 
896 	err = picl_get_node_by_path("/platform",  &nodeh);
897 	if (err != PICL_SUCCESS) {
898 		(void) log_printf("Getting plat node failed: %s\n",
899 		    picl_strerror(err));
900 		return (err);
901 	}
902 
903 	err = picl_get_prop_by_name(nodeh, "SPARC64-VII-mode",  &proph);
904 	if (err != PICL_SUCCESS) {
905 		/* Do not display error message */
906 		return (err);
907 	}
908 
909 	(void) picl_shutdown();
910 
911 	return (err);
912 }
913