changeset 14011:779e63d911a5

3679 prtconf should print out PCI database information 3680 Want a library to allow programatic access to the pci database Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com> Reviewed by: Theo Schlossnagle <jesus@omniti.com> Reviewed by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net> Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com> Approved by: Gordon Ross <gwr@nexenta.com>
author Robert Mustacchi <rm@joyent.com>
date Tue, 02 Apr 2013 17:25:01 -0700
parents 61e74b16a691
children c1f1ea4feeb1
files exception_lists/packaging usr/src/cmd/prtconf/Makefile.com usr/src/cmd/prtconf/pdevinfo.c usr/src/cmd/prtconf/prt_xxx.c usr/src/cmd/prtconf/prtconf.h usr/src/lib/Makefile usr/src/lib/libpcidb/Makefile usr/src/lib/libpcidb/Makefile.com usr/src/lib/libpcidb/amd64/Makefile usr/src/lib/libpcidb/common/llib-lpcidb usr/src/lib/libpcidb/common/mapfile-vers usr/src/lib/libpcidb/common/pcidb.c usr/src/lib/libpcidb/common/pcidb.h usr/src/lib/libpcidb/i386/Makefile usr/src/lib/libpcidb/sparc/Makefile usr/src/lib/libpcidb/sparcv9/Makefile usr/src/man/man1m/prtconf.1m usr/src/pkg/manifests/system-library.mf
diffstat 18 files changed, 1128 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/exception_lists/packaging	Thu Apr 11 10:46:40 2013 -0700
+++ b/exception_lists/packaging	Tue Apr 02 17:25:01 2013 -0700
@@ -981,3 +981,13 @@
 usr/lib/amd64/libsaveargs.so      	i386
 usr/lib/amd64/libstandsaveargs.so	i386
 usr/lib/amd64/llib-lsaveargs.ln   	i386
+
+#
+# libpcidb is private
+#
+usr/include/pcidb.h
+usr/lib/amd64/libpcidb.so
+usr/lib/amd64/llib-lpcidb.ln
+usr/lib/libpcidb.so
+usr/lib/llib-lpcidb
+usr/lib/llib-lpcidb.ln
--- a/usr/src/cmd/prtconf/Makefile.com	Thu Apr 11 10:46:40 2013 -0700
+++ b/usr/src/cmd/prtconf/Makefile.com	Tue Apr 02 17:25:01 2013 -0700
@@ -33,7 +33,7 @@
 CERRWARN +=	-_gcc=-Wno-parentheses
 CERRWARN +=	-_gcc=-Wno-switch
 CERRWARN +=	-_gcc=-Wno-uninitialized
-LDLIBS	+= -ldevinfo -lnvpair
+LDLIBS	+= -ldevinfo -lnvpair -lpcidb
 
 FILEMODE= 02555
 
--- a/usr/src/cmd/prtconf/pdevinfo.c	Thu Apr 11 10:46:40 2013 -0700
+++ b/usr/src/cmd/prtconf/pdevinfo.c	Tue Apr 02 17:25:01 2013 -0700
@@ -22,6 +22,9 @@
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ */
 
 /*
  * For machines that support the openprom, fetch and print the list
@@ -44,6 +47,7 @@
 #include <sys/stat.h>
 #include <zone.h>
 #include <libnvpair.h>
+#include <pcidb.h>
 #include "prtconf.h"
 
 
@@ -95,6 +99,7 @@
 typedef struct di_args {
 	di_prom_handle_t	prom_hdl;
 	di_devlink_handle_t	devlink_hdl;
+	pcidb_hdl_t 		*pcidb_hdl;
 } di_arg_t;
 
 static const dumpops_t sysprop_dumpops = {
@@ -155,6 +160,7 @@
 static void promclose();
 static di_node_t find_target_node(di_node_t);
 static void node_display_set(di_node_t);
+static int dump_pciid(char *, int, di_node_t, pcidb_hdl_t *);
 
 void
 prtconf_devinfo(void)
@@ -163,6 +169,7 @@
 	di_arg_t		di_arg;
 	di_prom_handle_t	prom_hdl = DI_PROM_HANDLE_NIL;
 	di_devlink_handle_t	devlink_hdl = NULL;
+	pcidb_hdl_t		*pcidb_hdl = NULL;
 	di_node_t		root_node;
 	uint_t			flag;
 	char			*rootpath;
@@ -219,8 +226,16 @@
 			exit(0);
 	}
 
+	if (opts.o_verbose || opts.o_pciid) {
+		pcidb_hdl = pcidb_open(PCIDB_VERSION);
+		if (pcidb_hdl == NULL)
+			(void) _error(NULL, "pcidb facility not available, "
+			    "continuing anyways");
+	}
+
 	di_arg.prom_hdl = prom_hdl;
 	di_arg.devlink_hdl = devlink_hdl;
+	di_arg.pcidb_hdl = pcidb_hdl;
 
 	/*
 	 * ...and walk all nodes to report them out...
@@ -293,6 +308,8 @@
 		di_prom_fini(prom_hdl);
 	if (devlink_hdl != NULL)
 		(void) di_devlink_fini(&devlink_hdl);
+	if (pcidb_hdl != NULL)
+		pcidb_close(pcidb_hdl);
 	di_fini(root_node);
 }
 
@@ -750,7 +767,7 @@
 
 	(void) printf("%s", di_node_name(node));
 	if (opts.o_pciid)
-		(void) print_pciid(node, di_arg->prom_hdl);
+		(void) print_pciid(node, di_arg->prom_hdl, di_arg->pcidb_hdl);
 
 	/*
 	 * if this node does not have an instance number or is the
@@ -790,9 +807,13 @@
 
 		/* Ensure that 'compatible' is printed under Hardware header */
 		if (!compat_printed)
