changeset 3418:b24fafdbfbc2

6459500 prtdiag should show more information with regards to physical slot locations of I/O components
author subhan
date Fri, 12 Jan 2007 11:56:47 -0800
parents 0630f537a7e5
children 83f3eb80c815
files usr/src/lib/libprtdiag_psr/sparc/opl/Makefile usr/src/lib/libprtdiag_psr/sparc/opl/common/opl.c usr/src/lib/libprtdiag_psr/sparc/opl/common/opl_picl.c usr/src/lib/libprtdiag_psr/sparc/opl/common/opl_picl.h
diffstat 4 files changed, 1082 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/lib/libprtdiag_psr/sparc/opl/Makefile	Fri Jan 12 11:35:52 2007 -0800
+++ b/usr/src/lib/libprtdiag_psr/sparc/opl/Makefile	Fri Jan 12 11:56:47 2007 -0800
@@ -19,23 +19,24 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-#ident	"%Z%%M%	%I%	%E% SMI"
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
 #
 # lib/libprtdiag_psr/sparc/opl/Makefile
 
 UTSBASE = ../../../../../src/uts
 
-PLATFORM_OBJECTS= opl.o
+PLATFORM_OBJECTS= opl.o opl_picl.o
 
 include ../Makefile.com
 
 IFLAGS += -I$(USR_PLAT_DIR)/sun4u/include -I ../../../libprtdiag/inc
-LINTFLAGS += $(IFLAGS)
+IFLAGS += -I$(SRC)/uts/common/ -I$(SRC)/cmd/picl/plugins/inc
+LDLIBS += -lpicl -ldevinfo -lkstat
 
-LDLIBS +=	-ldevinfo -lkstat
+LINTFLAGS += $(IFLAGS)
 
 #IMPLEMENTED_PLATFORM	= SUNW,OPL-Enterprise
 #PLATFORM=$(IMPLEMENTED_PLATFORM)
--- a/usr/src/lib/libprtdiag_psr/sparc/opl/common/opl.c	Fri Jan 12 11:35:52 2007 -0800
+++ b/usr/src/lib/libprtdiag_psr/sparc/opl/common/opl.c	Fri Jan 12 11:56:47 2007 -0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
  * Opl Platform specific functions.
@@ -94,9 +94,11 @@
 void	display_cpus(Board_node *board);
 void	display_memoryconf(Sys_tree *tree, struct grp_info *grps);
 void	display_io_cards(struct io_card *list);
+void	display_io_devices(Sys_tree *tree);
 void	display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
     struct system_kstat_data *kstats);
 Prop 	*find_prop(Prom_node *pnode, char *name);
+int	do_piclinfo(int);
 
 /* Local functions */
 static	void opl_disp_environ(void);
@@ -107,6 +109,37 @@
 void 	add_node(Sys_tree *root, Prom_node *pnode);
 static	int get_prop_size(Prop *prop);
 
+static int v_flag = 0;
+
+/*
+ * For display of I/O devices for "prtdiag"
+ */
+void
+display_io_devices(Sys_tree *tree)
+{
+	Board_node *bnode;
+
+	if (v_flag) {
+		/*
+		 * OPL's PICL interface for display of PCI I/O devices
+		 * for "prtdiag -v"
+		 */
+		(void) do_piclinfo(v_flag);
+	} else {
+		log_printf("\n", 0);
+		log_printf("=========================", 0);
+		log_printf(dgettext(TEXT_DOMAIN, " IO Cards "), 0);
+		log_printf("=========================", 0);
+		log_printf("\n", 0);
+		log_printf("\n", 0);
+		bnode = tree->bd_list;
+		while (bnode != NULL) {
+			display_pci(bnode);
+			bnode = bnode->next;
+		}
+	}
+}
+
 /*
  * Display all the leaf PCI nodes on this board that have "reg" property.
  * If the "reg" property is NULL for a leaf node, skip parsing its sibling
@@ -682,8 +715,7 @@
 	struct system_kstat_data *kstats)
 {
 	/* Print the PROM revisions */
