13d808a52Ssubhan /*
23d808a52Ssubhan  * CDDL HEADER START
33d808a52Ssubhan  *
43d808a52Ssubhan  * The contents of this file are subject to the terms of the
53d808a52Ssubhan  * Common Development and Distribution License (the "License").
63d808a52Ssubhan  * You may not use this file except in compliance with the License.
73d808a52Ssubhan  *
83d808a52Ssubhan  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93d808a52Ssubhan  * or http://www.opensolaris.org/os/licensing.
103d808a52Ssubhan  * See the License for the specific language governing permissions
113d808a52Ssubhan  * and limitations under the License.
123d808a52Ssubhan  *
133d808a52Ssubhan  * When distributing Covered Code, include this CDDL HEADER in each
143d808a52Ssubhan  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153d808a52Ssubhan  * If applicable, add the following below this CDDL HEADER, with the
163d808a52Ssubhan  * fields enclosed by brackets "[]" replaced with your own identifying
173d808a52Ssubhan  * information: Portions Copyright [yyyy] [name of copyright owner]
183d808a52Ssubhan  *
193d808a52Ssubhan  * CDDL HEADER END
203d808a52Ssubhan  */
213d808a52Ssubhan /*
22*abe610a3SMichael Bergknoff  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
233d808a52Ssubhan  * Use is subject to license terms.
243d808a52Ssubhan  *
253d808a52Ssubhan  * Opl platform specific PICL functions.
263d808a52Ssubhan  *
273d808a52Ssubhan  * 	called when :
283d808a52Ssubhan  *	machine_type == MTYPE_OPL
293d808a52Ssubhan  */
303d808a52Ssubhan 
313d808a52Ssubhan #include <stdio.h>
323d808a52Ssubhan #include <stdlib.h>
333d808a52Ssubhan #include <unistd.h>
343d808a52Ssubhan #include <kstat.h>
353d808a52Ssubhan #include <fcntl.h>
363d808a52Ssubhan #include <string.h>
373d808a52Ssubhan #include <assert.h>
383d808a52Ssubhan #include <libintl.h>
393d808a52Ssubhan #include <note.h>
403d808a52Ssubhan #include <dlfcn.h>
413d808a52Ssubhan #include <errno.h>
423d808a52Ssubhan #include <sys/systeminfo.h>
433d808a52Ssubhan #include <sys/openpromio.h>
443d808a52Ssubhan #include <sys/sysmacros.h>
453d808a52Ssubhan #include <picl.h>
463d808a52Ssubhan #include "picldefs.h"
473d808a52Ssubhan #include <pdevinfo.h>
483d808a52Ssubhan #include <display.h>
493d808a52Ssubhan #include <libprtdiag.h>
503d808a52Ssubhan #include <alloca.h>
513d808a52Ssubhan #include "opl_picl.h"
523d808a52Ssubhan #include <sys/pci.h>
533d808a52Ssubhan #include <sys/pci_tools.h>
543d808a52Ssubhan #include <sys/types.h>
553d808a52Ssubhan 
563d808a52Ssubhan #if !defined(TEXT_DOMAIN)
573d808a52Ssubhan #define	TEXT_DOMAIN	"SYS_TEST"
583d808a52Ssubhan #endif
593d808a52Ssubhan 
603d808a52Ssubhan static picl_errno_t do_walk(picl_nodehdl_t rooth, const char *classname,
613d808a52Ssubhan     void *c_args, picl_errno_t (*callback_fn)(picl_nodehdl_t hdl, void *args));
623d808a52Ssubhan static int opl_get_node_by_name(picl_nodehdl_t rooth, char *name,
633d808a52Ssubhan     picl_nodehdl_t *nodeh);
643d808a52Ssubhan static picl_errno_t get_lane_width(char *device_path, int bus_no, int func_no,
653d808a52Ssubhan     int dev_no, int *actual, int *maximum, uint32_t *speed_max,
663d808a52Ssubhan     uint32_t *speed_at, int *type);
673d808a52Ssubhan static int	opl_display_pci(int syserrlog, picl_nodehdl_t plafh);
683d808a52Ssubhan static picl_errno_t opl_pci_callback(picl_nodehdl_t pcih, void *args);
693d808a52Ssubhan static int opl_get_first_compatible_value(picl_nodehdl_t nodeh,
703d808a52Ssubhan     char **outbuf);
713d808a52Ssubhan static int picldiag_get_clock_freq(picl_nodehdl_t modh,
72*abe610a3SMichael Bergknoff     uint32_t *freq, uint32_t *freq_max);
733d808a52Ssubhan static uint64_t picldiag_get_uint_propval(picl_nodehdl_t modh,
743d808a52Ssubhan     char *prop_name, int *ret);
753d808a52Ssubhan static uint32_t	read_long(int fd, int bus, int dev, int func,
763d808a52Ssubhan     int offset, int *ret);
773d808a52Ssubhan static uint8_t read_byte(int fd, int bus, int dev, int func, int offset,
783d808a52Ssubhan     int *ret);
793d808a52Ssubhan static uint16_t read_word(int fd, int bus, int dev, int func, int offset,
803d808a52Ssubhan     int *ret);
813d808a52Ssubhan 
823d808a52Ssubhan /*
833d808a52Ssubhan  * Collect I/O nodes information.
843d808a52Ssubhan  */
853d808a52Ssubhan /* ARGSUSED */
863d808a52Ssubhan static picl_errno_t
opl_pci_callback(picl_nodehdl_t pcih,void * args)873d808a52Ssubhan opl_pci_callback(picl_nodehdl_t pcih, void *args)
883d808a52Ssubhan {
893d808a52Ssubhan 	picl_errno_t	err = PICL_SUCCESS;
903d808a52Ssubhan 	picl_nodehdl_t	nodeh;
913d808a52Ssubhan 	picl_prophdl_t  proph;
923d808a52Ssubhan 	picl_propinfo_t pinfo;
933d808a52Ssubhan 	char		path[MAXSTRLEN];
943d808a52Ssubhan 	char		parent_path[MAXSTRLEN];
953d808a52Ssubhan 	static char	root_path[MAXSTRLEN];
963d808a52Ssubhan 	char		piclclass[PICL_CLASSNAMELEN_MAX];
973d808a52Ssubhan 	char		name[MAXSTRLEN];
983d808a52Ssubhan 	char		model[MAXSTRLEN];
993d808a52Ssubhan 	char		*compatible;
1003d808a52Ssubhan 	char		binding_name[MAXSTRLEN];
1013d808a52Ssubhan 	struct io_card	pci_card;
1023d808a52Ssubhan 	char		status[6] = "N/A";
1033d808a52Ssubhan 	int		portid = PROP_INVALID;
1043d808a52Ssubhan 	int		*reg_val;
1053d808a52Ssubhan 	int		board = PROP_INVALID;
1063d808a52Ssubhan 	static int	saved_board = PROP_INVALID;
1073d808a52Ssubhan 	static int	saved_portid = PROP_INVALID;
1083d808a52Ssubhan 	int 		actual = PROP_INVALID, maximum = PROP_INVALID;
1093d808a52Ssubhan 	int 		bus_type;
1103d808a52Ssubhan 	int 		rev_id = PROP_INVALID, dev_id = PROP_INVALID;
1113d808a52Ssubhan 	int		ven_id = PROP_INVALID;
1123d808a52Ssubhan 	size_t		prop_size;
1133d808a52Ssubhan 
1143d808a52Ssubhan 	(void) memset(&pci_card, 0, sizeof (pci_card));
1153d808a52Ssubhan 
1163d808a52Ssubhan 	err = picl_get_propval_by_name(pcih, PICL_PROP_CLASSNAME,
1172917a9c9Sschwartz 	    piclclass, sizeof (piclclass));
1183d808a52Ssubhan 
1193d808a52Ssubhan 	if (err !=  PICL_SUCCESS)
1203d808a52Ssubhan 		/* Do not proceed to parse this branch */
1213d808a52Ssubhan 		return (err);
1223d808a52Ssubhan 
1233d808a52Ssubhan 	if (!IS_PCI(piclclass))
1243d808a52Ssubhan 		/* Do not parse non-pci nodes */
1253d808a52Ssubhan 		return (PICL_INVALIDARG);
1263d808a52Ssubhan 
1273d808a52Ssubhan 	err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, parent_path,
1283d808a52Ssubhan 	    sizeof (parent_path));
1293d808a52Ssubhan 	if (err != PICL_SUCCESS)
1303d808a52Ssubhan 		/* Do not proceed to parse this branch */
1313d808a52Ssubhan 		return (err);
1323d808a52Ssubhan 	err = picl_get_propval_by_name(pcih, OBP_PROP_BOARD_NUM, &board,
1332917a9c9Sschwartz 	    sizeof (board));
1343d808a52Ssubhan 
1353d808a52Ssubhan 	if (err == PICL_NORESPONSE)
1363d808a52Ssubhan 		/* Do not proceed to parse this branch */
1373d808a52Ssubhan 		return (err);
1383d808a52Ssubhan 	else if (err != PICL_PROPNOTFOUND) {
1393d808a52Ssubhan 		saved_board = board;
1403d808a52Ssubhan 		/* Save board node's pathname */
1413d808a52Ssubhan 		prop_size = sizeof (parent_path) + 1;
1423d808a52Ssubhan 		if (prop_size > MAXSTRLEN)
1433d808a52Ssubhan 			prop_size = MAXSTRLEN;
1443d808a52Ssubhan 		(void) strlcpy(root_path, parent_path, prop_size);
1453d808a52Ssubhan 	}
1463d808a52Ssubhan 
1473d808a52Ssubhan 	err = picl_get_propval_by_name
1482917a9c9Sschwartz 	    (pcih, OBP_PROP_PORTID, &portid, sizeof (portid));
1493d808a52Ssubhan 
1503d808a52Ssubhan 	if (err != PICL_PROPNOTFOUND)
1513d808a52Ssubhan 		saved_portid = portid;
1523d808a52Ssubhan 
1533d808a52Ssubhan 	/* Walk through the children */
1543d808a52Ssubhan 
1553d808a52Ssubhan 	err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
1563d808a52Ssubhan 	    sizeof (picl_nodehdl_t));
1573d808a52Ssubhan 
1583d808a52Ssubhan 	while (err == PICL_SUCCESS) {
1593d808a52Ssubhan 		uint32_t	freq_max = 0, freq_at = 0;
1603d808a52Ssubhan 
1613d808a52Ssubhan 		err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
1623d808a52Ssubhan 		    piclclass, sizeof (piclclass));
1633d808a52Ssubhan 		if (err !=  PICL_SUCCESS)
1643d808a52Ssubhan 			/* Do not proceed to parse this node */
1653d808a52Ssubhan 			return (err);
1663d808a52Ssubhan 
1673d808a52Ssubhan 		if (IS_EBUS(piclclass)) {
1683d808a52Ssubhan 			err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
1692917a9c9Sschwartz 			    &nodeh, sizeof (picl_nodehdl_t));
1703d808a52Ssubhan 			continue;
1713d808a52Ssubhan 		}
1723d808a52Ssubhan 
1733d808a52Ssubhan 		err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH,
1743d808a52Ssubhan 		    path, sizeof (path));
1753d808a52Ssubhan 		if (err != PICL_SUCCESS) {
1763d808a52Ssubhan 			/* Do not proceed to parse this node */
1773d808a52Ssubhan 			return (err);
1783d808a52Ssubhan 		}
1793d808a52Ssubhan 
1803d808a52Ssubhan 		prop_size = sizeof (path) + 1;
1813d808a52Ssubhan 		if (prop_size > MAXSTRLEN)
1823d808a52Ssubhan 			prop_size = MAXSTRLEN;
1833d808a52Ssubhan 		(void) strlcpy(pci_card.notes, path, prop_size);
1843d808a52Ssubhan 
1853d808a52Ssubhan 		pci_card.board = saved_board;
1863d808a52Ssubhan 		pci_card.schizo_portid = saved_portid;
1873d808a52Ssubhan 
1883d808a52Ssubhan 		/*
1893d808a52Ssubhan 		 * Get bus#, dev# and func# for this card from 'reg' property.
1903d808a52Ssubhan 		 */
1913d808a52Ssubhan 
1923d808a52Ssubhan 		err = picl_get_propinfo_by_name
1932917a9c9Sschwartz 		    (nodeh, OBP_PROP_REG, &pinfo, &proph);
1943d808a52Ssubhan 		if (err == PICL_SUCCESS) {
1953d808a52Ssubhan 			/* All of the array of bytes of "reg" have to be read */
1963d808a52Ssubhan 			reg_val = malloc(pinfo.size);
1973d808a52Ssubhan 			if (reg_val == NULL)
1983d808a52Ssubhan 				return (PICL_FAILURE);
1993d808a52Ssubhan 
2003d808a52Ssubhan 
2013d808a52Ssubhan 			err = picl_get_propval_by_name
2023d808a52Ssubhan 			    (nodeh, OBP_PROP_REG, reg_val, pinfo.size);
2033d808a52Ssubhan 
2043d808a52Ssubhan 			if (err != PICL_SUCCESS) {
2053d808a52Ssubhan 				free(reg_val);
2063d808a52Ssubhan 				/* Do not proceed to parse this node */
2073d808a52Ssubhan 				return (err);
2083d808a52Ssubhan 			}
2093d808a52Ssubhan 
2103d808a52Ssubhan 			if (reg_val[0] != 0) {
2113d808a52Ssubhan 				pci_card.dev_no =
2122917a9c9Sschwartz 				    (((reg_val[0]) & PCI_DEV_MASK) >> 11);
2133d808a52Ssubhan 				pci_card.func_no =
2142917a9c9Sschwartz 				    (((reg_val[0]) & PCI_FUNC_MASK) >> 8);
2153d808a52Ssubhan 				pci_card.slot =
2162917a9c9Sschwartz 				    (((reg_val[0]) & PCI_BUS_MASK) >> 16);
2173d808a52Ssubhan 			} else
2183d808a52Ssubhan 				free(reg_val);
2193d808a52Ssubhan 		}
2203d808a52Ssubhan 
2212917a9c9Sschwartz 		err = get_lane_width(root_path, pci_card.slot, pci_card.dev_no,
2222917a9c9Sschwartz 		    pci_card.func_no, &actual, &maximum, &freq_max, &freq_at,
2232917a9c9Sschwartz 		    &bus_type);
2243d808a52Ssubhan 
2253d808a52Ssubhan 		if (err != PICL_SUCCESS) {
226a7480016Smb 			/*
227a7480016Smb 			 * get_lane_width will fail when run as non-root.
228a7480016Smb 			 * Set bus_type to PCI_UNKN so that bus frequency,
229a7480016Smb 			 * bus type and lane width will print as "--" or UNKN.
230a7480016Smb 			 */
231a7480016Smb 			bus_type = PCI_UNKN;
2323d808a52Ssubhan 		}
2333d808a52Ssubhan 
2343d808a52Ssubhan 
2353d808a52Ssubhan 		err = picl_get_propval_by_name
2363d808a52Ssubhan 		    (nodeh, PICL_PROP_NAME, name, sizeof (name));
2373d808a52Ssubhan 		if (err != PICL_SUCCESS)
2383d808a52Ssubhan 			(void) strcpy(name, "");
2393d808a52Ssubhan 
2403d808a52Ssubhan 		/*
2413d808a52Ssubhan 		 * Get the name of this card. If binding_name is found,
2423d808a52Ssubhan 		 * name will be <nodename>-<binding_name>
2433d808a52Ssubhan 		 */
2443d808a52Ssubhan 
2453d808a52Ssubhan 		err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
2463d808a52Ssubhan 		    binding_name, sizeof (binding_name));
2473d808a52Ssubhan 		if (err == PICL_PROPNOTFOUND) {
2483d808a52Ssubhan 			/*
2493d808a52Ssubhan 			 * if compatible prop is found, name will be
2503d808a52Ssubhan 			 * <nodename>-<compatible>
2513d808a52Ssubhan 			 */
2523d808a52Ssubhan 			err = opl_get_first_compatible_value(nodeh,
2533d808a52Ssubhan 			    &compatible);
2543d808a52Ssubhan 			if (err == PICL_SUCCESS) {
2553d808a52Ssubhan 				(void) strlcat(name, "-", MAXSTRLEN);
2563d808a52Ssubhan 				(void) strlcat(name, compatible, MAXSTRLEN);
2573d808a52Ssubhan 				free(compatible);
2583d808a52Ssubhan 			}
2593d808a52Ssubhan 		} else if (err != PICL_SUCCESS) {
2603d808a52Ssubhan 			/* No binding-name or compatible */
2613d808a52Ssubhan 			(void) strcpy(binding_name, "N/A");
2623d808a52Ssubhan 		} else if (strcmp(name, binding_name) != 0) {
2633d808a52Ssubhan 			(void) strlcat(name, "-", MAXSTRLEN);
2643d808a52Ssubhan 			(void) strlcat(name, binding_name, MAXSTRLEN);
2653d808a52Ssubhan 		}
2663d808a52Ssubhan 
2673d808a52Ssubhan 
2683d808a52Ssubhan 		prop_size = sizeof (name) + 1;
2693d808a52Ssubhan 		if (prop_size > MAXSTRLEN)
2703d808a52Ssubhan 			prop_size =  MAXSTRLEN;
2713d808a52Ssubhan 		(void) strlcpy(pci_card.name, name, prop_size);
2723d808a52Ssubhan 
2733d808a52Ssubhan 		/* Get the status of the card */
2743d808a52Ssubhan 		err = picl_get_propval_by_name
2753d808a52Ssubhan 		    (nodeh, PICL_PROP_STATUS, status, sizeof (status));
2763d808a52Ssubhan 
2773d808a52Ssubhan 
2783d808a52Ssubhan 		/* Get the model of this card */
2793d808a52Ssubhan 
2803d808a52Ssubhan 		err = picl_get_propval_by_name
2813d808a52Ssubhan 		    (nodeh, OBP_PROP_MODEL, model, sizeof (model));
2823d808a52Ssubhan 		prop_size = sizeof (model) + 1;
2833d808a52Ssubhan 		if (prop_size > MAXSTRLEN)
2843d808a52Ssubhan 			prop_size =  MAXSTRLEN;
2853d808a52Ssubhan 		if (err != PICL_SUCCESS)
2863d808a52Ssubhan 			(void) strcpy(model, "N/A");
2873d808a52Ssubhan 		(void) strlcpy(pci_card.model, model, prop_size);
2883d808a52Ssubhan 
2893d808a52Ssubhan 		if (bus_type == PCI)
2902917a9c9Sschwartz 			(void) strlcpy(pci_card.bus_type,
2912917a9c9Sschwartz 			    "PCI", sizeof (pci_card.bus_type));
2923d808a52Ssubhan 		else if (bus_type == PCIX)
2932917a9c9Sschwartz 			(void) strlcpy(pci_card.bus_type,
2942917a9c9Sschwartz 			    "PCIx", sizeof (pci_card.bus_type));
2953d808a52Ssubhan 		else if (bus_type == PCIE)
2962917a9c9Sschwartz 			(void) strlcpy(pci_card.bus_type,
2972917a9c9Sschwartz 			    "PCIe", sizeof (pci_card.bus_type));
2983d808a52Ssubhan 		else
2992917a9c9Sschwartz 			(void) strlcpy(pci_card.bus_type,
3002917a9c9Sschwartz 			    "UNKN", sizeof (pci_card.bus_type));
3013d808a52Ssubhan 
3023d808a52Ssubhan 		/* Get revision id */
3033d808a52Ssubhan 		err = picl_get_propval_by_name
3042917a9c9Sschwartz 		    (nodeh, OBP_PROP_REVISION_ID, &rev_id, sizeof (rev_id));
3053d808a52Ssubhan 
3063d808a52Ssubhan 		/* Get device id */
3073d808a52Ssubhan 		err = picl_get_propval_by_name
3082917a9c9Sschwartz 		    (nodeh, OBP_PROP_DEVICE_ID, &dev_id, sizeof (dev_id));
3093d808a52Ssubhan 
3103d808a52Ssubhan 		/* Get vendor id */
3113d808a52Ssubhan 		err = picl_get_propval_by_name
3122917a9c9Sschwartz 		    (nodeh, OBP_PROP_VENDOR_ID, &ven_id, sizeof (ven_id));
3133d808a52Ssubhan 
3143d808a52Ssubhan 		/*
3153d808a52Ssubhan 		 * prtdiag -v prints all devices
3163d808a52Ssubhan 		 */
3173d808a52Ssubhan 
3183d808a52Ssubhan 		/* Print board number */
3193d808a52Ssubhan 		log_printf("%02d  ", pci_card.board);
3203d808a52Ssubhan 		/* Print IO Type */
3213d808a52Ssubhan 		log_printf("%-5.5s ", pci_card.bus_type);
3223d808a52Ssubhan 
3233d808a52Ssubhan 		log_printf("%-3d  ", pci_card.schizo_portid);
3243d808a52Ssubhan 		log_printf("%4x, %4x, %4x     ", rev_id, dev_id, ven_id);
3253d808a52Ssubhan 
3262917a9c9Sschwartz 		log_printf("%3d, %2d, %2d",
3272917a9c9Sschwartz 		    pci_card.slot, pci_card.dev_no, pci_card.func_no);
3283d808a52Ssubhan 
3293d808a52Ssubhan 		/* Print status */
3303d808a52Ssubhan 		log_printf("  %-5.5s ", status);
3313d808a52Ssubhan 
3323d808a52Ssubhan 		/* Print Lane widths, Max/Sup Freq, Speed */
3333d808a52Ssubhan 		if (bus_type == PCIE) {
3343d808a52Ssubhan 			PRINT_FMT(actual, maximum);
3353d808a52Ssubhan 		} else if (bus_type == PCIX) {
3363d808a52Ssubhan 			PRINT_FREQ_FMT(freq_at, freq_max);
3373d808a52Ssubhan 		} else if (bus_type == PCI) {
338*abe610a3SMichael Bergknoff 			err = picldiag_get_clock_freq(nodeh, &freq_at,
339*abe610a3SMichael Bergknoff 			    &freq_max);
3403d808a52Ssubhan 			PRINT_FREQ_FMT(freq_at, freq_max);
3413d808a52Ssubhan 		} else
3423d808a52Ssubhan 			log_printf(" -- , --   ");
3433d808a52Ssubhan 
3443d808a52Ssubhan 		/* Print Card Name */
3453d808a52Ssubhan 		log_printf("%-30.30s", pci_card.name);
3463d808a52Ssubhan 
3473d808a52Ssubhan 		/* Print Card Model */
3483d808a52Ssubhan 		log_printf(" %-20.20s", pci_card.model);
3493d808a52Ssubhan 
3503d808a52Ssubhan 		log_printf("\n");
3513d808a52Ssubhan 
3523d808a52Ssubhan 		log_printf("%4s%-100.100s", " ", pci_card.notes);
3533d808a52Ssubhan 		log_printf("\n");
3543d808a52Ssubhan 		log_printf("\n");
3553d808a52Ssubhan 
3563d808a52Ssubhan 
3573d808a52Ssubhan 		err = picl_get_propval_by_name
3583d808a52Ssubhan 		    (nodeh, PICL_PROP_PEER, &nodeh, sizeof (picl_nodehdl_t));
3593d808a52Ssubhan 
3603d808a52Ssubhan 	}
3613d808a52Ssubhan 
3623d808a52Ssubhan 	return (PICL_WALK_CONTINUE);
3633d808a52Ssubhan }
3643d808a52Ssubhan 
3653d808a52Ssubhan /*
3663d808a52Ssubhan  * opl_display_pci
3673d808a52Ssubhan  * Display all the PCI IO cards on this board.
3683d808a52Ssubhan  */
3693d808a52Ssubhan static int
opl_display_pci(int syserrlog,picl_nodehdl_t plafh)3703d808a52Ssubhan opl_display_pci(int syserrlog, picl_nodehdl_t plafh)
3713d808a52Ssubhan {
3723d808a52Ssubhan 	picl_errno_t err;
3733d808a52Ssubhan 	char	*fmt = "%-3s %-5s %-4s %-20s %-11s %-5s %-11s %-30s %-20s";
3743d808a52Ssubhan 	char 	*fmt2 = "%-16s";
3753d808a52Ssubhan 	static int banner = FALSE; /* Have we printed the column headings? */
3763d808a52Ssubhan 
3773d808a52Ssubhan 	if (banner == FALSE) {
3783d808a52Ssubhan 		log_printf("\n", 0);
3793d808a52Ssubhan 		log_printf("=========================", 0);
3803d808a52Ssubhan 		log_printf(dgettext(TEXT_DOMAIN, " IO Devices "), 0);
3813d808a52Ssubhan 		log_printf("=========================", 0);
3823d808a52Ssubhan 		log_printf("\n", 0);
3833d808a52Ssubhan 		log_printf("\n", 0);
3843d808a52Ssubhan 		log_printf(fmt, "", "IO", "", "", "", "", "Lane/Frq",
3852917a9c9Sschwartz 		    "", "", 0);
3863d808a52Ssubhan 		log_printf("\n", 0);
3873d808a52Ssubhan 
3883d808a52Ssubhan 		log_printf(fmt, "LSB", "Type", "LPID", "  RvID,DvID,VnID",
3892917a9c9Sschwartz 		    "  BDF", "State", "Act,  Max", "Name", "Model", 0);
3903d808a52Ssubhan 
3913d808a52Ssubhan 		log_printf("\n");
3923d808a52Ssubhan 
3932917a9c9Sschwartz 		log_printf(fmt,
3942917a9c9Sschwartz 		    "---", "-----", "----", "  ------------------",
3952917a9c9Sschwartz 		    "  ---------", "-----", "-----------",
3962917a9c9Sschwartz 		    "------------------------------",
3972917a9c9Sschwartz 		    "--------------------", 0);
3983d808a52Ssubhan 		log_printf("\n");
3993d808a52Ssubhan 		log_printf(fmt2, "    Logical Path");
4003d808a52Ssubhan 		log_printf("\n");
4013d808a52Ssubhan 		log_printf(fmt2, "    ------------");
4023d808a52Ssubhan 		log_printf("\n");
4033d808a52Ssubhan 		banner = TRUE;
4043d808a52Ssubhan 	}
4053d808a52Ssubhan 
4063d808a52Ssubhan 	err = do_walk(plafh, PICL_CLASS_PCI, PICL_CLASS_PCI, opl_pci_callback);
4073d808a52Ssubhan 	return (err);
4083d808a52Ssubhan }
4093d808a52Ssubhan 
4103d808a52Ssubhan 
4113d808a52Ssubhan /*
4123d808a52Ssubhan  * return the first compatible value
4133d808a52Ssubhan  */
4143d808a52Ssubhan static int
opl_get_first_compatible_value(picl_nodehdl_t nodeh,char ** outbuf)4153d808a52Ssubhan opl_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
4163d808a52Ssubhan {
4173d808a52Ssubhan 	picl_errno_t	err;
4183d808a52Ssubhan 	picl_prophdl_t	proph;
4193d808a52Ssubhan 	picl_propinfo_t	pinfo;
4203d808a52Ssubhan 	picl_prophdl_t	tblh;
4213d808a52Ssubhan 	picl_prophdl_t	rowproph;
4223d808a52Ssubhan 	char		*pval;
4233d808a52Ssubhan 
4243d808a52Ssubhan 	err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
4253d808a52Ssubhan 	    &pinfo, &proph);
4263d808a52Ssubhan 	if (err != PICL_SUCCESS)
4272917a9c9Sschwartz 		return (err);
4283d808a52Ssubhan 
4293d808a52Ssubhan 	if (pinfo.type == PICL_PTYPE_CHARSTRING) {
4303d808a52Ssubhan 		pval = malloc(pinfo.size);
4313d808a52Ssubhan 		if (pval == NULL)
4323d808a52Ssubhan 			return (PICL_FAILURE);
4333d808a52Ssubhan 		err = picl_get_propval(proph, pval, pinfo.size);
4343d808a52Ssubhan 		if (err != PICL_SUCCESS) {
4353d808a52Ssubhan 			free(pval);
4363d808a52Ssubhan 			return (err);
4373d808a52Ssubhan 		}
4383d808a52Ssubhan 		*outbuf = pval;
4393d808a52Ssubhan 		return (PICL_SUCCESS);
4403d808a52Ssubhan 	}
4413d808a52Ssubhan 
4423d808a52Ssubhan 	if (pinfo.type != PICL_PTYPE_TABLE)
4433d808a52Ssubhan 		return (PICL_FAILURE);
4443d808a52Ssubhan 
4453d808a52Ssubhan 	/* get first string from table */
4463d808a52Ssubhan 	err = picl_get_propval(proph, &tblh, pinfo.size);
4473d808a52Ssubhan 	if (err != PICL_SUCCESS)
4483d808a52Ssubhan 		return (err);
4493d808a52Ssubhan 
4503d808a52Ssubhan 	err = picl_get_next_by_row(tblh, &rowproph);
4513d808a52Ssubhan 	if (err != PICL_SUCCESS)
4523d808a52Ssubhan 		return (err);
4533d808a52Ssubhan 
4543d808a52Ssubhan 	err = picl_get_propinfo(rowproph, &pinfo);
4553d808a52Ssubhan 	if (err != PICL_SUCCESS)
4562917a9c9Sschwartz 		return (err);
4573d808a52Ssubhan 
4583d808a52Ssubhan 	pval = malloc(pinfo.size);
4593d808a52Ssubhan 	if (pval == NULL)
4603d808a52Ssubhan 		return (PICL_FAILURE);
4613d808a52Ssubhan 
4623d808a52Ssubhan 	err = picl_get_propval(rowproph, pval, pinfo.size);
4633d808a52Ssubhan 	if (err != PICL_SUCCESS) {
4643d808a52Ssubhan 		free(pval);
4653d808a52Ssubhan 		return (err);
4663d808a52Ssubhan 	}
4673d808a52Ssubhan 
4683d808a52Ssubhan 	*outbuf = pval;
4693d808a52Ssubhan 	return (PICL_SUCCESS);
4703d808a52Ssubhan }
4713d808a52Ssubhan 
4723d808a52Ssubhan int
do_piclinfo(int syserrlog)4733d808a52Ssubhan do_piclinfo(int syserrlog)
4743d808a52Ssubhan {
4753d808a52Ssubhan 	picl_nodehdl_t rooth;		/* root PICL node for IO display */
4763d808a52Ssubhan 	picl_nodehdl_t plafh;		/* Platform PICL node for IO display */
4773d808a52Ssubhan 
4783d808a52Ssubhan 	picl_errno_t err;
4793d808a52Ssubhan 
4803d808a52Ssubhan 	err = picl_initialize();
4813d808a52Ssubhan 	if (err != PICL_SUCCESS) {
4823d808a52Ssubhan 		(void) log_printf("picl_initialize failed: %s\n",
4832917a9c9Sschwartz 		    picl_strerror(err));
4843d808a52Ssubhan 		return (err);
4853d808a52Ssubhan 	}
4863d808a52Ssubhan 
4873d808a52Ssubhan 
4883d808a52Ssubhan 	err = picl_get_root(&rooth);
4893d808a52Ssubhan 	if (err != PICL_SUCCESS) {
4903d808a52Ssubhan 		(void) log_printf("Getting root node failed: %s\n",
4912917a9c9Sschwartz 		    picl_strerror(err));
4923d808a52Ssubhan 		return (err);
4933d808a52Ssubhan 	}
4943d808a52Ssubhan 
4953d808a52Ssubhan 	err = opl_get_node_by_name(rooth, PICL_NODE_PLATFORM, &plafh);
4963d808a52Ssubhan 
4973d808a52Ssubhan 	if (err != PICL_SUCCESS) {
4983d808a52Ssubhan 		(void) log_printf("Getting nodes by name failed: %s\n",
4992917a9c9Sschwartz 		    picl_strerror(err));
5003d808a52Ssubhan 		return (err);
5013d808a52Ssubhan 	}
5023d808a52Ssubhan 
5033d808a52Ssubhan 	err = opl_display_pci(syserrlog, plafh);
5043d808a52Ssubhan 
5053d808a52Ssubhan 	(void) picl_shutdown();
5063d808a52Ssubhan 
5073d808a52Ssubhan 	return (err);
5083d808a52Ssubhan }
5093d808a52Ssubhan 
5103d808a52Ssubhan /*
5113d808a52Ssubhan  * search children to get the node by the nodename
5123d808a52Ssubhan  */
5133d808a52Ssubhan static int
opl_get_node_by_name(picl_nodehdl_t rooth,char * name,picl_nodehdl_t * nodeh)5143d808a52Ssubhan opl_get_node_by_name(picl_nodehdl_t rooth, char *name,
5153d808a52Ssubhan     picl_nodehdl_t *nodeh)
5163d808a52Ssubhan {
5173d808a52Ssubhan 	picl_nodehdl_t	childh;
5183d808a52Ssubhan 	int		err;
5193d808a52Ssubhan 	char		*nodename;
5203d808a52Ssubhan 
5213d808a52Ssubhan 	nodename = alloca(strlen(name) + 1);
5223d808a52Ssubhan 	if (nodename == NULL)
5233d808a52Ssubhan 		return (PICL_FAILURE);
5243d808a52Ssubhan 
5253d808a52Ssubhan 	err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh,
5262917a9c9Sschwartz 	    sizeof (picl_nodehdl_t));
5273d808a52Ssubhan 
5283d808a52Ssubhan 	while (err == PICL_SUCCESS) {
5293d808a52Ssubhan 		err = picl_get_propval_by_name(childh, PICL_PROP_NAME,
5302917a9c9Sschwartz 		    nodename, (strlen(name) + 1));
5313d808a52Ssubhan 		if (err != PICL_SUCCESS) {
5323d808a52Ssubhan 			err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
5332917a9c9Sschwartz 			    &childh, sizeof (picl_nodehdl_t));
5343d808a52Ssubhan 			continue;
5353d808a52Ssubhan 		}
5363d808a52Ssubhan 
5373d808a52Ssubhan 		if (strcmp(nodename, name) == 0) {
5383d808a52Ssubhan 			*nodeh = childh;
5393d808a52Ssubhan 			return (PICL_SUCCESS);
5403d808a52Ssubhan 		}
5413d808a52Ssubhan 
5423d808a52Ssubhan 		err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
5432917a9c9Sschwartz 		    &childh, sizeof (picl_nodehdl_t));
5443d808a52Ssubhan 	}
5453d808a52Ssubhan 
5463d808a52Ssubhan 	return (err);
5473d808a52Ssubhan }
5483d808a52Ssubhan 
5493d808a52Ssubhan static int
open_root_complex(char * root_complex)5503d808a52Ssubhan open_root_complex(char *root_complex)
5513d808a52Ssubhan {
5523d808a52Ssubhan 	char *path;
5533d808a52Ssubhan 	static char device_str[] = {"/devices"};
5543d808a52Ssubhan 	static char devctl_str[] = {":reg"};
5553d808a52Ssubhan 	int fd;
5563d808a52Ssubhan 
5573d808a52Ssubhan 	path = malloc(
5583d808a52Ssubhan 	    strlen(root_complex) + sizeof (device_str) + sizeof (devctl_str));
5593d808a52Ssubhan 	if (path == NULL)
5603d808a52Ssubhan 		return (PICL_FAILURE);
5613d808a52Ssubhan 	(void) strcpy(path, device_str);
5623d808a52Ssubhan 	(void) strcat(path, root_complex);
5633d808a52Ssubhan 	(void) strcat(path, devctl_str);
5643d808a52Ssubhan 
5653d808a52Ssubhan 	if ((fd = open(path, O_RDWR)) == -1) {
5663d808a52Ssubhan 		return (-1);
5673d808a52Ssubhan 	}
5683d808a52Ssubhan 	return (fd);
5693d808a52Ssubhan }
5703d808a52Ssubhan 
5713d808a52Ssubhan static uint32_t
read_long(int fd,int bus,int dev,int func,int offset,int * ret)5723d808a52Ssubhan read_long(int fd, int bus, int dev, int func, int offset, int *ret)
5733d808a52Ssubhan {
5743d808a52Ssubhan 	int rval;
5753d808a52Ssubhan 	pcitool_reg_t prg;
5763d808a52Ssubhan 
5772917a9c9Sschwartz 	prg.user_version = PCITOOL_VERSION;
5783d808a52Ssubhan 	prg.barnum = 0;
5793d808a52Ssubhan 	prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 +
5803d808a52Ssubhan 	    PCITOOL_ACC_ATTR_ENDN_LTL;
5813d808a52Ssubhan 	prg.bus_no = bus;
5823d808a52Ssubhan 	prg.dev_no = dev;
5833d808a52Ssubhan 	prg.func_no = func;
5843d808a52Ssubhan 	prg.offset = offset;
5853d808a52Ssubhan 	rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg);
5863d808a52Ssubhan 	if (rval != 0) {
5872917a9c9Sschwartz 		log_printf("DEV_GET failed %d %s\n", rval, strerror(errno));
5882917a9c9Sschwartz 		log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
5893d808a52Ssubhan 	}
5903d808a52Ssubhan 	*ret = rval;
5913d808a52Ssubhan 	return ((uint32_t)prg.data);
5923d808a52Ssubhan }
5933d808a52Ssubhan 
5943d808a52Ssubhan static uint16_t
read_word(int fd,int bus,int dev,int func,int offset,int * ret)5953d808a52Ssubhan read_word(int fd, int bus, int dev, int func, int offset, int *ret)
5963d808a52Ssubhan {
5973d808a52Ssubhan 	int rval;
5983d808a52Ssubhan 	pcitool_reg_t prg;
5993d808a52Ssubhan 
6002917a9c9Sschwartz 	prg.user_version = PCITOOL_VERSION;
6013d808a52Ssubhan 	prg.barnum = 0;
6023d808a52Ssubhan 	prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_2 +
6033d808a52Ssubhan 	    PCITOOL_ACC_ATTR_ENDN_LTL;
6043d808a52Ssubhan 	prg.bus_no = bus;
6053d808a52Ssubhan 	prg.dev_no = dev;
6063d808a52Ssubhan 	prg.func_no = func;
6073d808a52Ssubhan 	prg.offset = offset;
6083d808a52Ssubhan 	rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg);
6093d808a52Ssubhan 	if (rval != 0) {
6102917a9c9Sschwartz 		log_printf("DEV_GET failed %d %s\n", rval, strerror(errno));
6112917a9c9Sschwartz 		log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
6123d808a52Ssubhan 	}
6133d808a52Ssubhan 	*ret = rval;
6143d808a52Ssubhan 	return ((uint16_t)prg.data);
6153d808a52Ssubhan }
6163d808a52Ssubhan 
6173d808a52Ssubhan static uint8_t
read_byte(int fd,int bus,int dev,int func,int offset,int * ret)6183d808a52Ssubhan read_byte(int fd, int bus, int dev, int func, int offset, int *ret)
6193d808a52Ssubhan {
6203d808a52Ssubhan 	int rval;
6213d808a52Ssubhan 	pcitool_reg_t prg;
6223d808a52Ssubhan 
6232917a9c9Sschwartz 	prg.user_version = PCITOOL_VERSION;
6243d808a52Ssubhan 	prg.barnum = 0;
6253d808a52Ssubhan 	prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_1 +
6263d808a52Ssubhan 	    PCITOOL_ACC_ATTR_ENDN_LTL;
6273d808a52Ssubhan 	prg.bus_no = bus;
6283d808a52Ssubhan 	prg.dev_no = dev;
6293d808a52Ssubhan 	prg.func_no = func;
6303d808a52Ssubhan 	prg.offset = offset;
6313d808a52Ssubhan 	rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg);
6323d808a52Ssubhan 	if (rval != 0) {
6332917a9c9Sschwartz 		log_printf("DEV_GET failed %d %s\n", rval, strerror(errno));
6342917a9c9Sschwartz 		log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
6353d808a52Ssubhan 	}
6363d808a52Ssubhan 	*ret = rval;
6373d808a52Ssubhan 	return ((uint8_t)prg.data);
6383d808a52Ssubhan }
6393d808a52Ssubhan 
6403d808a52Ssubhan 
6413d808a52Ssubhan static picl_errno_t
get_lane_width(char * device_path,int bus,int dev,int func,int * actual,int * maximum,uint32_t * speed_max,uint32_t * speed_at,int * type)6423d808a52Ssubhan get_lane_width
6433d808a52Ssubhan 	(char *device_path, int bus, int dev, int func, int *actual,
6443d808a52Ssubhan 	int *maximum, uint32_t *speed_max, uint32_t *speed_at, int *type)
6453d808a52Ssubhan {
6463d808a52Ssubhan 	uint_t cap_ptr, cap_reg, link_status, link_cap, capid;
6473d808a52Ssubhan 	int fd, ret;
6483d808a52Ssubhan 
6493d808a52Ssubhan 	if (device_path == NULL)
6503d808a52Ssubhan 		return (PICL_FAILURE);
6513d808a52Ssubhan 
6523d808a52Ssubhan 	fd = open_root_complex(device_path);
6533d808a52Ssubhan 	if (fd == -1)
6543d808a52Ssubhan 		return (PICL_FAILURE);
6553d808a52Ssubhan 
6563d808a52Ssubhan 	/*
6573d808a52Ssubhan 	 * Link Capabilities and Link Status registers are in the
6583d808a52Ssubhan 	 * PCI-E capabilities register.  They are at offset
6593d808a52Ssubhan 	 * 0xc and 0x12 respectively. They are documented in section
6603d808a52Ssubhan 	 * 7.8 of the PCI Express Base Specification. The address of
6613d808a52Ssubhan 	 * that structure is not fixed, it's kind of a linked list.
6623d808a52Ssubhan 	 * The Capabilities Pointer reg (8 bits) is always at 0x34.
6633d808a52Ssubhan 	 * It contains a pointer to the first capabilities structure.
6643d808a52Ssubhan 	 * For each capability structure, the first 8 bits is the capability
6653d808a52Ssubhan 	 * ID. The next 8 bits is the pointer to the next structure.
6663d808a52Ssubhan 	 * If the Next Cap register is zero, it's the end of the list.
6673d808a52Ssubhan 	 * The capability ID for the PCI-E strucutre is 0x10.  The idea
6683d808a52Ssubhan 	 * is to follow the links until you find a Cap ID of 0x10, then
6693d808a52Ssubhan 	 * read the registers at 0xc and 0x12 from there.
6703d808a52Ssubhan 	 * If there's no Cap ID 0x10, then it's not a PCI-E device.
6713d808a52Ssubhan 	 */
6723d808a52Ssubhan 
6733d808a52Ssubhan 	cap_ptr = read_byte(fd, bus, dev, func, PCI_CONF_CAP_PTR, &ret);
6743d808a52Ssubhan 	if (ret != 0) {
6753d808a52Ssubhan 		/* ioctl failure */
6767561ff47Sanbui 		close(fd);
6773d808a52Ssubhan 		return (PICL_FAILURE);
6783d808a52Ssubhan 	}
6793d808a52Ssubhan 	cap_reg = read_word(fd, bus, dev, func, cap_ptr, &ret);
6803d808a52Ssubhan 	if (ret != 0) {
6813d808a52Ssubhan 		/* ioctl failure */
6827561ff47Sanbui 		close(fd);
6833d808a52Ssubhan 		return (PICL_FAILURE);
6843d808a52Ssubhan 	}
6854c963d50Smb 	*type = PCI;
6863d808a52Ssubhan 	capid = cap_reg & PCI_CAP_MASK;
6873d808a52Ssubhan 	while (cap_ptr != 0) {
6883d808a52Ssubhan 
6893d808a52Ssubhan 		if (capid == PCI_CAP_ID_PCI_E) {
6903d808a52Ssubhan 			link_cap = read_long(fd, bus, dev, func, cap_ptr +
6913d808a52Ssubhan 			    PCIE_LINKCAP, &ret);
6923d808a52Ssubhan 			if (ret != 0) {
6937561ff47Sanbui 				close(fd);
6943d808a52Ssubhan 				return (PICL_FAILURE);
6953d808a52Ssubhan 			}
6962917a9c9Sschwartz 			link_status = read_word(fd, bus, dev, func,
6972917a9c9Sschwartz 			    cap_ptr + PCIE_LINKSTS, &ret);
6983d808a52Ssubhan 			if (ret != 0) {
6997561ff47Sanbui 				close(fd);
7003d808a52Ssubhan 				return (PICL_FAILURE);
7013d808a52Ssubhan 			}
7023d808a52Ssubhan 			*actual = ((link_status >> PCI_LINK_SHIFT) &
7032917a9c9Sschwartz 			    PCI_LINK_MASK);
7043d808a52Ssubhan 			*maximum = ((link_cap >> PCI_LINK_SHIFT) &
7052917a9c9Sschwartz 			    PCI_LINK_MASK);
7063d808a52Ssubhan 			*type = PCIE;
7074c963d50Smb 		} else if (capid == PCI_CAP_ID_PCIX) {
7083d808a52Ssubhan 			uint32_t pcix_status;
7093d808a52Ssubhan 			uint8_t hdr_type;
7103d808a52Ssubhan 			int max_speed = PCI_FREQ_66;
7113d808a52Ssubhan 
7123d808a52Ssubhan 			hdr_type = read_byte
7132917a9c9Sschwartz 			    (fd, bus, dev, func, PCI_CONF_HEADER, &ret);
7143d808a52Ssubhan 			if (ret != 0) {
7153d808a52Ssubhan 				/* ioctl failure */
7167561ff47Sanbui 				close(fd);
7173d808a52Ssubhan 				return (PICL_FAILURE);
7183d808a52Ssubhan 			}
7194c963d50Smb 			*type = PCIX;
7203d808a52Ssubhan 			if ((hdr_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
7213d808a52Ssubhan 				/* This is a PCI-X bridge */
7223d808a52Ssubhan 				uint16_t sec_status, mode;
7233d808a52Ssubhan 				sec_status = read_word(fd, bus, dev, func,
7242917a9c9Sschwartz 				    cap_ptr + PCI_PCIX_SEC_STATUS, &ret);
7253d808a52Ssubhan 				if (ret != 0) {
7263d808a52Ssubhan 					/* ioctl failure */
7277561ff47Sanbui 					close(fd);
7283d808a52Ssubhan 					return (PICL_FAILURE);
7293d808a52Ssubhan 				}
7303d808a52Ssubhan 				if (sec_status & PCI_SEC_133)
7313d808a52Ssubhan 					max_speed = PCI_FREQ_133;
7323d808a52Ssubhan 				if (sec_status & PCI_SEC_266)
7333d808a52Ssubhan 					max_speed = PCI_FREQ_266;
7343d808a52Ssubhan 				if (sec_status & PCI_SEC_533)
7353d808a52Ssubhan 					max_speed = PCI_FREQ_533;
7363d808a52Ssubhan 				*speed_max = max_speed;
7372917a9c9Sschwartz 				mode = (sec_status >> PCI_CLASS_BRIDGE) &
7382917a9c9Sschwartz 				    PCI_BRIDGE_MC;
7393d808a52Ssubhan 				if (mode) {
7403d808a52Ssubhan 					int speed;
7413d808a52Ssubhan 					if (mode == PCI_MODE_66)
7423d808a52Ssubhan 						speed = PCI_FREQ_66;
7433d808a52Ssubhan 					else if (mode == PCI_MODE_100)
7443d808a52Ssubhan 						speed = PCI_FREQ_100;
7453d808a52Ssubhan 					else if (mode == PCI_MODE_133)
7463d808a52Ssubhan 						speed = PCI_FREQ_133;
7473d808a52Ssubhan 					*speed_at = speed;
7483d808a52Ssubhan 				}
7493d808a52Ssubhan 
7503d808a52Ssubhan 			} else {  /* Leaf device */
7513d808a52Ssubhan 				pcix_status = read_long(fd, bus, dev, func,
7523d808a52Ssubhan 				    cap_ptr + PCI_PCIX_STATUS, &ret);
7533d808a52Ssubhan 				if (ret != 0) {
7543d808a52Ssubhan 					/* ioctl failure */
7557561ff47Sanbui 					close(fd);
7563d808a52Ssubhan 					return (PICL_FAILURE);
7573d808a52Ssubhan 				}
7583d808a52Ssubhan 				if (pcix_status &
7592917a9c9Sschwartz 				    (PCI_LEAF_ULONG << PCI_SHIFT_133))
7603d808a52Ssubhan 					max_speed = PCI_FREQ_133;
7613d808a52Ssubhan 				if (pcix_status &
7622917a9c9Sschwartz 				    (PCI_LEAF_ULONG << PCI_SHIFT_266))
7633d808a52Ssubhan 					max_speed = PCI_FREQ_266;
7643d808a52Ssubhan 				if (pcix_status &
7652917a9c9Sschwartz 				    (PCI_LEAF_ULONG << PCI_SHIFT_533))
7663d808a52Ssubhan 					max_speed = PCI_FREQ_533;
7673d808a52Ssubhan 				*speed_max = max_speed;
7683d808a52Ssubhan 			}
7693d808a52Ssubhan 		}
7703d808a52Ssubhan 		cap_ptr = (cap_reg >> PCI_REG_FUNC_SHIFT);
7713d808a52Ssubhan 		cap_reg = read_word(fd, bus, dev, func, cap_ptr, &ret);
7723d808a52Ssubhan 		if (ret != 0) {
7733d808a52Ssubhan 			/* ioctl failure */
7747561ff47Sanbui 			close(fd);
7753d808a52Ssubhan 			return (PICL_FAILURE);
7763d808a52Ssubhan 		}
7773d808a52Ssubhan 		capid = cap_reg & PCI_CAP_MASK;
7783d808a52Ssubhan 	}
7793d808a52Ssubhan 
7807561ff47Sanbui 	if (close(fd) == -1) {
7817561ff47Sanbui 		return (PICL_FAILURE);
7827561ff47Sanbui 	}
7837561ff47Sanbui 
7843d808a52Ssubhan 	return (PICL_SUCCESS);
7853d808a52Ssubhan }
7863d808a52Ssubhan 
787*abe610a3SMichael Bergknoff static int
is_66mhz_capable(picl_nodehdl_t nodeh)788*abe610a3SMichael Bergknoff is_66mhz_capable(picl_nodehdl_t nodeh)
789*abe610a3SMichael Bergknoff {
790*abe610a3SMichael Bergknoff 	picl_errno_t	err;
791*abe610a3SMichael Bergknoff 	picl_prophdl_t	proph;
792*abe610a3SMichael Bergknoff 	picl_propinfo_t	pinfo;
793*abe610a3SMichael Bergknoff 
794*abe610a3SMichael Bergknoff 	err = picl_get_propinfo_by_name(nodeh, OBP_PROP_66MHZ_CAPABLE,
795*abe610a3SMichael Bergknoff 	    &pinfo, &proph);
796*abe610a3SMichael Bergknoff 	if (err == PICL_SUCCESS)
797*abe610a3SMichael Bergknoff 		return (1);
798*abe610a3SMichael Bergknoff 	return (0);
799*abe610a3SMichael Bergknoff }
800*abe610a3SMichael Bergknoff 
8013d808a52Ssubhan /*
8023d808a52Ssubhan  * get the clock frequency
8033d808a52Ssubhan  */
8043d808a52Ssubhan static int
picldiag_get_clock_freq(picl_nodehdl_t modh,uint32_t * freq,uint32_t * freq_max)805*abe610a3SMichael Bergknoff picldiag_get_clock_freq(picl_nodehdl_t modh, uint32_t *freq, uint32_t *freq_max)
8063d808a52Ssubhan {
8073d808a52Ssubhan 	int		err;
8083d808a52Ssubhan 	uint64_t	clk_freq;
8093d808a52Ssubhan 
810*abe610a3SMichael Bergknoff 	*freq_max = PCI_FREQ_33;
811*abe610a3SMichael Bergknoff 	if (is_66mhz_capable(modh))
812*abe610a3SMichael Bergknoff 		*freq_max = PCI_FREQ_66;
8133d808a52Ssubhan 	clk_freq = picldiag_get_uint_propval(modh, OBP_PROP_CLOCK_FREQ, &err);
8143d808a52Ssubhan 	if (err != PICL_SUCCESS)
8153d808a52Ssubhan 		return (err);
8163d808a52Ssubhan 
8173d808a52Ssubhan 	*freq = ROUND_TO_MHZ(clk_freq);
8183d808a52Ssubhan 
8193d808a52Ssubhan 	return (PICL_SUCCESS);
8203d808a52Ssubhan }
8213d808a52Ssubhan 
8223d808a52Ssubhan static uint64_t
picldiag_get_uint_propval(picl_nodehdl_t modh,char * prop_name,int * ret)8233d808a52Ssubhan picldiag_get_uint_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
8243d808a52Ssubhan {
8253d808a52Ssubhan 	int		err;
8263d808a52Ssubhan 	picl_prophdl_t	proph;
8273d808a52Ssubhan 	picl_propinfo_t pinfo;
8283d808a52Ssubhan 	uint8_t		uint8v;
8293d808a52Ssubhan 	uint16_t	uint16v;
8303d808a52Ssubhan 	uint32_t	uint32v;
8313d808a52Ssubhan 	uint64_t	uint64v;
8323d808a52Ssubhan 
8333d808a52Ssubhan 	err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
8343d808a52Ssubhan 	if (err != PICL_SUCCESS) {
8353d808a52Ssubhan 		*ret = err;
8363d808a52Ssubhan 		return (0);
8373d808a52Ssubhan 	}
8383d808a52Ssubhan 
8393d808a52Ssubhan 	/*
8403d808a52Ssubhan 	 * If it is not an int or uint prop, return failure
8413d808a52Ssubhan 	 */
8423d808a52Ssubhan 	if ((pinfo.type != PICL_PTYPE_INT) &&
8432917a9c9Sschwartz 	    (pinfo.type != PICL_PTYPE_UNSIGNED_INT)) {
8443d808a52Ssubhan 		*ret = PICL_FAILURE;
8453d808a52Ssubhan 		return (0);
8463d808a52Ssubhan 	}
8473d808a52Ssubhan 
8483d808a52Ssubhan 
8493d808a52Ssubhan 	/* uint prop */
8503d808a52Ssubhan 
8513d808a52Ssubhan 	switch (pinfo.size) {
8523d808a52Ssubhan 	case sizeof (uint8_t):
8533d808a52Ssubhan 		err = picl_get_propval(proph, &uint8v, sizeof (uint8v));
8543d808a52Ssubhan 		*ret = err;
8553d808a52Ssubhan 		return (uint8v);
8563d808a52Ssubhan 	case sizeof (uint16_t):
8573d808a52Ssubhan 		err = picl_get_propval(proph, &uint16v, sizeof (uint16v));
8583d808a52Ssubhan 		*ret = err;
8593d808a52Ssubhan 		return (uint16v);
8603d808a52Ssubhan 	case sizeof (uint32_t):
8613d808a52Ssubhan 		err = picl_get_propval(proph, &uint32v, sizeof (uint32v));
8623d808a52Ssubhan 		*ret = err;
8633d808a52Ssubhan 		return (uint32v);
8643d808a52Ssubhan 	case sizeof (uint64_t):
8653d808a52Ssubhan 		err = picl_get_propval(proph, &uint64v, sizeof (uint64v));
8663d808a52Ssubhan 		*ret = err;
8673d808a52Ssubhan 		return (uint64v);
8683d808a52Ssubhan 	default:	/* not supported size */
8693d808a52Ssubhan 		*ret = PICL_FAILURE;
8703d808a52Ssubhan 		return (0);
8713d808a52Ssubhan 	}
8723d808a52Ssubhan }
8733d808a52Ssubhan 
8743d808a52Ssubhan /*
8753d808a52Ssubhan  * recursively visit all nodes
8763d808a52Ssubhan  */
8773d808a52Ssubhan static picl_errno_t
do_walk(picl_nodehdl_t rooth,const char * classname,void * c_args,picl_errno_t (* callback_fn)(picl_nodehdl_t hdl,void * args))8783d808a52Ssubhan do_walk(picl_nodehdl_t rooth, const char *classname,
8793d808a52Ssubhan     void *c_args, picl_errno_t (*callback_fn)(picl_nodehdl_t hdl, void *args))
8803d808a52Ssubhan {
8813d808a52Ssubhan 	picl_errno_t	err;
8823d808a52Ssubhan 	picl_nodehdl_t  chdh;
8833d808a52Ssubhan 	char		classval[PICL_CLASSNAMELEN_MAX];
8843d808a52Ssubhan 
8853d808a52Ssubhan 	err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh,
8862917a9c9Sschwartz 	    sizeof (chdh));
8873d808a52Ssubhan 	while (err == PICL_SUCCESS) {
8883d808a52Ssubhan 		err = picl_get_propval_by_name(chdh, PICL_PROP_NAME,
8892917a9c9Sschwartz 		    classval, sizeof (classval));
8903d808a52Ssubhan 		if (err != PICL_SUCCESS)
8913d808a52Ssubhan 			return (err);
8923d808a52Ssubhan 
8933d808a52Ssubhan 		err = callback_fn(chdh, c_args);
8943d808a52Ssubhan 
8953d808a52Ssubhan 		if ((err = do_walk(chdh, classname, c_args, callback_fn)) !=
8962917a9c9Sschwartz 		    PICL_WALK_CONTINUE)
8973d808a52Ssubhan 			return (err);
8983d808a52Ssubhan 
8993d808a52Ssubhan 		err = picl_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
9002917a9c9Sschwartz 		    sizeof (chdh));
9013d808a52Ssubhan 	}
9023d808a52Ssubhan 	if (err == PICL_PROPNOTFOUND)   /* end of a branch */
9033d808a52Ssubhan 		return (PICL_WALK_CONTINUE);
9043d808a52Ssubhan 	return (err);
9053d808a52Ssubhan }
9061ba18ff1Sjimand 
9071ba18ff1Sjimand int
get_proc_mode(void)9081ba18ff1Sjimand get_proc_mode(void)
9091ba18ff1Sjimand {
9101ba18ff1Sjimand 	picl_nodehdl_t nodeh;
9111ba18ff1Sjimand 	picl_prophdl_t  proph;
9121ba18ff1Sjimand 	picl_errno_t err;
9131ba18ff1Sjimand 
9141ba18ff1Sjimand 	err = picl_initialize();
9151ba18ff1Sjimand 	if (err != PICL_SUCCESS) {
9161ba18ff1Sjimand 		(void) log_printf("picl_initialize failed: %s\n",
9171ba18ff1Sjimand 		    picl_strerror(err));
9181ba18ff1Sjimand 		return (err);
9191ba18ff1Sjimand 	}
9201ba18ff1Sjimand 
9211ba18ff1Sjimand 	err = picl_get_node_by_path("/platform",  &nodeh);
9221ba18ff1Sjimand 	if (err != PICL_SUCCESS) {
9231ba18ff1Sjimand 		(void) log_printf("Getting plat node failed: %s\n",
9241ba18ff1Sjimand 		    picl_strerror(err));
9251ba18ff1Sjimand 		return (err);
9261ba18ff1Sjimand 	}
9271ba18ff1Sjimand 
9281ba18ff1Sjimand 	err = picl_get_prop_by_name(nodeh, "SPARC64-VII-mode",  &proph);
9291ba18ff1Sjimand 	if (err != PICL_SUCCESS) {
9301ba18ff1Sjimand 		/* Do not display error message */
9311ba18ff1Sjimand 		return (err);
9321ba18ff1Sjimand 	}
9331ba18ff1Sjimand 
9341ba18ff1Sjimand 	(void) picl_shutdown();
9351ba18ff1Sjimand 
9361ba18ff1Sjimand 	return (err);
9371ba18ff1Sjimand }
938