-			(void) dump_compatible(printed ? NULL : "Hardware",
+			printed |= dump_compatible(printed ? NULL : "Hardware",
 			    ilev + 1, node);
 
+		/* Ensure that pci id information is printed under Hardware */
+		(void) dump_pciid(printed ? NULL : "Hardware",
+		    ilev + 1, node, di_arg->pcidb_hdl);
+
 		dump_priv_data(ilev + 1, node);
 		dump_pathing_data(ilev + 1, node);
 		dump_link_data(ilev + 1, node, devlink_hdl);
@@ -1924,3 +1945,104 @@
 	(void) putchar('\n');
 	return (1);
 }
+
+static int
+dump_pciid(char *name, int ilev, di_node_t node, pcidb_hdl_t *pci)
+{
+	char *t = NULL;
+	int *vid, *did, *svid, *sdid;
+	const char *vname, *dname, *sname;
+	pcidb_vendor_t *pciv;
+	pcidb_device_t *pcid;
+	pcidb_subvd_t *pcis;
+	di_node_t pnode = di_parent_node(node);
+
+	const char *unov = "unknown vendor";
+	const char *unod = "unknown device";
+	const char *unos = "unknown subsystem";
+
+	if (pci == NULL)
+		return (0);
+
+	vname = unov;
+	dname = unod;
+	sname = unos;
+
+	if (di_prop_lookup_strings(DDI_DEV_T_ANY, pnode,
+	    "device_type", &t) <= 0)
+		return (0);
+
+	if (t == NULL || (strcmp(t, "pci") != 0 &&
+	    strcmp(t, "pciex") != 0))
+		return (0);
+
+	/*
+	 * All devices should have a vendor and device id, if we fail to find
+	 * one, then we're going to return right here and not print anything.
+	 *
+	 * We're going to also check for the subsystem-vendor-id and
+	 * subsystem-id. If we don't find one of them, we're going to assume
+	 * that this device does not have one. In that case, we will never
+	 * attempt to try and print anything related to that. If it does have
+	 * both, then we are going to look them up and print the appropriate
+	 * string if we find it or not.
+	 */
+	if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "vendor-id", &vid) <= 0)
+		return (0);
+
+	if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "device-id", &did) <= 0)
+		return (0);
+
+	if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "subsystem-vendor-id",
+	    &svid) <= 0 || di_prop_lookup_ints(DDI_DEV_T_ANY, node,
+	    "subsystem-id", &sdid) <= 0) {
+		svid = NULL;
+		sdid = NULL;
+		sname = NULL;
+	}
+
+	pciv = pcidb_lookup_vendor(pci, vid[0]);
+	if (pciv == NULL)
+		goto print;
+	vname = pcidb_vendor_name(pciv);
+
+	pcid = pcidb_lookup_device_by_vendor(pciv, did[0]);
+	if (pcid == NULL)
+		goto print;
+	dname = pcidb_device_name(pcid);
+
+	if (svid != NULL) {
+		pcis = pcidb_lookup_subvd_by_device(pcid, svid[0], sdid[0]);
+		if (pcis == NULL)
+			goto print;
+		sname = pcidb_subvd_name(pcis);
+	}
+
+print:
+	/* If name is non-NULL, produce header */
+	if (name) {
+		indent_to_level(ilev);
+		(void) printf("%s properties:\n", name);
+	}
+	ilev++;
+
+	/* These are all going to be single string properties */
+	indent_to_level(ilev);
+	(void) printf("name='vendor-name' type=string items=1\n");
+	indent_to_level(ilev);
+	(void) printf("    value='%s'\n", vname);
+
+	indent_to_level(ilev);
+	(void) printf("name='device-name' type=string items=1\n");
+	indent_to_level(ilev);
+	(void) printf("    value='%s'\n", dname);
+
+	if (sname != NULL) {
+		indent_to_level(ilev);
+		(void) printf("name='subsystem-name' type=string items=1\n");
+		indent_to_level(ilev);
+		(void) printf("    value='%s'\n", sname);
+	}
+
+	return (0);
+}
--- a/usr/src/cmd/prtconf/prt_xxx.c	Thu Apr 11 10:46:40 2013 -0700
+++ b/usr/src/cmd/prtconf/prt_xxx.c	Tue Apr 02 17:25:01 2013 -0700
@@ -21,6 +21,8 @@
 /*
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ *
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
  */
 
 #include <stdio.h>