-	if (flag)
-		opl_disp_hw_revisions(tree, root);
+	opl_disp_hw_revisions(tree, root);
 }
 
 /*
@@ -780,6 +812,7 @@
 int
 do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag)
 {
+	v_flag = syserrlog;
 	return (do_devinfo(syserrlog, pgname, log_flag, prt_flag));
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libprtdiag_psr/sparc/opl/common/opl_picl.c	Fri Jan 12 11:56:47 2007 -0800
@@ -0,0 +1,888 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Opl platform specific PICL functions.
+ *
+ * 	called when :
+ *	machine_type == MTYPE_OPL
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <kstat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <assert.h>
+#include <libintl.h>
+#include <note.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <sys/systeminfo.h>
+#include <sys/openpromio.h>
+#include <sys/sysmacros.h>
+#include <picl.h>
+#include "picldefs.h"
+#include <pdevinfo.h>
+#include <display.h>
+#include <libprtdiag.h>
+#include <alloca.h>
+#include "opl_picl.h"
+#include <sys/pci.h>
+#include <sys/pci_tools.h>
+#include <sys/types.h>
+
+#if !defined(TEXT_DOMAIN)
+#define	TEXT_DOMAIN	"SYS_TEST"
+#endif
+
+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));
+static int opl_get_node_by_name(picl_nodehdl_t rooth, char *name,
+    picl_nodehdl_t *nodeh);
+static picl_errno_t get_lane_width(char *device_path, int bus_no, int func_no,
+    int dev_no, int *actual, int *maximum, uint32_t *speed_max,
+    uint32_t *speed_at, int *type);
+static int	opl_display_pci(int syserrlog, picl_nodehdl_t plafh);
+static picl_errno_t opl_pci_callback(picl_nodehdl_t pcih, void *args);
+static int opl_get_first_compatible_value(picl_nodehdl_t nodeh,
+    char **outbuf);
+static int picldiag_get_clock_freq(picl_nodehdl_t modh,
+    uint32_t *freq);
+static uint64_t picldiag_get_uint_propval(picl_nodehdl_t modh,
+    char *prop_name, int *ret);
+static uint32_t	read_long(int fd, int bus, int dev, int func,
+    int offset, int *ret);
+static uint8_t read_byte(int fd, int bus, int dev, int func, int offset,
+    int *ret);
+static uint16_t read_word(int fd, int bus, int dev, int func, int offset,
+    int *ret);
+
+
+/*
+ * Collect I/O nodes information.
+ */
+/* ARGSUSED */
+static picl_errno_t
+opl_pci_callback(picl_nodehdl_t pcih, void *args)
+{
+	picl_errno_t	err = PICL_SUCCESS;
+	picl_nodehdl_t	nodeh;
+	picl_prophdl_t  proph;
+	picl_propinfo_t pinfo;
+	char		path[MAXSTRLEN];
+	char		parent_path[MAXSTRLEN];
+	static char	root_path[MAXSTRLEN];
+	char		piclclass[PICL_CLASSNAMELEN_MAX];
+	char		name[MAXSTRLEN];
+	char		model[MAXSTRLEN];
+	char		*compatible;
+	char		binding_name[MAXSTRLEN];
+	struct io_card	pci_card;
+	char		status[6] = "N/A";
+	int		portid = PROP_INVALID;
+	int		*reg_val;
+	int		board = PROP_INVALID;
+	static int	saved_board = PROP_INVALID;
+	static int	saved_portid = PROP_INVALID;
+	int 		actual = PROP_INVALID, maximum = PROP_INVALID;
+	int 		bus_type;
+	int 		rev_id = PROP_INVALID, dev_id = PROP_INVALID;
+	int		ven_id = PROP_INVALID;
+	size_t		prop_size;
+
+	(void) memset(&pci_card, 0, sizeof (pci_card));
+
+	err = picl_get_propval_by_name(pcih, PICL_PROP_CLASSNAME,
+		piclclass, sizeof (piclclass));
+
+	if (err !=  PICL_SUCCESS)
+		/* Do not proceed to parse this branch */
+		return (err);
+
+	if (!IS_PCI(piclclass))
+		/* Do not parse non-pci nodes */
+		return (PICL_INVALIDARG);
+
+	err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, parent_path,
+	    sizeof (parent_path));
+	if (err != PICL_SUCCESS)
+		/* Do not proceed to parse this branch */
+		return (err);
+	err = picl_get_propval_by_name(pcih, OBP_PROP_BOARD_NUM, &board,
+		sizeof (board));
+
+	if (err == PICL_NORESPONSE)
+		/* Do not proceed to parse this branch */
+		return (err);
+	else if (err != PICL_PROPNOTFOUND) {
+		saved_board = board;
+		/* Save board node's pathname */
+		prop_size = sizeof (parent_path) + 1;
+		if (prop_size > MAXSTRLEN)
+			prop_size = MAXSTRLEN;
+		(void) strlcpy(root_path, parent_path, prop_size);
+	}
+
+	err = picl_get_propval_by_name
+		(pcih, OBP_PROP_PORTID, &portid, sizeof (portid));
+
+	if (err != PICL_PROPNOTFOUND)
+		saved_portid = portid;
+
+	/* Walk through the children */
+
+	err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
+	    sizeof (picl_nodehdl_t));
+
+	while (err == PICL_SUCCESS) {
+		uint32_t	freq_max = 0, freq_at = 0;
+
+		err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
+		    piclclass, sizeof (piclclass));
+		if (err !=  PICL_SUCCESS)
+			/* Do not proceed to parse this node */
+			return (err);
+
+		if (IS_EBUS(piclclass)) {
+			err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
+				&nodeh, sizeof (picl_nodehdl_t));
+			continue;
+		}
+
+		err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH,
+		    path, sizeof (path));
+		if (err != PICL_SUCCESS) {
+			/* Do not proceed to parse this node */
+			return (err);
+		}
+
+		prop_size = sizeof (path) + 1;
+		if (prop_size > MAXSTRLEN)
+			prop_size = MAXSTRLEN;
+		(void) strlcpy(pci_card.notes, path, prop_size);
+
+		pci_card.board = saved_board;
+		pci_card.schizo_portid = saved_portid;
+
+		/*
+		 * Get bus#, dev# and func# for this card from 'reg' property.
+		 */
+
+		err = picl_get_propinfo_by_name
+			(nodeh, OBP_PROP_REG, &pinfo, &proph);
+		if (err == PICL_SUCCESS) {
+			/* All of the array of bytes of "reg" have to be read */
+			reg_val = malloc(pinfo.size);
+			if (reg_val == NULL)
+				return (PICL_FAILURE);
+
+
+			err = picl_get_propval_by_name
+			    (nodeh, OBP_PROP_REG, reg_val, pinfo.size);
+
+			if (err != PICL_SUCCESS) {
+				free(reg_val);
+				/* Do not proceed to parse this node */
+				return (err);
+			}
+
+			if (reg_val[0] != 0) {
+				pci_card.dev_no =
+					(((reg_val[0]) & PCI_DEV_MASK) >> 11);
+				pci_card.func_no =
+					(((reg_val[0]) & PCI_FUNC_MASK) >> 8);
+				pci_card.slot =
+					(((reg_val[0]) & PCI_BUS_MASK) >> 16);
+			} else
+				free(reg_val);
+		}
+
+		err = get_lane_width
+			(root_path, pci_card.slot, pci_card.dev_no,
+				pci_card.func_no, &actual, &maximum, &freq_max,
+				&freq_at, &bus_type);
+
+		if (err != PICL_SUCCESS) {
+			/* Move on to next node */
+			log_printf("Getting lane width failed for path %s\n",
+				pci_card.notes);
+			err = picl_get_propval_by_name
+				(nodeh, PICL_PROP_PEER, &nodeh,
+					sizeof (picl_nodehdl_t));
+			continue;
+		}
+
+
+		err = picl_get_propval_by_name
+		    (nodeh, PICL_PROP_NAME, name, sizeof (name));
+		if (err != PICL_SUCCESS)
+			(void) strcpy(name, "");
+
+		/*
+		 * Get the name of this card. If binding_name is found,
+		 * name will be <nodename>-<binding_name>
+		 */
+
+		err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
+		    binding_name, sizeof (binding_name));
+		if (err == PICL_PROPNOTFOUND) {
+			/*
+			 * if compatible prop is found, name will be
+			 * <nodename>-<compatible>
+			 */
+			err = opl_get_first_compatible_value(nodeh,
+			    &compatible);
+			if (err == PICL_SUCCESS) {
+				(void) strlcat(name, "-", MAXSTRLEN);
+				(void) strlcat(name, compatible, MAXSTRLEN);
+				free(compatible);
+			}
+		} else if (err != PICL_SUCCESS) {
+			/* No binding-name or compatible */
+			(void) strcpy(binding_name, "N/A");
+		} else if (strcmp(name, binding_name) != 0) {
+			(void) strlcat(name, "-", MAXSTRLEN);
+			(void) strlcat(name, binding_name, MAXSTRLEN);
+		}
+
+
+		prop_size = sizeof (name) + 1;
+		if (prop_size > MAXSTRLEN)
+			prop_size =  MAXSTRLEN;
+		(void) strlcpy(pci_card.name, name, prop_size);
+
+		/* Get the status of the card */
+		err = picl_get_propval_by_name
+		    (nodeh, PICL_PROP_STATUS, status, sizeof (status));
+
+
+		/* Get the model of this card */
+
+		err = picl_get_propval_by_name
+		    (nodeh, OBP_PROP_MODEL, model, sizeof (model));
+		prop_size = sizeof (model) + 1;
+		if (prop_size > MAXSTRLEN)
+			prop_size =  MAXSTRLEN;
+		if (err != PICL_SUCCESS)
+			(void) strcpy(model, "N/A");
+		(void) strlcpy(pci_card.model, model, prop_size);
+
+		if (bus_type == PCI)
+			(void) strlcpy
+			(pci_card.bus_type, "PCI", sizeof (pci_card.bus_type));
+		else if (bus_type == PCIX)
+			(void) strlcpy
+			(pci_card.bus_type, "PCIx", sizeof (pci_card.bus_type));
+		else if (bus_type == PCIE)
+			(void) strlcpy
+			(pci_card.bus_type, "PCIe", sizeof (pci_card.bus_type));
+		else
+			(void) strlcpy
+			(pci_card.bus_type, "UNKN", sizeof (pci_card.bus_type));
+
+		/* Get revision id */
+		err = picl_get_propval_by_name
+			(nodeh, OBP_PROP_REVISION_ID, &rev_id, sizeof (rev_id));
+
+		/* Get device id */
+		err = picl_get_propval_by_name
+			(nodeh, OBP_PROP_DEVICE_ID, &dev_id, sizeof (dev_id));
+
+		/* Get vendor id */
+		err = picl_get_propval_by_name
+			(nodeh, OBP_PROP_VENDOR_ID, &ven_id, sizeof (ven_id));
+
+		/*
+		 * prtdiag -v prints all devices
+		 */
+
+		/* Print board number */
+		log_printf("%02d  ", pci_card.board);
+		/* Print IO Type */
+		log_printf("%-5.5s ", pci_card.bus_type);
+
+		log_printf("%-3d  ", pci_card.schizo_portid);
+		log_printf("%4x, %4x, %4x     ", rev_id, dev_id, ven_id);
+
+		log_printf
+		("%3d, %2d, %2d",
+			pci_card.slot, pci_card.dev_no, pci_card.func_no);
+
+		/* Print status */
+		log_printf("  %-5.5s ", status);
+
+		/* Print Lane widths, Max/Sup Freq, Speed */
+		if (bus_type == PCIE) {
+			PRINT_FMT(actual, maximum);
+		} else if (bus_type == PCIX) {
+			PRINT_FREQ_FMT(freq_at, freq_max);
+		} else if (bus_type == PCI) {
+			err = picldiag_get_clock_freq(nodeh, &freq_at);
+			PRINT_FREQ_FMT(freq_at, freq_max);
+		} else
+			log_printf(" -- , --   ");
+
+		/* Print Card Name */
+		log_printf("%-30.30s", pci_card.name);
+
+		/* Print Card Model */
+		log_printf(" %-20.20s", pci_card.model);
+
+		log_printf("\n");
+
+		log_printf("%4s%-100.100s", " ", pci_card.notes);
+		log_printf("\n");
+		log_printf("\n");
+
+
+		err = picl_get_propval_by_name
+		    (nodeh, PICL_PROP_PEER, &nodeh, sizeof (picl_nodehdl_t));
+
+	}
+
+	return (PICL_WALK_CONTINUE);
+}
+
+/*
+ * opl_display_pci
+ * Display all the PCI IO cards on this board.
+ */
+static int
+opl_display_pci(int syserrlog, picl_nodehdl_t plafh)
+{
+	picl_errno_t err;
+	char	*fmt = "%-3s %-5s %-4s %-20s %-11s %-5s %-11s %-30s %-20s";
+	char 	*fmt2 = "%-16s";
+	static int banner = FALSE; /* Have we printed the column headings? */
+
+	if (banner == FALSE) {
+		log_printf("\n", 0);
+		log_printf("=========================", 0);
+		log_printf(dgettext(TEXT_DOMAIN, " IO Devices "), 0);
+		log_printf("=========================", 0);
+		log_printf("\n", 0);
+		log_printf("\n", 0);
+		log_printf(fmt, "", "IO", "", "", "", "", "Lane/Frq",
+			"", "", 0);
+		log_printf("\n", 0);
+
+		log_printf(fmt, "LSB", "Type", "LPID", "  RvID,DvID,VnID",
+			"  BDF", "State", "Act,  Max", "Name", "Model", 0);
+
+		log_printf("\n");
+
+		log_printf
+			(fmt, "---", "-----", "----", "  ------------------",
+			"  ---------", "-----", "-----------",
+			"------------------------------",
+			"--------------------", 0);
+		log_printf("\n");
+		log_printf(fmt2, "    Logical Path");
+		log_printf("\n");
+		log_printf(fmt2, "    ------------");
+		log_printf("\n");
+		banner = TRUE;
+	}
+
+	err = do_walk(plafh, PICL_CLASS_PCI, PICL_CLASS_PCI, opl_pci_callback);
+	return (err);
+}
+
+
+/*
+ * return the first compatible value
+ */
+static int
+opl_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
+{
+	picl_errno_t	err;
+	picl_prophdl_t	proph;
+	picl_propinfo_t	pinfo;
+	picl_prophdl_t	tblh;
+	picl_prophdl_t	rowproph;
+	char		*pval;
+
+	err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
+	    &pinfo, &proph);
+	if (err != PICL_SUCCESS)
+	    return (err);
+
+	if (pinfo.type == PICL_PTYPE_CHARSTRING) {
+		pval = malloc(pinfo.size);
+		if (pval == NULL)
+			return (PICL_FAILURE);
+		err = picl_get_propval(proph, pval, pinfo.size);
+		if (err != PICL_SUCCESS) {
+			free(pval);
+			return (err);
+		}
+		*outbuf = pval;
+		return (PICL_SUCCESS);
+	}
+
+	if (pinfo.type != PICL_PTYPE_TABLE)
+		return (PICL_FAILURE);
+
+	/* get first string from table */
+	err = picl_get_propval(proph, &tblh, pinfo.size);
+	if (err != PICL_SUCCESS)
+		return (err);
+
+	err = picl_get_next_by_row(tblh, &rowproph);
+	if (err != PICL_SUCCESS)
+		return (err);
+
+	err = picl_get_propinfo(rowproph, &pinfo);
+	if (err != PICL_SUCCESS)
+	    return (err);
+
+	pval = malloc(pinfo.size);
+	if (pval == NULL)
+		return (PICL_FAILURE);
+
+	err = picl_get_propval(rowproph, pval, pinfo.size);
+	if (err != PICL_SUCCESS) {
+		free(pval);
+		return (err);
+	}
+
+	*outbuf = pval;
+	return (PICL_SUCCESS);
+}
+
+int
+do_piclinfo(int syserrlog)
+{
+	picl_nodehdl_t rooth;		/* root PICL node for IO display */
+	picl_nodehdl_t plafh;		/* Platform PICL node for IO display */
+
+	picl_errno_t err;
+
+	err = picl_initialize();
+	if (err != PICL_SUCCESS) {
+		(void) log_printf("picl_initialize failed: %s\n",
+			picl_strerror(err));
+		return (err);
+	}
+
+
+	err = picl_get_root(&rooth);
+	if (err != PICL_SUCCESS) {
+		(void) log_printf("Getting root node failed: %s\n",
+			picl_strerror(err));
+		return (err);
+	}
+
+	err = opl_get_node_by_name(rooth, PICL_NODE_PLATFORM, &plafh);
+
+	if (err != PICL_SUCCESS) {
+		(void) log_printf("Getting nodes by name failed: %s\n",
+			picl_strerror(err));
+		return (err);
+	}
+
+	err = opl_display_pci(syserrlog, plafh);
+
+	(void) picl_shutdown();
+
+	return (err);
+}
+
+/*
+ * search children to get the node by the nodename
+ */
+static int
+opl_get_node_by_name(picl_nodehdl_t rooth, char *name,
+    picl_nodehdl_t *nodeh)
+{
+	picl_nodehdl_t	childh;
+	int		err;
+	char		*nodename;
+
+	nodename = alloca(strlen(name) + 1);
+	if (nodename == NULL)
+		return (PICL_FAILURE);
+
+	err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh,
+		sizeof (picl_nodehdl_t));
+
+	while (err == PICL_SUCCESS) {
+		err = picl_get_propval_by_name(childh, PICL_PROP_NAME,
+			nodename, (strlen(name) + 1));
+		if (err != PICL_SUCCESS) {
+			err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
+				&childh, sizeof (picl_nodehdl_t));
+			continue;
+		}
+
+		if (strcmp(nodename, name) == 0) {
+			*nodeh = childh;
+			return (PICL_SUCCESS);
+		}
+
+		err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
+			&childh, sizeof (picl_nodehdl_t));
+	}
+
+	return (err);
+}
+
+static int
+open_root_complex(char *root_complex)
+{
+	char *path;
+	static char device_str[] = {"/devices"};
+	static char devctl_str[] = {":reg"};
+	int fd;
+
+	path = malloc(
+	    strlen(root_complex) + sizeof (device_str) + sizeof (devctl_str));
+	if (path == NULL)
+		return (PICL_FAILURE);
+	(void) strcpy(path, device_str);
+	(void) strcat(path, root_complex);
+	(void) strcat(path, devctl_str);
+
+	if ((fd = open(path, O_RDWR)) == -1) {
+		return (-1);
+	}
+	return (fd);
+}
+
+static uint32_t
+read_long(int fd, int bus, int dev, int func, int offset, int *ret)
+{
+	int rval;
+	pcitool_reg_t prg;
+
+	prg.user_version = PCITOOL_USER_VERSION;
+	prg.barnum = 0;
+	prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 +
+	    PCITOOL_ACC_ATTR_ENDN_LTL;
+	prg.bus_no = bus;
+	prg.dev_no = dev;
+	prg.func_no = func;
+	prg.offset = offset;
+	rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg);
+	if (rval != 0) {
+		log_printf
+		("DEV_GET failed %d %s\n", rval, strerror(errno));
+		log_printf
+		("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
+	}
+	*ret = rval;
+	return ((uint32_t)prg.data);
+}
+
+static uint16_t
+read_word(int fd, int bus, int dev, int func, int offset, int *ret)
+{
+	int rval;
+	pcitool_reg_t prg;
+
+	prg.user_version = PCITOOL_USER_VERSION;
+	prg.barnum = 0;
+	prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_2 +
+	    PCITOOL_ACC_ATTR_ENDN_LTL;
+	prg.bus_no = bus;
+	prg.dev_no = dev;
+	prg.func_no = func;
+	prg.offset = offset;
+	rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg);
+	if (rval != 0) {
+		log_printf
+		("DEV_GET failed %d %s\n", rval, strerror(errno));
+		log_printf
+		("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
+	}
+	*ret = rval;
+	return ((uint16_t)prg.data);
+}
+
+static uint8_t
+read_byte(int fd, int bus, int dev, int func, int offset, int *ret)
+{
+	int rval;
+	pcitool_reg_t prg;
+
+	prg.user_version = PCITOOL_USER_VERSION;
+	prg.barnum = 0;
+	prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_1 +
+	    PCITOOL_ACC_ATTR_ENDN_LTL;
+	prg.bus_no = bus;
+	prg.dev_no = dev;
+	prg.func_no = func;
+	prg.offset = offset;
+	rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg);
+	if (rval != 0) {
+		log_printf
+		("DEV_GET failed %d %s\n", rval, strerror(errno));
+		log_printf
+		("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
+	}
+	*ret = rval;
+	return ((uint8_t)prg.data);
+}
+
+
+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)
+{
+	uint_t cap_ptr, cap_reg, link_status, link_cap, capid;
+	int fd, ret;
+
+	if (device_path == NULL)
+		return (PICL_FAILURE);
+
+	fd = open_root_complex(device_path);
+	if (fd == -1)
+		return (PICL_FAILURE);
+
+	/*
+	 * Link Capabilities and Link Status registers are in the
+	 * PCI-E capabilities register.  They are at offset
+	 * 0xc and 0x12 respectively. They are documented in section
+	 * 7.8 of the PCI Express Base Specification. The address of
+	 * that structure is not fixed, it's kind of a linked list.
+	 * The Capabilities Pointer reg (8 bits) is always at 0x34.
+	 * It contains a pointer to the first capabilities structure.
+	 * For each capability structure, the first 8 bits is the capability
+	 * ID. The next 8 bits is the pointer to the next structure.
+	 * If the Next Cap register is zero, it's the end of the list.
+	 * The capability ID for the PCI-E strucutre is 0x10.  The idea
+	 * is to follow the links until you find a Cap ID of 0x10, then
+	 * read the registers at 0xc and 0x12 from there.
+	 * If there's no Cap ID 0x10, then it's not a PCI-E device.
+	 */
+
+	cap_ptr = read_byte(fd, bus, dev, func, PCI_CONF_CAP_PTR, &ret);
+	if (ret != 0) {
+		/* ioctl failure */
+		return (PICL_FAILURE);
+	}
+	cap_reg = read_word(fd, bus, dev, func, cap_ptr, &ret);
+	if (ret != 0) {
+		/* ioctl failure */
+		return (PICL_FAILURE);
+	}
+	capid = cap_reg & PCI_CAP_MASK;
+	while (cap_ptr != 0) {
+
+		if (capid == PCI_CAP_ID_PCI_E) {
+			link_cap = read_long(fd, bus, dev, func, cap_ptr +
+			    PCIE_LINKCAP, &ret);
+			if (ret != 0) {
+				return (PICL_FAILURE);
+			}
+			link_status = read_word(fd, bus, dev, func, cap_ptr +
+				PCIE_LINKSTS, &ret);
+			if (ret != 0) {
+				return (PICL_FAILURE);
+			}
+			*actual = ((link_status >> PCI_LINK_SHIFT) &
+				PCI_LINK_MASK);
+			*maximum = ((link_cap >> PCI_LINK_SHIFT) &
+				PCI_LINK_MASK);
+			*type = PCIE;
+		}
+		if (capid == PCI_CAP_ID_PCIX) {
+			uint32_t pcix_status;
+			uint8_t hdr_type;
+			int max_speed = PCI_FREQ_66;
+
+			hdr_type = read_byte
+				(fd, bus, dev, func, PCI_CONF_HEADER, &ret);
+			if (ret != 0) {
+				/* ioctl failure */
+				return (PICL_FAILURE);
+			}
+			if ((hdr_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
+				/* This is a PCI-X bridge */
+				uint16_t sec_status, mode;
+				sec_status = read_word(fd, bus, dev, func,
+					cap_ptr + PCI_PCIX_SEC_STATUS, &ret);
+				if (ret != 0) {
+					/* ioctl failure */
+					return (PICL_FAILURE);
+				}
+				if (sec_status & PCI_SEC_133)
+					max_speed = PCI_FREQ_133;
+				if (sec_status & PCI_SEC_266)
+					max_speed = PCI_FREQ_266;
+				if (sec_status & PCI_SEC_533)
+					max_speed = PCI_FREQ_533;
+				*speed_max = max_speed;
+				*type = PCIX;
+				mode = (sec_status >> PCI_CLASS_BRIDGE)
+					& PCI_BRIDGE_MC;
+				if (mode) {
+					int speed;
+					if (mode == PCI_MODE_66)
+						speed = PCI_FREQ_66;
+					else if (mode == PCI_MODE_100)
+						speed = PCI_FREQ_100;
+					else if (mode == PCI_MODE_133)
+						speed = PCI_FREQ_133;
+					*speed_at = speed;
+				}
+
+			} else {  /* Leaf device */
+				pcix_status = read_long(fd, bus, dev, func,
+				    cap_ptr + PCI_PCIX_STATUS, &ret);
+				if (ret != 0) {
+					/* ioctl failure */
+					return (PICL_FAILURE);
+				}
+				if (pcix_status &
+					(PCI_LEAF_ULONG << PCI_SHIFT_133))
+					max_speed = PCI_FREQ_133;
+				if (pcix_status &
+					(PCI_LEAF_ULONG << PCI_SHIFT_266))
+					max_speed = PCI_FREQ_266;
+				if (pcix_status &
+					(PCI_LEAF_ULONG << PCI_SHIFT_533))
+					max_speed = PCI_FREQ_533;
+				*speed_max = max_speed;
+				*type = PCI;
+			}
+		}
+		cap_ptr = (cap_reg >> PCI_REG_FUNC_SHIFT);
+		cap_reg = read_word(fd, bus, dev, func, cap_ptr, &ret);
+		if (ret != 0) {
+			/* ioctl failure */
+			return (PICL_FAILURE);
+		}
+		capid = cap_reg & PCI_CAP_MASK;
+	}
+
+	return (PICL_SUCCESS);
+}
+
+/*
+ * get the clock frequency
+ */
+static int
+picldiag_get_clock_freq(picl_nodehdl_t modh, uint32_t *freq)
+{
+	int		err;
+	uint64_t	clk_freq;
+
+	clk_freq = picldiag_get_uint_propval(modh, OBP_PROP_CLOCK_FREQ, &err);
+	if (err != PICL_SUCCESS)
+		return (err);
+
+	*freq = ROUND_TO_MHZ(clk_freq);
+
+	return (PICL_SUCCESS);
+}
+
+static uint64_t
+picldiag_get_uint_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
+{
+	int		err;
+	picl_prophdl_t	proph;
+	picl_propinfo_t pinfo;
+	uint8_t		uint8v;
+	uint16_t	uint16v;
+	uint32_t	uint32v;
+	uint64_t	uint64v;
+
+	err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
+	if (err != PICL_SUCCESS) {
+		*ret = err;
+		return (0);
+	}
+
+	/*
+	 * If it is not an int or uint prop, return failure
+	 */
+	if ((pinfo.type != PICL_PTYPE_INT) &&
+		(pinfo.type != PICL_PTYPE_UNSIGNED_INT)) {
+		*ret = PICL_FAILURE;
+		return (0);
+	}
+
+
+	/* uint prop */
+
+	switch (pinfo.size) {
+	case sizeof (uint8_t):
+		err = picl_get_propval(proph, &uint8v, sizeof (uint8v));
+		*ret = err;
+		return (uint8v);
+	case sizeof (uint16_t):
+		err = picl_get_propval(proph, &uint16v, sizeof (uint16v));
+		*ret = err;
+		return (uint16v);
+	case sizeof (uint32_t):
+		err = picl_get_propval(proph, &uint32v, sizeof (uint32v));
+		*ret = err;
+		return (uint32v);
+	case sizeof (uint64_t):
+		err = picl_get_propval(proph, &uint64v, sizeof (uint64v));
+		*ret = err;
+		return (uint64v);
+	default:	/* not supported size */
+		*ret = PICL_FAILURE;
+		return (0);
+	}
+}
+
+/*
+ * recursively visit all nodes
+ */
+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))
+{
+	picl_errno_t	err;
+	picl_nodehdl_t  chdh;
+	char		classval[PICL_CLASSNAMELEN_MAX];
+
+	err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh,
+		sizeof (chdh));
+	while (err == PICL_SUCCESS) {
+		err = picl_get_propval_by_name(chdh, PICL_PROP_NAME,
+			classval, sizeof (classval));
+		if (err != PICL_SUCCESS)
+			return (err);
+
+		err = callback_fn(chdh, c_args);
+
+		if ((err = do_walk(chdh, classname, c_args, callback_fn)) !=
+			PICL_WALK_CONTINUE)
+			return (err);
+
+		err = picl_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
+			sizeof (chdh));
+	}
+	if (err == PICL_PROPNOTFOUND)   /* end of a branch */
+		return (PICL_WALK_CONTINUE);
+	return (err);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libprtdiag_psr/sparc/opl/common/opl_picl.h	Fri Jan 12 11:56:47 2007 -0800
@@ -0,0 +1,152 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Opl Platform header file.
+ *
+ * 	called when :
+ *	machine_type == MTYPE_OPL
+ */
+
+#ifndef	_OPL_PICL_H
+#define	_OPL_PICL_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Property names
+ */
+#define	OBP_PROP_REG			"reg"
+#define	OBP_PROP_CLOCK_FREQ		"clock-frequency"
+#define	OBP_PROP_BOARD_NUM		"board#"
+#define	OBP_PROP_REVISION_ID		"revision-id"
+#define	OBP_PROP_VENDOR_ID		"vendor-id"
+#define	OBP_PROP_DEVICE_ID		"device-id"
+#define	OBP_PROP_VERSION_NUM		"version#"
+#define	OBP_PROP_BOARD_TYPE		"board_type"
+#define	OBP_PROP_ECACHE_SIZE		"ecache-size"
+#define	OBP_PROP_IMPLEMENTATION		"implementation#"
+#define	OBP_PROP_MASK			"mask#"
+#define	OBP_PROP_COMPATIBLE		"compatible"
+#define	OBP_PROP_BANNER_NAME		"banner-name"
+#define	OBP_PROP_MODEL			"model"
+#define	OBP_PROP_66MHZ_CAPABLE		"66mhz-capable"
+#define	OBP_PROP_VERSION		"version"
+#define	OBP_PROP_INSTANCE		"instance"
+
+/* PCI BUS types */
+
+#define	PCI	10
+#define	PCIX	20
+#define	PCIE	30
+
+/* PCI device defines */
+
+#define	PCI_CONF_VENID		0x0		/* vendor id, 2 bytes */
+#define	PCI_CONF_DEVID		0x2		/* device id, 2 bytes */
+#define	PCI_CONF_CAP_PTR	0x34		/* 1 byte capability pointer */
+#define	PCI_CAP_ID_PCI_E	0x10		/* PCI Express supported */
+#define	PCIE_LINKCAP		0x0C		/* Link Capability */
+#define	PCIE_LINKSTS		0x12		/* Link Status */
+#define	PCI_CAP_MASK		0xff		/* CAP Mask */
+#define	PCI_DEV_MASK		0xF800		/* Dev# Mask */
+#define	PCI_FUNC_MASK		0x700		/* Func# Mask */
+#define	PCI_BUS_MASK		0x1ff0000	/* Bus# Mask */
+#define	PCI_LINK_MASK		0x1f		/* Link Mask */
+
+#define	PCI_LINK_SHIFT		4		/* Link shift Bits */
+#define	PCI_FREQ_66		66		/* PCI default freq */
+#define	PCI_FREQ_100		100
+
+/* PCI frequencies */
+
+#define	PCI_FREQ_133		133
+#define	PCI_FREQ_266		266
+#define	PCI_FREQ_533		533
+
+/* PCI frequency shift bits */
+
+#define	PCI_SHIFT_133		17
+#define	PCI_SHIFT_266		30
+#define	PCI_SHIFT_533		31
+
+/* PCI frequency modes */
+
+#define	PCI_MODE_66		1
+#define	PCI_MODE_100		2
+#define	PCI_MODE_133		3
+
+/* PCI frequency SEC status masks */
+
+#define	PCI_SEC_133		0x2
+#define	PCI_SEC_266		0x4000
+#define	PCI_SEC_533		0x8000
+#define	PCI_LEAF_ULONG		1UL
+
+
+/* Invalid property value */
+#define	PROP_INVALID		-1
+
+/* Macros */
+
+#define	IS_PCI(name) \
+	(((name) != NULL) && (strncmp((name), "pci", 3) == 0))
+
+#define	IS_EBUS(class) \
+	(((class) != NULL) && (strncmp((class), "ebus", 4) == 0))
+
+#define	ROUND_TO_MHZ(x)	(((x) + 500000)/ 1000000)
+
+#define	PRINT_FREQ_FMT(arg_1, arg_2) \
+		if (((arg_1) != 0) && \
+			((arg_2) != 0)) \
+				log_printf("%4d, %4d  ", (arg_1), (arg_2)); \
+			else if ((arg_2) != 0) \
+				log_printf("  --, %4d  ", (arg_2)); \
+			else if ((arg_1) != 0) \
+				log_printf("%4d,  -- ", (arg_1)); \
+			else \
+				log_printf("  --,  --  ");
+
+#define	PRINT_FMT(arg_1, arg_2) \
+		if (((arg_1) != PROP_INVALID) && \
+			((arg_2) != PROP_INVALID)) \
+				log_printf("%4d, %4d  ", (arg_1), (arg_2)); \
+			else if ((arg_2) != PROP_INVALID) \
+				log_printf("  --, %4d  ", (arg_2)); \
+			else if ((arg_1) != PROP_INVALID) \
+				log_printf("%4d,  -- ", (arg_1)); \
+			else \
+				log_printf("  --,  --  ");
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OPL_PICL_H */