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 2008 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 			/*
230 			 * get_lane_width will fail when run as non-root.
231 			 * Set bus_type to PCI_UNKN so that bus frequency,
232 			 * bus type and lane width will print as "--" or UNKN.
233 			 */
234 			bus_type = PCI_UNKN;
235 		}
236 
237 
238 		err = picl_get_propval_by_name
239 		    (nodeh, PICL_PROP_NAME, name, sizeof (name));
240 		if (err != PICL_SUCCESS)
241 			(void) strcpy(name, "");
242 
243 		/*
244 		 * Get the name of this card. If binding_name is found,
245 		 * name will be <nodename>-<binding_name>
246 		 */
247 
248 		err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
249 		    binding_name, sizeof (binding_name));
250 		if (err == PICL_PROPNOTFOUND) {
251 			/*
252 			 * if compatible prop is found, name will be
253 			 * <nodename>-<compatible>
254 			 */
255 			err = opl_get_first_compatible_value(nodeh,
256 			    &compatible);
257 			if (err == PICL_SUCCESS) {
258 				(void) strlcat(name, "-", MAXSTRLEN);
259 				(void) strlcat(name, compatible, MAXSTRLEN);
260 				free(compatible);
261 			}
262 		} else if (err != PICL_SUCCESS) {
263 			/* No binding-name or compatible */
264 			(void) strcpy(binding_name, "N/A");
265 		} else if (strcmp(name, binding_name) != 0) {
266 			(void) strlcat(name, "-", MAXSTRLEN);
267 			(void) strlcat(name, binding_name, MAXSTRLEN);
268 		}
269 
270 
271 		prop_size = sizeof (name) + 1;
272 		if (prop_size > MAXSTRLEN)
273 			prop_size =  MAXSTRLEN;
274 		(void) strlcpy(pci_card.name, name, prop_size);
275 
276 		/* Get the status of the card */
277 		err = picl_get_propval_by_name
278 		    (nodeh, PICL_PROP_STATUS, status, sizeof (status));
279 
280 
281 		/* Get the model of this card */
282 
283 		err = picl_get_propval_by_name
284 		    (nodeh, OBP_PROP_MODEL, model, sizeof (model));
285 		prop_size = sizeof (model) + 1;
286 		if (prop_size > MAXSTRLEN)
287 			prop_size =  MAXSTRLEN;
288 		if (err != PICL_SUCCESS)
289 			(void) strcpy(model, "N/A");
290 		(void) strlcpy(pci_card.model, model, prop_size);
291 
292 		if (bus_type == PCI)
293 			(void) strlcpy(pci_card.bus_type,
294 			    "PCI", sizeof (pci_card.bus_type));
295 		else if (bus_type == PCIX)
296 			(void) strlcpy(pci_card.bus_type,
297 			    "PCIx", sizeof (pci_card.bus_type));
298 		else if (bus_type == PCIE)
299 			(void) strlcpy(pci_card.bus_type,
300 			    "PCIe", sizeof (pci_card.bus_type));
301 		else
302 			(void) strlcpy(pci_card.bus_type,
303 			    "UNKN", sizeof (pci_card.bus_type));
304 
305 		/* Get revision id */
306 		err = picl_get_propval_by_name
307 		    (nodeh, OBP_PROP_REVISION_ID, &rev_id, sizeof (rev_id));
308 
309 		/* Get device id */
310 		err = picl_get_propval_by_name
311 		    (nodeh, OBP_PROP_DEVICE_ID, &dev_id, sizeof (dev_id));
312 
313 		/* Get vendor id */
314 		err = picl_get_propval_by_name
315 		    (nodeh, OBP_PROP_VENDOR_ID, &ven_id, sizeof (ven_id));
316 
317 		/*
318 		 * prtdiag -v prints all devices
319 		 */
320 
321 		/* Print board number */
322 		log_printf("%02d  ", pci_card.board);
323 		/* Print IO Type */
324 		log_printf("%-5.5s ", pci_card.bus_type);
325 
326 		log_printf("%-3d  ", pci_card.schizo_portid);
327 		log_printf("%4x, %4x, %4x     ", rev_id, dev_id, ven_id);
328 
329 		log_printf("%3d, %2d, %2d",
330 		    pci_card.slot, pci_card.dev_no, pci_card.func_no);
331 
332 		/* Print status */
333 		log_printf("  %-5.5s ", status);
334 
335 		/* Print Lane widths, Max/Sup Freq, Speed */
336 		if (bus_type == PCIE) {
337 			PRINT_FMT(actual, maximum);
338 		} else if (bus_type == PCIX) {
339 			PRINT_FREQ_FMT(freq_at, freq_max);
340 		} else if (bus_type == PCI) {
341 			err = picldiag_get_clock_freq(nodeh, &freq_at);
342 			PRINT_FREQ_FMT(freq_at, freq_max);
343 		} else
344 			log_printf(" -- , --   ");
345 
346 		/* Print Card Name */
347 		log_printf("%-30.30s", pci_card.name);
348 
349 		/* Print Card Model */
350 		log_printf(" %-20.20s", pci_card.model);
351 
352 		log_printf("\n");
353 
354 		log_printf("%4s%-100.100s", " ", pci_card.notes);
355 		log_printf("\n");
356 		log_printf("\n");
357 
358 
359 		err = picl_get_propval_by_name
360 		    (nodeh, PICL_PROP_PEER, &nodeh, sizeof (picl_nodehdl_t));
361 
362 	}
363 
364 	return (PICL_WALK_CONTINUE);
365 }
366 
367 /*
368  * opl_display_pci
369  * Display all the PCI IO cards on this board.
370  */
371 static int
372 opl_display_pci(int syserrlog, picl_nodehdl_t plafh)
373 {
374 	picl_errno_t err;
375 	char	*fmt = "%-3s %-5s %-4s %-20s %-11s %-5s %-11s %-30s %-20s";
376 	char 	*fmt2 = "%-16s";
377 	static int banner = FALSE; /* Have we printed the column headings? */
378 
379 	if (banner == FALSE) {
380 		log_printf("\n", 0);
381 		log_printf("=========================", 0);
382 		log_printf(dgettext(TEXT_DOMAIN, " IO Devices "), 0);
383 		log_printf("=========================", 0);
384 		log_printf("\n", 0);
385 		log_printf("\n", 0);
386 		log_printf(fmt, "", "IO", "", "", "", "", "Lane/Frq",
387 		    "", "", 0);
388 		log_printf("\n", 0);
389 
390 		log_printf(fmt, "LSB", "Type", "LPID", "  RvID,DvID,VnID",
391 		    "  BDF", "State", "Act,  Max", "Name", "Model", 0);
392 
393 		log_printf("\n");
394 
395 		log_printf(fmt,
396 		    "---", "-----", "----", "  ------------------",
397 		    "  ---------", "-----", "-----------",
398 		    "------------------------------",
399 		    "--------------------", 0);
400 		log_printf("\n");
401 		log_printf(fmt2, "    Logical Path");
402 		log_printf("\n");
403 		log_printf(fmt2, "    ------------");
404 		log_printf("\n");
405 		banner = TRUE;
406 	}
407 
408 	err = do_walk(plafh, PICL_CLASS_PCI, PICL_CLASS_PCI, opl_pci_callback);
409 	return (err);
410 }
411 
412 
413 /*
414  * return the first compatible value
415  */
416 static int
417 opl_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
418 {
419 	picl_errno_t	err;
420 	picl_prophdl_t	proph;
421 	picl_propinfo_t	pinfo;
422 	picl_prophdl_t	tblh;
423 	picl_prophdl_t	rowproph;
424 	char		*pval;
425 
426 	err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
427 	    &pinfo, &proph);
428 	if (err != PICL_SUCCESS)
429 		return (err);
430 
431 	if (pinfo.type == PICL_PTYPE_CHARSTRING) {
432 		pval = malloc(pinfo.size);
433 		if (pval == NULL)
434 			return (PICL_FAILURE);
435 		err = picl_get_propval(proph, pval, pinfo.size);
436 		if (err != PICL_SUCCESS) {
437 			free(pval);
438 			return (err);
439 		}
440 		*outbuf = pval;
441 		return (PICL_SUCCESS);
442 	}
443 
444 	if (pinfo.type != PICL_PTYPE_TABLE)
445 		return (PICL_FAILURE);
446 
447 	/* get first string from table */
448 	err = picl_get_propval(proph, &tblh, pinfo.size);
449 	if (err != PICL_SUCCESS)
450 		return (err);
451 
452 	err = picl_get_next_by_row(tblh, &rowproph);
453 	if (err != PICL_SUCCESS)
454 		return (err);
455 
456 	err = picl_get_propinfo(rowproph, &pinfo);
457 	if (err != PICL_SUCCESS)
458 		return (err);
459 
460 	pval = malloc(pinfo.size);
461 	if (pval == NULL)
462 		return (PICL_FAILURE);
463 
464 	err = picl_get_propval(rowproph, pval, pinfo.size);
465 	if (err != PICL_SUCCESS) {
466 		free(pval);
467 		return (err);
468 	}
469 
470 	*outbuf = pval;
471 	return (PICL_SUCCESS);
472 }
473 
474 int
475 do_piclinfo(int syserrlog)
476 {
477 	picl_nodehdl_t rooth;		/* root PICL node for IO display */
478 	picl_nodehdl_t plafh;		/* Platform PICL node for IO display */
479 
480 	picl_errno_t err;
481 
482 	err = picl_initialize();
483 	if (err != PICL_SUCCESS) {
484 		(void) log_printf("picl_initialize failed: %s\n",
485 		    picl_strerror(err));
486 		return (err);
487 	}
488 
489 
490 	err = picl_get_root(&rooth);
491 	if (err != PICL_SUCCESS) {
492 		(void) log_printf("Getting root node failed: %s\n",
493 		    picl_strerror(err));
494 		return (err);
495 	}
496 
497 	err = opl_get_node_by_name(rooth, PICL_NODE_PLATFORM, &plafh);
498 
499 	if (err != PICL_SUCCESS) {
500 		(void) log_printf("Getting nodes by name failed: %s\n",
501 		    picl_strerror(err));
502 		return (err);
503 	}
504 
505 	err = opl_display_pci(syserrlog, plafh);
506 
507 	(void) picl_shutdown();
508 
509 	return (err);
510 }
511 
512 /*
513  * search children to get the node by the nodename
514  */
515 static int
516 opl_get_node_by_name(picl_nodehdl_t rooth, char *name,
517     picl_nodehdl_t *nodeh)
518 {
519 	picl_nodehdl_t	childh;
520 	int		err;
521 	char		*nodename;
522 
523 	nodename = alloca(strlen(name) + 1);
524 	if (nodename == NULL)
525 		return (PICL_FAILURE);
526 
527 	err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh,
528 	    sizeof (picl_nodehdl_t));
529 
530 	while (err == PICL_SUCCESS) {
531 		err = picl_get_propval_by_name(childh, PICL_PROP_NAME,
532 		    nodename, (strlen(name) + 1));
533 		if (err != PICL_SUCCESS) {
534 			err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
535 			    &childh, sizeof (picl_nodehdl_t));
536 			continue;
537 		}
538 
539 		if (strcmp(nodename, name) == 0) {
540 			*nodeh = childh;
541 			return (PICL_SUCCESS);
542 		}
543 
544 		err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
545 		    &childh, sizeof (picl_nodehdl_t));
546 	}
547 
548 	return (err);
549 }
550 
551 static int
552 open_root_complex(char *root_complex)
553 {
554 	char *path;
555 	static char device_str[] = {"/devices"};
556 	static char devctl_str[] = {":reg"};
557 	int fd;
558 
559 	path = malloc(
560 	    strlen(root_complex) + sizeof (device_str) + sizeof (devctl_str));
561 	if (path == NULL)
562 		return (PICL_FAILURE);
563 	(void) strcpy(path, device_str);
564 	(void) strcat(path, root_complex);
565 	(void) strcat(path, devctl_str);
566 
567 	if ((fd = open(path, O_RDWR)) == -1) {
568 		return (-1);
569 	}
570 	return (fd);
571 }
572 
573 static uint32_t
574 read_long(int fd, int bus, int dev, int func, int offset, int *ret)
575 {
576 	int rval;
577 	pcitool_reg_t prg;
578 
579 	prg.user_version = PCITOOL_VERSION;
580 	prg.barnum = 0;
581 	prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 +
582 	    PCITOOL_ACC_ATTR_ENDN_LTL;
583 	prg.bus_no = bus;
584 	prg.dev_no = dev;
585 	prg.func_no = func;
586 	prg.offset = offset;
587 	rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg);
588 	if (rval != 0) {
589 		log_printf("DEV_GET failed %d %s\n", rval, strerror(errno));
590 		log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
591 	}
592 	*ret = rval;
593 	return ((uint32_t)prg.data);
594 }
595 
596 static uint16_t
597 read_word(int fd, int bus, int dev, int func, int offset, int *ret)
598 {
599 	int rval;
600 	pcitool_reg_t prg;
601 
602 	prg.user_version = PCITOOL_VERSION;
603 	prg.barnum = 0;
604 	prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_2 +
605 	    PCITOOL_ACC_ATTR_ENDN_LTL;
606 	prg.bus_no = bus;
607 	prg.dev_no = dev;
608 	prg.func_no = func;
609 	prg.offset = offset;
610 	rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg);
611 	if (rval != 0) {
612 		log_printf("DEV_GET failed %d %s\n", rval, strerror(errno));
613 		log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
614 	}
615 	*ret = rval;
616 	return ((uint16_t)prg.data);
617 }
618 
619 static uint8_t
620 read_byte(int fd, int bus, int dev, int func, int offset, int *ret)
621 {
622 	int rval;
623 	pcitool_reg_t prg;
624 
625 	prg.user_version = PCITOOL_VERSION;
626 	prg.barnum = 0;
627 	prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_1 +
628 	    PCITOOL_ACC_ATTR_ENDN_LTL;
629 	prg.bus_no = bus;
630 	prg.dev_no = dev;
631 	prg.func_no = func;
632 	prg.offset = offset;
633 	rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg);
634 	if (rval != 0) {
635 		log_printf("DEV_GET failed %d %s\n", rval, strerror(errno));
636 		log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
637 	}
638 	*ret = rval;
639 	return ((uint8_t)prg.data);
640 }
641 
642 
643 static picl_errno_t
644 get_lane_width
645 	(char *device_path, int bus, int dev, int func, int *actual,
646 	int *maximum, uint32_t *speed_max, uint32_t *speed_at, int *type)
647 {
648 	uint_t cap_ptr, cap_reg, link_status, link_cap, capid;
649 	int fd, ret;
650 
651 	if (device_path == NULL)
652 		return (PICL_FAILURE);
653 
654 	fd = open_root_complex(device_path);
655 	if (fd == -1)
656 		return (PICL_FAILURE);
657 
658 	/*
659 	 * Link Capabilities and Link Status registers are in the
660 	 * PCI-E capabilities register.  They are at offset
661 	 * 0xc and 0x12 respectively. They are documented in section
662 	 * 7.8 of the PCI Express Base Specification. The address of
663 	 * that structure is not fixed, it's kind of a linked list.
664 	 * The Capabilities Pointer reg (8 bits) is always at 0x34.
665 	 * It contains a pointer to the first capabilities structure.
666 	 * For each capability structure, the first 8 bits is the capability
667 	 * ID. The next 8 bits is the pointer to the next structure.
668 	 * If the Next Cap register is zero, it's the end of the list.
669 	 * The capability ID for the PCI-E strucutre is 0x10.  The idea
670 	 * is to follow the links until you find a Cap ID of 0x10, then
671 	 * read the registers at 0xc and 0x12 from there.
672 	 * If there's no Cap ID 0x10, then it's not a PCI-E device.
673 	 */
674 
675 	cap_ptr = read_byte(fd, bus, dev, func, PCI_CONF_CAP_PTR, &ret);
676 	if (ret != 0) {
677 		/* ioctl failure */
678 		close(fd);
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 		close(fd);
685 		return (PICL_FAILURE);
686 	}
687 	*type = PCI;
688 	capid = cap_reg & PCI_CAP_MASK;
689 	while (cap_ptr != 0) {
690 
691 		if (capid == PCI_CAP_ID_PCI_E) {
692 			link_cap = read_long(fd, bus, dev, func, cap_ptr +
693 			    PCIE_LINKCAP, &ret);
694 			if (ret != 0) {
695 				close(fd);
696 				return (PICL_FAILURE);
697 			}
698 			link_status = read_word(fd, bus, dev, func,
699 			    cap_ptr + PCIE_LINKSTS, &ret);
700 			if (ret != 0) {
701 				close(fd);
702 				return (PICL_FAILURE);
703 			}
704 			*actual = ((link_status >> PCI_LINK_SHIFT) &
705 			    PCI_LINK_MASK);
706 			*maximum = ((link_cap >> PCI_LINK_SHIFT) &
707 			    PCI_LINK_MASK);
708 			*type = PCIE;
709 		} else if (capid == PCI_CAP_ID_PCIX) {
710 			uint32_t pcix_status;
711 			uint8_t hdr_type;
712 			int max_speed = PCI_FREQ_66;
713 
714 			hdr_type = read_byte
715 			    (fd, bus, dev, func, PCI_CONF_HEADER, &ret);
716 			if (ret != 0) {
717 				/* ioctl failure */
718 				close(fd);
719 				return (PICL_FAILURE);
720 			}
721 			*type = PCIX;
722 			if ((hdr_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
723 				/* This is a PCI-X bridge */
724 				uint16_t sec_status, mode;
725 				sec_status = read_word(fd, bus, dev, func,
726 				    cap_ptr + PCI_PCIX_SEC_STATUS, &ret);
727 				if (ret != 0) {
728 					/* ioctl failure */
729 					close(fd);
730 					return (PICL_FAILURE);
731 				}
732 				if (sec_status & PCI_SEC_133)
733 					max_speed = PCI_FREQ_133;
734 				if (sec_status & PCI_SEC_266)
735 					max_speed = PCI_FREQ_266;
736 				if (sec_status & PCI_SEC_533)
737 					max_speed = PCI_FREQ_533;
738 				*speed_max = max_speed;
739 				mode = (sec_status >> PCI_CLASS_BRIDGE) &
740 				    PCI_BRIDGE_MC;
741 				if (mode) {
742 					int speed;
743 					if (mode == PCI_MODE_66)
744 						speed = PCI_FREQ_66;
745 					else if (mode == PCI_MODE_100)
746 						speed = PCI_FREQ_100;
747 					else if (mode == PCI_MODE_133)
748 						speed = PCI_FREQ_133;
749 					*speed_at = speed;
750 				}
751 
752 			} else {  /* Leaf device */
753 				pcix_status = read_long(fd, bus, dev, func,
754 				    cap_ptr + PCI_PCIX_STATUS, &ret);
755 				if (ret != 0) {
756 					/* ioctl failure */
757 					close(fd);
758 					return (PICL_FAILURE);
759 				}
760 				if (pcix_status &
761 				    (PCI_LEAF_ULONG << PCI_SHIFT_133))
762 					max_speed = PCI_FREQ_133;
763 				if (pcix_status &
764 				    (PCI_LEAF_ULONG << PCI_SHIFT_266))
765 					max_speed = PCI_FREQ_266;
766 				if (pcix_status &
767 				    (PCI_LEAF_ULONG << PCI_SHIFT_533))
768 					max_speed = PCI_FREQ_533;
769 				*speed_max = max_speed;
770 			}
771 		}
772 		cap_ptr = (cap_reg >> PCI_REG_FUNC_SHIFT);
773 		cap_reg = read_word(fd, bus, dev, func, cap_ptr, &ret);
774 		if (ret != 0) {
775 			/* ioctl failure */
776 			close(fd);
777 			return (PICL_FAILURE);
778 		}
779 		capid = cap_reg & PCI_CAP_MASK;
780 	}
781 
782 	if (close(fd) == -1) {
783 		return (PICL_FAILURE);
784 	}
785 
786 	return (PICL_SUCCESS);
787 }
788 
789 /*
790  * get the clock frequency
791  */
792 static int
793 picldiag_get_clock_freq(picl_nodehdl_t modh, uint32_t *freq)
794 {
795 	int		err;
796 	uint64_t	clk_freq;
797 
798 	clk_freq = picldiag_get_uint_propval(modh, OBP_PROP_CLOCK_FREQ, &err);
799 	if (err != PICL_SUCCESS)
800 		return (err);
801 
802 	*freq = ROUND_TO_MHZ(clk_freq);
803 
804 	return (PICL_SUCCESS);
805 }
806 
807 static uint64_t
808 picldiag_get_uint_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
809 {
810 	int		err;
811 	picl_prophdl_t	proph;
812 	picl_propinfo_t pinfo;
813 	uint8_t		uint8v;
814 	uint16_t	uint16v;
815 	uint32_t	uint32v;
816 	uint64_t	uint64v;
817 
818 	err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
819 	if (err != PICL_SUCCESS) {
820 		*ret = err;
821 		return (0);
822 	}
823 
824 	/*
825 	 * If it is not an int or uint prop, return failure
826 	 */
827 	if ((pinfo.type != PICL_PTYPE_INT) &&
828 	    (pinfo.type != PICL_PTYPE_UNSIGNED_INT)) {
829 		*ret = PICL_FAILURE;
830 		return (0);
831 	}
832 
833 
834 	/* uint prop */
835 
836 	switch (pinfo.size) {
837 	case sizeof (uint8_t):
838 		err = picl_get_propval(proph, &uint8v, sizeof (uint8v));
839 		*ret = err;
840 		return (uint8v);
841 	case sizeof (uint16_t):
842 		err = picl_get_propval(proph, &uint16v, sizeof (uint16v));
843 		*ret = err;
844 		return (uint16v);
845 	case sizeof (uint32_t):
846 		err = picl_get_propval(proph, &uint32v, sizeof (uint32v));
847 		*ret = err;
848 		return (uint32v);
849 	case sizeof (uint64_t):
850 		err = picl_get_propval(proph, &uint64v, sizeof (uint64v));
851 		*ret = err;
852 		return (uint64v);
853 	default:	/* not supported size */
854 		*ret = PICL_FAILURE;
855 		return (0);
856 	}
857 }
858 
859 /*
860  * recursively visit all nodes
861  */
862 static picl_errno_t
863 do_walk(picl_nodehdl_t rooth, const char *classname,
864     void *c_args, picl_errno_t (*callback_fn)(picl_nodehdl_t hdl, void *args))
865 {
866 	picl_errno_t	err;
867 	picl_nodehdl_t  chdh;
868 	char		classval[PICL_CLASSNAMELEN_MAX];
869 
870 	err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh,
871 	    sizeof (chdh));
872 	while (err == PICL_SUCCESS) {
873 		err = picl_get_propval_by_name(chdh, PICL_PROP_NAME,
874 		    classval, sizeof (classval));
875 		if (err != PICL_SUCCESS)
876 			return (err);
877 
878 		err = callback_fn(chdh, c_args);
879 
880 		if ((err = do_walk(chdh, classname, c_args, callback_fn)) !=
881 		    PICL_WALK_CONTINUE)
882 			return (err);
883 
884 		err = picl_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
885 		    sizeof (chdh));
886 	}
887 	if (err == PICL_PROPNOTFOUND)   /* end of a branch */
888 		return (PICL_WALK_CONTINUE);
889 	return (err);
890 }
891 
892 int
893 get_proc_mode(void)
894 {
895 	picl_nodehdl_t nodeh;
896 	picl_prophdl_t  proph;
897 	picl_errno_t err;
898 
899 	err = picl_initialize();
900 	if (err != PICL_SUCCESS) {
901 		(void) log_printf("picl_initialize failed: %s\n",
902 		    picl_strerror(err));
903 		return (err);
904 	}
905 
906 	err = picl_get_node_by_path("/platform",  &nodeh);
907 	if (err != PICL_SUCCESS) {
908 		(void) log_printf("Getting plat node failed: %s\n",
909 		    picl_strerror(err));
910 		return (err);
911 	}
912 
913 	err = picl_get_prop_by_name(nodeh, "SPARC64-VII-mode",  &proph);
914 	if (err != PICL_SUCCESS) {
915 		/* Do not display error message */
916 		return (err);
917 	}
918 
919 	(void) picl_shutdown();
920 
921 	return (err);
922 }
923