@@ -418,8 +420,10 @@
  * Print vendor ID and device ID for PCI devices
  */
 int
-print_pciid(di_node_t node, di_prom_handle_t ph)
+print_pciid(di_node_t node, di_prom_handle_t ph, pcidb_hdl_t *pci)
 {
+	pcidb_vendor_t *vend;
+	pcidb_device_t *dev;
 	di_node_t pnode = di_parent_node(node);
 	char *s = NULL;
 	int *i, type = di_nodeid(node);
@@ -436,10 +440,28 @@
 	    "vendor-id", &i) > 0)
 		(void) printf("%x", i[0]);
 
+	if (pci != NULL)
+		vend = pcidb_lookup_vendor(pci, i[0]);
+
 	if (LOOKUP_PROP(ints, ph, type, DDI_DEV_T_ANY, node,
 	    "device-id", &i) > 0)
 		(void) printf(",%x", i[0]);
-	(void) printf(")");
+
+	if (pci != NULL)
+		dev = pcidb_lookup_device_by_vendor(vend, i[0]);
+
+	(void) printf(") [");
 
+	if (vend != NULL)
+		(void) printf("%s ", pcidb_vendor_name(vend));
+	else
+		(void) printf("unknown vendor, ");
+
+	if (dev != NULL)
+		(void) printf("%s", pcidb_device_name(dev));
+	else
+		(void) printf("unknown device");
+
+	(void) printf("]");
 	return (1);
 }
--- a/usr/src/cmd/prtconf/prtconf.h	Thu Apr 11 10:46:40 2013 -0700
+++ b/usr/src/cmd/prtconf/prtconf.h	Tue Apr 02 17:25:01 2013 -0700
@@ -21,6 +21,7 @@
 /*
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright (c) 2012 Joyent, Inc.  All rights reserved.
  */
 
 #ifndef	_PRT_CONF_H
@@ -31,11 +32,12 @@
 #endif
 
 #include <libdevinfo.h>
+#include <pcidb.h>
 #include <sys/utsname.h>
 
 extern void init_priv_data(struct di_priv_data *);
 extern void dump_priv_data(int, di_node_t);
-extern int print_pciid(di_node_t, di_prom_handle_t);
+extern int print_pciid(di_node_t, di_prom_handle_t, pcidb_hdl_t *);
 extern void indent_to_level(int);
 extern void prtconf_devinfo();
 extern int do_fbname();
--- a/usr/src/lib/Makefile	Thu Apr 11 10:46:40 2013 -0700
+++ b/usr/src/lib/Makefile	Tue Apr 02 17:25:01 2013 -0700
@@ -22,6 +22,7 @@
 # Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
 # Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
 # Copyright (c) 2012 by Delphix. All rights reserved.
+# Copyright (c) 2012, Joyent, Inc. All rights reserved.
 
 include ../Makefile.master
 
@@ -157,7 +158,8 @@
 	libdscfg	\
 	librdc		\
 	libinstzones	\
-	libpkg
+	libpkg		\
+	libpcidb
 
 SUBDIRS += \
 	passwdutil	\
@@ -432,6 +434,7 @@
 	libnsl		\
 	libnwam		\
 	libpam		\
+	libpcidb	\
 	libpctx		\
 	libpicl		\
 	libpicltree	\
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libpcidb/Makefile	Tue Apr 02 17:25:01 2013 -0700
@@ -0,0 +1,55 @@
+#
+# 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 (c) 2012 Joyent, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.lib
+
+HDRS = pcidb.h
+HDRDIR = common
+
+SUBDIRS = $(MACH) 
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+install: install_h $(SUBDIRS)
+
+install_h: $(ROOTHDRS)
+
+check: $(CHECKHDRS)
+
+$(SUBDIRS): FRC
+	@cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libpcidb/Makefile.com	Tue Apr 02 17:25:01 2013 -0700
@@ -0,0 +1,45 @@
+#
+# 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 (c) 2012 Joyent, Inc. All rights reserved.
+#
+
+LIBRARY = libpcidb.a
+VERS = .1
+OBJECTS = pcidb.o
+
+include ../../Makefile.lib
+
+LIBS = $(DYNLIB) $(LINTLIB)
+
+SRCDIR = ../common
+
+LDLIBS += -lc
+
+$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libpcidb/amd64/Makefile	Tue Apr 02 17:25:01 2013 -0700
@@ -0,0 +1,29 @@
+#
+# 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 (c) 2012 Joyent, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libpcidb/common/llib-lpcidb	Tue Apr 02 17:25:01 2013 -0700
@@ -0,0 +1,30 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (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 (c) 2012 Joyent, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+#include <pcidb.h>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libpcidb/common/mapfile-vers	Tue Apr 02 17:25:01 2013 -0700
@@ -0,0 +1,69 @@
+#
+# 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 (c) 2012 Joyent, Inc. All rights reserved.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING:  STOP NOW.  DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+#	usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION SUNWprivate {
+    global:
+	pcidb_open;
+	pcidb_close;
+	pcidb_lookup_vendor;
+	pcidb_vendor_iter;
+	pcidb_vendor_iter_next;
+	pcidb_vendor_name;
+	pcidb_vendor_id;
+	pcidb_lookup_device;
+	pcidb_lookup_device_by_vendor;
+	pcidb_device_iter;
+	pcidb_device_iter_next;
+	pcidb_device_name;
+	pcidb_device_id;
+	pcidb_device_vendor;
+	pcidb_lookup_subvd;
+	pcidb_lookup_subvd_by_vendor;	
+	pcidb_lookup_subvd_by_device;	
+	pcidb_subvd_iter;
+	pcidb_subvd_iter_next;
+	pcidb_subvd_name;
+	pcidb_subvd_svid;
+	pcidb_subvd_sdid;
+	pcidb_subvd_device;
+	pcidb_subvd_vendor;
+    local:
+	*;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libpcidb/common/pcidb.c	Tue Apr 02 17:25:01 2013 -0700
@@ -0,0 +1,559 @@
+/*
+ * 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 (c) 2012, Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * This library exists to understand and parse the pci.ids database that is
+ * maintained at http://pci-ids.ucw.cz/ and in the gate at cmd/hwdata. This
+ * database provides a way to map the PCI device, vendor, and subsystem ids to
+ * a human understandable name.
+ *
+ * This library exports this data in a similar way to a tree. The handle that
+ * is returned from pcidb_open is the root of the tree. The next level are the
+ * vendors. Each vendor has a unique set of devices and each device has a unique
+ * set of subvendor and subdevice pairs.
+ *
+ * Parsing information:
+ *
+ * The database is formatted in the following basic format:
+ * vendor_id<two spaces>vendor_name
+ * <tab>device_id<two spaces>device_name
+ * <tab><tab>subvendor<space>subdevice<two spaces>subsystem_name
+ *
+ * For any given vendor, there can be multiple devices. And for any given device
+ * there will be multiple subsystems. In addition, there can be comments that
+ * start a line which use the '#' character.
+ *
+ * At the end of the file, there are a series of PCI classes. Those will start
+ * with a single C<space>. Once we hit those, we stop all parsing. We currently
+ * don't care about consuming or presenting those.
+ */
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+#include <unistd.h>
+
+#include "pcidb.h"
+
+#define	PCI_NAME_MAX	256
+#define	PCI_READLINE	1024
+
+/* Forward declarations */
+struct pcidb_vendor;
+struct pcidb_device;
+struct pcidb_subvd;
+
+struct pcidb_subvd {
+	uint16_t		ps_vid;
+	uint16_t		ps_did;
+	char			ps_name[PCI_NAME_MAX];
+	struct pcidb_subvd	*ps_prev;
+	struct pcidb_subvd	*ps_next;
+	struct pcidb_device	*ps_dev;
+	struct pcidb_vendor	*ps_vend;
+};
+
+struct pcidb_device {
+	uint16_t		pd_id;
+	char			pd_name[PCI_NAME_MAX];
+	struct pcidb_subvd	*pd_sstart;
+	struct pcidb_subvd	*pd_send;
+	struct pcidb_device	*pd_next;
+	struct pcidb_device	*pd_prev;
+	struct pcidb_vendor	*pd_vend;
+};
+
+struct pcidb_vendor {
+	uint16_t		pv_id;
+	char 			pv_name[PCI_NAME_MAX];
+	struct pcidb_device	*pv_dstart;
+	struct pcidb_device	*pv_dend;
+	struct pcidb_vendor	*pv_prev;
+	struct pcidb_vendor	*pv_next;
+};
+
+struct pcidb_hdl {
+	pcidb_vendor_t	*ph_vstart;
+	pcidb_vendor_t	*ph_vend;
+};
+
+typedef enum pcidb_parse {
+	PDB_VENDOR,
+	PDB_DEVICE,
+	PDB_SUBDEV
+} pcidb_parse_t;
+
+static const char *pci_db = "/usr/share/hwdata/pci.ids";
+
+static void
+pcihdl_add_vendor(pcidb_hdl_t *hdl, pcidb_vendor_t *v)
+{
+	if (hdl->ph_vstart == NULL && hdl->ph_vend == NULL) {
+		hdl->ph_vstart = v;
+		hdl->ph_vend = v;
+		v->pv_prev = NULL;
+		v->pv_next = NULL;
+	} else {
+		v->pv_prev = hdl->ph_vend;
+		v->pv_next = NULL;
+		hdl->ph_vend->pv_next = v;
+		hdl->ph_vend = v;
+	}
+}
+
+static pcidb_vendor_t *
+parse_vendor(char *buf, pcidb_hdl_t *hdl)
+{
+	pcidb_vendor_t *v;
+	size_t len;
+
+	v = malloc(sizeof (pcidb_vendor_t));
+	if (v == NULL)
+		return (NULL);
+
+	pcihdl_add_vendor(hdl, v);
+	v->pv_dstart = NULL;
+	v->pv_dend = NULL;
+
+	buf[4] = '\0';
+	v->pv_id = strtol(buf, NULL, 16);
+	buf += 6;
+	len = strlen(buf);
+	if (buf[len-1] == '\n')
+		buf[len-1] = '\0';
+
+	(void) strlcpy(v->pv_name, buf, PCI_NAME_MAX);
+
+	return (v);
+}
+
+static void
+insert_device(pcidb_vendor_t *v, pcidb_device_t *d)
+{
+	d->pd_vend = v;
+	if (v->pv_dstart == NULL && v->pv_dend == NULL) {
+		v->pv_dstart = d;
+		v->pv_dend = d;
+		d->pd_next = NULL;
+		d->pd_prev = NULL;
+	} else {
+		d->pd_prev = v->pv_dend;
+		d->pd_next = NULL;
+		v->pv_dend->pd_next = d;
+		v->pv_dend = d;
+	}
+}
+
+static pcidb_device_t *
+parse_device(char *buf, pcidb_vendor_t *v)
+{
+	pcidb_device_t *d;
+	size_t len;
+
+	d = malloc(sizeof (pcidb_device_t));
+	if (d == NULL)
+		return (d);
+
+	d->pd_sstart = NULL;
+	d->pd_send = NULL;
+	insert_device(v, d);
+
+	buf++;
+	buf[4] = '\0';
+	d->pd_id = strtol(buf, NULL, 16);
+	buf += 6;
+	len = strlen(buf);
+	if (buf[len-1] == '\n')
+		buf[len-1] = '\0';
+
+	(void) strlcpy(d->pd_name, buf, PCI_NAME_MAX);
+	return (d);
+}
+
+static void
+insert_subdev(pcidb_device_t *d, pcidb_subvd_t *s)
+{
+	s->ps_dev = d;
+	s->ps_vend = d->pd_vend;
+	if (d->pd_sstart == NULL) {
+		d->pd_sstart = s;
+		d->pd_send = s;
+		s->ps_prev = NULL;
+		s->ps_next = NULL;
+	} else {
+		s->ps_prev = d->pd_send;
+		s->ps_next = NULL;
+		d->pd_send->ps_next = s;
+		d->pd_send = s;
+	}
+}
+
+static pcidb_subvd_t *
+parse_subdev(char *buf, pcidb_device_t *d)
+{
+	pcidb_subvd_t *s;
+	size_t len;
+
+	s = malloc(sizeof (pcidb_subvd_t));
+	if (s == NULL)
+		return (NULL);
+	insert_subdev(d, s);
+
+	buf += 2;
+	buf[4] = '\0';
+	s->ps_vid = strtol(buf, NULL, 16);
+	buf += 5;
+	buf[4] = '\0';
+	s->ps_did = strtol(buf, NULL, 16);
+	buf += 6;
+
+	len = strlen(buf);
+	if (buf[len-1] == '\n')
+		buf[len-1] = '\0';
+
+	(void) strlcpy(s->ps_name, buf, PCI_NAME_MAX);
+
+	return (s);
+}
+
+static int
+readline(FILE *f, char *buf, size_t len)
+{
+	for (;;) {
+		if (fgets(buf, len, f) == NULL)
+			return (-1);
+
+		if (buf[0] == 'C')
+			return (-1);
+
+		if (buf[0] != '#' && buf[0] != '\n')
+			return (0);
+	}
+}
+
+static int
+parse_db(FILE *f, pcidb_hdl_t *hdl)
+{
+	char buf[1024];
+	pcidb_vendor_t *v = NULL;
+	pcidb_device_t *d = NULL;
+	pcidb_parse_t state = PDB_VENDOR;
+
+	for (;;) {
+		errno = 0;
+		if (readline(f, buf, sizeof (buf)) != 0) {
+			if (errno != 0)
+				return (-1);
+			else
+				return (0);
+		}
+
+newstate:
+		switch (state) {
+		case PDB_VENDOR:
+			v = parse_vendor(buf, hdl);
+			if (v == NULL)
+				return (NULL);
+			state = PDB_DEVICE;
+			continue;
+		case PDB_DEVICE:
+			if (buf[0] != '\t') {
+				state = PDB_VENDOR;
+				goto newstate;
+			}
+
+			if (buf[1] == '\t') {
+				state = PDB_SUBDEV;
+				goto newstate;
+			}
+
+			assert(v != NULL);
+			d = parse_device(buf, v);
+			if (d == NULL)
+				return (NULL);
+			continue;
+		case PDB_SUBDEV:
+			if (buf[0] != '\t') {
+				state = PDB_VENDOR;
+				goto newstate;
+			}
+
+			if (buf[0] == '\t' && buf[1] != '\t') {
+				state = PDB_DEVICE;
+				goto newstate;
+			}
+
+			assert(buf[0] == '\t' && buf[1] == '\t');
+			assert(d != NULL);
+			(void) parse_subdev(buf, d);
+		}
+	}
+}
+
+pcidb_hdl_t *
+pcidb_open(int version)
+{
+	pcidb_hdl_t *h;
+	FILE *f;
+
+	if (version != PCIDB_VERSION) {
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	h = malloc(sizeof (pcidb_hdl_t));
+	if (h == NULL)
+		return (NULL);
+
+	h->ph_vstart = NULL;
+	h->ph_vend = NULL;
+
+	f = fopen(pci_db, "rF");
+	if (f == NULL) {
+		free(h);
+		return (NULL);
+	}
+
+	if (parse_db(f, h) < 0) {
+		pcidb_close(h);
+		free(h);
+		return (NULL);
+	}
+
+	return (h);
+}
+
+void
+pcidb_close(pcidb_hdl_t *h)
+{
+	pcidb_vendor_t *v, *tv;
+
+	pcidb_device_t *d, *td;
+	pcidb_subvd_t *s, *ts;
+
+	if (h == NULL)
+		return;
+
+	v = h->ph_vstart;
+	while (v != NULL) {
+		d = v->pv_dstart;
+		while (d != NULL) {
+			s = d->pd_sstart;
+			while (s != NULL) {
+				ts = s;
+				s = s->ps_next;
+				free(ts);
+			}
+			td = d;
+			d = d->pd_next;
+			free(td);
+		}
+		tv = v;
+		v = v->pv_next;
+		free(tv);
+	}
+
+	free(h);
+}
+
+pcidb_vendor_t *
+pcidb_lookup_vendor(pcidb_hdl_t *hdl, uint16_t id)
+{
+	pcidb_vendor_t *v;
+
+	for (v = hdl->ph_vstart; v != NULL; v = v->pv_next) {
+		if (v->pv_id == id)
+			return (v);
+	}
+
+	return (NULL);
+}
+
+const char *
+pcidb_vendor_name(pcidb_vendor_t *v)
+{
+	return (v->pv_name);
+}
+
+uint16_t
+pcidb_vendor_id(pcidb_vendor_t *v)
+{
+	return (v->pv_id);
+}
+
+pcidb_vendor_t *
+pcidb_vendor_iter(pcidb_hdl_t *h)
+{
+	return (h->ph_vstart);
+}
+
+pcidb_vendor_t *
+pcidb_vendor_iter_next(pcidb_vendor_t *v)
+{
+	assert(v != NULL);
+	return (v->pv_next);
+}
+
+pcidb_device_t *
+pcidb_lookup_device_by_vendor(pcidb_vendor_t *v, uint16_t id)
+{
+	pcidb_device_t *d;
+	assert(v != NULL);
+
+	for (d = v->pv_dstart; d != NULL; d = d->pd_next)
+		if (d->pd_id == id)
+			return (d);
+
+	return (NULL);
+}
+
+pcidb_device_t *
+pcidb_lookup_device(pcidb_hdl_t *h, uint16_t vid, uint16_t did)
+{
+	pcidb_vendor_t *v;
+
+	v = pcidb_lookup_vendor(h, vid);
+	if (v == NULL)
+		return (NULL);
+
+	return (pcidb_lookup_device_by_vendor(v, did));
+}
+
+pcidb_device_t *
+pcidb_device_iter(pcidb_vendor_t *v)
+{
+	return (v->pv_dstart);
+}
+
+pcidb_device_t *
+pcidb_device_iter_next(pcidb_device_t *d)
+{
+	return (d->pd_next);
+}
+
+const char *
+pcidb_device_name(pcidb_device_t *d)
+{
+	return (d->pd_name);
+}
+
+uint16_t
+pcidb_device_id(pcidb_device_t *d)
+{
+	return (d->pd_id);
+}
+
+pcidb_vendor_t *
+pcidb_device_vendor(pcidb_device_t *d)
+{
+	return (d->pd_vend);
+}
+
+pcidb_subvd_t *
+pcidb_lookup_subvd_by_device(pcidb_device_t *d, uint16_t svid, uint16_t sdid)
+{
+	pcidb_subvd_t *s;
+
+	assert(d != NULL);
+
+	for (s = d->pd_sstart; s != NULL; s = s->ps_next)
+		if (s->ps_vid == svid && s->ps_did == sdid)
+			return (s);
+
+	return (NULL);
+}
+
+pcidb_subvd_t *
+pcidb_lookup_subvd_by_vendor(pcidb_vendor_t *v, uint16_t devid, uint16_t svid,
+    uint16_t sdid)
+{
+	pcidb_device_t *d;
+
+	assert(v != NULL);
+	d = pcidb_lookup_device_by_vendor(v, devid);
+	if (d == NULL)
+		return (NULL);
+
+	return (pcidb_lookup_subvd_by_device(d, svid, sdid));
+}
+
+pcidb_subvd_t *
+pcidb_lookup_subvd(pcidb_hdl_t *h, uint16_t vid, uint16_t did, uint16_t svid,
+    uint16_t sdid)
+{
+	pcidb_device_t *d;
+
+	assert(h != NULL);
+	d = pcidb_lookup_device(h, vid, did);
+	if (d == NULL)
+		return (NULL);
+
+	return (pcidb_lookup_subvd_by_device(d, svid, sdid));
+}
+
+pcidb_subvd_t *
+pcidb_subvd_iter(pcidb_device_t *d)
+{
+	return (d->pd_sstart);
+}
+
+pcidb_subvd_t *
+pcidb_subvd_iter_next(pcidb_subvd_t *s)
+{
+	return (s->ps_next);
+}
+
+const char *
+pcidb_subvd_name(pcidb_subvd_t *s)
+{
+	return (s->ps_name);
+}
+
+uint16_t
+pcidb_subvd_svid(pcidb_subvd_t *s)
+{
+	return (s->ps_vid);
+}
+
+uint16_t
+pcidb_subvd_sdid(pcidb_subvd_t *s)
+{
+	return (s->ps_did);
+}
+
+pcidb_device_t *
+pcidb_subvd_device(pcidb_subvd_t *s)
+{
+	return (s->ps_dev);
+}
+
+pcidb_vendor_t *
+pcidb_subvd_vendor(pcidb_subvd_t *s)
+{
+	return (s->ps_vend);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libpcidb/common/pcidb.h	Tue Apr 02 17:25:01 2013 -0700
@@ -0,0 +1,84 @@
+/*
+ * 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 (c) 2012, Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * This header file is private to illumos and should not be shipped.
+ */
+
+#ifndef	_PCIDB_H
+#define	_PCIDB_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define	PCIDB_VERSION	1
+
+typedef struct pcidb_hdl pcidb_hdl_t;
+typedef struct pcidb_vendor pcidb_vendor_t;
+typedef struct pcidb_device pcidb_device_t;
+typedef struct pcidb_subvd pcidb_subvd_t;
+
+extern pcidb_hdl_t *pcidb_open(int);
+extern void pcidb_close(pcidb_hdl_t *);
+
+extern pcidb_vendor_t *pcidb_lookup_vendor(pcidb_hdl_t *, uint16_t);
+extern pcidb_vendor_t *pcidb_vendor_iter(pcidb_hdl_t *);
+extern pcidb_vendor_t *pcidb_vendor_iter_next(pcidb_vendor_t *);
+
+extern const char *pcidb_vendor_name(pcidb_vendor_t *);
+extern uint16_t pcidb_vendor_id(pcidb_vendor_t *);
+
+extern pcidb_device_t *pcidb_lookup_device(pcidb_hdl_t *, uint16_t, uint16_t);
+extern pcidb_device_t *pcidb_lookup_device_by_vendor(pcidb_vendor_t *,
+    uint16_t);
+extern pcidb_device_t *pcidb_device_iter(pcidb_vendor_t *);
+extern pcidb_device_t *pcidb_device_iter_next(pcidb_device_t *);
+
+extern const char *pcidb_device_name(pcidb_device_t *);
+extern uint16_t pcidb_device_id(pcidb_device_t *);
+extern pcidb_vendor_t *pcidb_device_vendor(pcidb_device_t *);
+
+extern pcidb_subvd_t *pcidb_lookup_subvd(pcidb_hdl_t *, uint16_t, uint16_t,
+    uint16_t, uint16_t);
+extern pcidb_subvd_t *pcidb_lookup_subvd_by_vendor(pcidb_vendor_t *, uint16_t,
+    uint16_t, uint16_t);
+extern pcidb_subvd_t *pcidb_lookup_subvd_by_device(pcidb_device_t *, uint16_t,
+    uint16_t);
+extern pcidb_subvd_t *pcidb_subvd_iter(pcidb_device_t *);
+extern pcidb_subvd_t *pcidb_subvd_iter_next(pcidb_subvd_t *);
+
+extern const char *pcidb_subvd_name(pcidb_subvd_t *);
+extern uint16_t pcidb_subvd_svid(pcidb_subvd_t *);
+extern uint16_t pcidb_subvd_sdid(pcidb_subvd_t *);
+extern pcidb_device_t *pcidb_subvd_device(pcidb_subvd_t *);
+extern pcidb_vendor_t *pcidb_subvd_vendor(pcidb_subvd_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PCIDB_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libpcidb/i386/Makefile	Tue Apr 02 17:25:01 2013 -0700
@@ -0,0 +1,28 @@
+#
+# 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 (c) 2012 Joyent, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libpcidb/sparc/Makefile	Tue Apr 02 17:25:01 2013 -0700
@@ -0,0 +1,28 @@
+#
+# 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 (c) 2012 Joyent, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libpcidb/sparcv9/Makefile	Tue Apr 02 17:25:01 2013 -0700
@@ -0,0 +1,29 @@
+#
+# 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 (c) 2012 Joyent, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
--- a/usr/src/man/man1m/prtconf.1m	Thu Apr 11 10:46:40 2013 -0700
+++ b/usr/src/man/man1m/prtconf.1m	Tue Apr 02 17:25:01 2013 -0700
@@ -1,9 +1,10 @@
 '\" te
 .\"  Copyright 1989 AT&T Copyright (c) 2003, Sun Microsystems, Inc. All Rights Reserved
+.\"  Copyright 2012, Joyent, Inc. All Rights Reserved
 .\" 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]
-.TH PRTCONF 1M "Mar 13, 2009"
+.TH PRTCONF 1M "Jan 11, 2013"
 .SH NAME
 prtconf \- print system configuration
 .SH SYNOPSIS
@@ -67,7 +68,8 @@
 .ad
 .RS 6n
 Display vendor ID and device ID for PCI and PCI Express devices, in addition to
-the nodename.
+the nodename. If the information is known, the vendor name and device name will
+also be shown.
 .RE
 
 .sp
--- a/usr/src/pkg/manifests/system-library.mf	Thu Apr 11 10:46:40 2013 -0700
+++ b/usr/src/pkg/manifests/system-library.mf	Tue Apr 02 17:25:01 2013 -0700
@@ -347,6 +347,7 @@
 file path=usr/lib/$(ARCH64)/libmtmalloc.so.1
 file path=usr/lib/$(ARCH64)/libnls.so.1
 file path=usr/lib/$(ARCH64)/libpanel.so.1
+file path=usr/lib/$(ARCH64)/libpcidb.so.1
 file path=usr/lib/$(ARCH64)/libpkcs11.so.1
 file path=usr/lib/$(ARCH64)/libproject.so.1
 file path=usr/lib/$(ARCH64)/libraidcfg.so.1
@@ -419,6 +420,7 @@
 file path=usr/lib/libmtmalloc.so.1
 file path=usr/lib/libnls.so.1
 file path=usr/lib/libpanel.so.1
+file path=usr/lib/libpcidb.so.1
 file path=usr/lib/libpkcs11.so.1
 file path=usr/lib/libproject.so.1
 file path=usr/lib/libraidcfg.so.1