15825345 SUNBT7206701 libpciaccess: remove pcitool dependency in probing phase s12_15
authorhenryzh <henry.zhao@oracle.com>
Wed, 23 Jan 2013 12:31:19 -0800
changeset 1349 b1016e88dcd0
parent 1348 31cc94d67017
child 1350 7179bc555162
15825345 SUNBT7206701 libpciaccess: remove pcitool dependency in probing phase
open-src/lib/libpciaccess/Makefile
open-src/lib/libpciaccess/probe_improve.patch
--- a/open-src/lib/libpciaccess/Makefile	Wed Jan 16 12:31:46 2013 -0800
+++ b/open-src/lib/libpciaccess/Makefile	Wed Jan 23 12:31:19 2013 -0800
@@ -44,7 +44,8 @@
 	sparc.patch \
 	nexus_devlist.patch,-p1 \
 	rom_and_scanpci.patch,-p1 \
-	sparc_domain.patch,-p1
+	sparc_domain.patch,-p1 \
+	probe_improve.patch,-p1
 
 # Library name
 LIBNAME=libpciaccess
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/open-src/lib/libpciaccess/probe_improve.patch	Wed Jan 23 12:31:19 2013 -0800
@@ -0,0 +1,631 @@
+--- a/src/solx_devfs.c	Thu Jan 10 14:15:59 2013
++++ b/src/solx_devfs.c	Thu Jan 10 16:22:52 2013
+@@ -1,6 +1,6 @@
+ /*
+  * (C) Copyright IBM Corporation 2006
+- * Copyright (c) 2007, 2009, 2011, 2012, Oracle and/or its affiliates.
++ * Copyright (c) 2007, 2009, 2011, 2012, 2013 Oracle and/or its affiliates.
+  * All Rights Reserved.
+  *
+  * Permission is hereby granted, free of charge, to any person obtaining a
+@@ -51,11 +51,6 @@
+ #define	INITIAL_NUM_DEVICES	256
+ #define	CELL_NUMS_1275	(sizeof(pci_regspec_t) / sizeof(uint_t))
+ 
+-typedef union {
+-    uint8_t bytes[16 * sizeof (uint32_t)];
+-    uint32_t dwords[16];
+-} pci_conf_hdr_t;
+-
+ typedef struct i_devnode {
+     uint8_t bus;
+     uint8_t dev;
+@@ -79,14 +74,17 @@
+     struct pci_device_private * volatile devices;
+ } probe_info_t;
+ 
+-#ifdef __sparc
+-typedef struct bdf_table_info {
+-    int bus;
+-    int dev;
+-    int func;
+-} bdf_table_info_t;
+-#endif
++typedef struct probe_args {
++    probe_info_t *pinfo;
++    nexus_t *nexus;
++    int ret;
++} probe_args_t;
+ 
++typedef struct property_info {
++    char *name;
++    int value;
++} property_info_t;
++
+ static nexus_t *nexus_list = NULL;
+ #if !defined(__sparc)
+ static int xsvc_fd = -1;
+@@ -94,9 +92,6 @@
+ 
+ #ifdef __sparc
+ static di_prom_handle_t di_phdl;
+-static bdf_table_info_t *bdf_table = NULL;
+-static size_t  num_bdfs = 0;
+-static size_t  num_allocated_bdfs = 0;
+ static size_t  nexus_count = 0;
+ #endif
+ 
+@@ -152,15 +147,6 @@
+     return NULL;
+ }
+ 
+-#define GET_CONFIG_VAL_8(offset) (config_hdr.bytes[offset])
+-#define GET_CONFIG_VAL_16(offset) \
+-    (uint16_t) (GET_CONFIG_VAL_8(offset) + (GET_CONFIG_VAL_8(offset+1) << 8))
+-#define GET_CONFIG_VAL_32(offset) \
+-    (uint32_t) (GET_CONFIG_VAL_8(offset) + 		\
+-		(GET_CONFIG_VAL_8(offset+1) << 8) +	\
+-		(GET_CONFIG_VAL_8(offset+2) << 16) +	\
+-		(GET_CONFIG_VAL_8(offset+3) << 24))
+-
+ /*
+  * Release all the resources
+  * Solaris version
+@@ -209,358 +195,111 @@
+ #endif
+ 
+ 
+-/*
+- * Retrieve first 16 dwords of device's config header, except for the first
+- * dword.  First 16 dwords are defined by the PCI specification.
+- */
+ static int
+-get_config_header(int fd, uint8_t bus_no, uint8_t dev_no, uint8_t func_no,
+-		  pci_conf_hdr_t *config_hdr_p)
++probe_device_node(di_node_t node, void *arg)
+ {
+-    pcitool_reg_t cfg_prg;
+-    int i;
+-    int rval = 0;
++    int *retbuf = NULL;
++    int len = 0, i;
++    struct pci_device	*pci_base;
++    probe_info_t *pinfo = ((probe_args_t *)arg)->pinfo;
++    nexus_t *nexus = ((probe_args_t *)arg)->nexus;
++    property_info_t property_list[] = {
++				"class-code", 0,
++    				"device-id", 0,
++    				"vendor-id", 0,
++    				"revision-id", 0,
++    				"subsystem-vendor-id", 0,
++    				"subsystem-id", 0,
++			    	};
++#define NUM_PROPERTIES		sizeof(property_list)/sizeof(property_info_t)
+ 
+-    /* Prepare a local pcitool_reg_t so as to not disturb the caller's. */
+-    cfg_prg.offset = 0;
+-    cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + NATIVE_ENDIAN;
+-    cfg_prg.bus_no = bus_no;
+-    cfg_prg.dev_no = dev_no;
+-    cfg_prg.func_no = func_no;
+-    cfg_prg.barnum = 0;
+-    cfg_prg.user_version = PCITOOL_USER_VERSION;
++    len = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", &retbuf);
+ 
+-    /* Get dwords 1-15 of config space. They must be read as uint32_t. */
+-    for (i = 1; i < (sizeof (pci_conf_hdr_t) / sizeof (uint32_t)); i++) {
+-	cfg_prg.offset += sizeof (uint32_t);
+-	if ((rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &cfg_prg)) != 0) {
+-	    break;
+-	}
+-	config_hdr_p->dwords[i] = (uint32_t)cfg_prg.data;
+-    }
+-
+-    return (rval);
+-}
+-
+ #ifdef __sparc
+-static int
+-create_bdf_table(di_node_t node, void *arg)
+-{
+-    int *regbuf = NULL;
+-    int len = 0;
+-
+-    len = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", &regbuf);
+-
+     if ((len <= 0) && di_phdl)
+-	len = di_prom_prop_lookup_ints(di_phdl, node, "reg", &regbuf);
++	len = di_prom_prop_lookup_ints(di_phdl, node, "reg", &retbuf);
++#endif
+ 
+     /* Exclude usb devices */
+     if (len < 5) {
+-    	return (DI_WALK_CONTINUE);
++    	return DI_WALK_CONTINUE;
+     }
+ 
+-    bdf_table[num_bdfs].bus = PCI_REG_BUS_G(regbuf[0]);
+-    bdf_table[num_bdfs].dev = PCI_REG_DEV_G(regbuf[0]);
+-    bdf_table[num_bdfs].func  = PCI_REG_FUNC_G(regbuf[0]);
++    pci_base = &pinfo->devices[pinfo->num_devices].base;
+ 
+-    if (++num_bdfs == num_allocated_bdfs) {
+-	bdf_table_info_t  *new_bdfs;
+-	size_t new_num_bdfs = num_allocated_bdfs * 2;
++    pci_base->domain = nexus->domain;
++    pci_base->bus = PCI_REG_BUS_G(retbuf[0]);
++    pci_base->dev = PCI_REG_DEV_G(retbuf[0]);
++    pci_base->func  = PCI_REG_FUNC_G(retbuf[0]);
+ 
+-	new_bdfs = realloc (bdf_table,
+-                   new_num_bdfs * sizeof (bdf_table_info_t));
+-	if (new_bdfs == NULL)
+-	    return (DI_WALK_TERMINATE);
+-
+-	(void) memset(&new_bdfs[num_bdfs], 0,
+-                   num_allocated_bdfs *
+-                   sizeof (bdf_table_info_t));
+-	num_allocated_bdfs = new_num_bdfs;
+-	bdf_table = new_bdfs;
+-    }
+-
+-    return (DI_WALK_CONTINUE);
+-}
+-#endif
+-
+-/*
+- * Probe device's functions.  Modifies many fields in the prg_p.
+- */
+-static int
+-probe_dev(nexus_t *nexus, pcitool_reg_t *prg_p, probe_info_t *pinfo)
+-{
+-    pci_conf_hdr_t	config_hdr;
+-    boolean_t		multi_function_device;
+-    int8_t		func;
+-    int8_t		first_func = 0;
+-    int8_t		last_func = PCI_REG_FUNC_M >> PCI_REG_FUNC_SHIFT;
+-    int			rval = 0;
+-    struct pci_device *	pci_base;
+-
+-    /*
+-     * Loop through at least func=first_func.  Continue looping through
+-     * functions if there are no errors and the device is a multi-function
+-     * device.
+-     *
+-     * (Note, if first_func == 0, header will show whether multifunction
+-     * device and set multi_function_device.  If first_func != 0, then we
+-     * will force the loop as the user wants a specific function to be
+-     * checked.
+-     */
+-
+-    for (func = first_func, multi_function_device = B_FALSE;
+-	 ((func <= last_func) &&
+-	  ((func == first_func) || (multi_function_device)));
+-	 func++) {
++    /* Get property values */
++    for (i = 0; i < NUM_PROPERTIES; i++) {
++	len = di_prop_lookup_ints(DDI_DEV_T_ANY, node, 
++		property_list[i].name, &retbuf);
+ #ifdef __sparc
+-	int i;
++	if ((len <= 0) && di_phdl)
++	    len = di_prom_prop_lookup_ints(di_phdl, node, 
++		property_list[i].name, &retbuf);
+ #endif
+ 
+-	prg_p->func_no = func;
+-
+-#ifdef __sparc
+-	/* Check validity of bdf */
+-	for (i = 0; i < num_bdfs; i++) {
+-	    if ((bdf_table[i].bus == prg_p->bus_no) && 
+-		(bdf_table[i].dev == prg_p->dev_no) &&
+-		(bdf_table[i].func == prg_p->func_no))
+-		break;
++	if (len > 0)
++	    property_list[i].value = retbuf[0];
++	else {
++	    /* a device must have property "class-code", "device-id", "vendor-id" */
++	    if (i < 3)
++		return DI_WALK_CONTINUE;
++#ifdef DEBUG
++	    fprintf(stderr, "cannot get property \"%s\" for nexus = %s :\n", 
++		property_list[i].name, nexus->path);
++	    fprintf(stderr, "	domain = %x, busno = %x, devno = %x, funcno = %x\n",
++		pci_base->domain, pci_base->bus, pci_base->dev, pci_base->func);
++#endif
+ 	}
++    }
+ 
+-	/* Skipping if bdf device not on devinfo tree */
+-	if (i == num_bdfs) {
+-	    continue;
+-	}
+-#endif
+-	    
+-	/*
+-	 * Four things can happen here:
+-	 *
+-	 * 1) ioctl comes back as EFAULT and prg_p->status is
+-	 *    PCITOOL_INVALID_ADDRESS.  There is no device at this location.
+-	 *
+-	 * 2) ioctl comes back successful and the data comes back as
+-	 *    zero.  Config space is mapped but no device responded.
+-	 *
+-	 * 3) ioctl comes back successful and the data comes back as
+-	 *    non-zero.  We've found a device.
+-	 *
+-	 * 4) Some other error occurs in an ioctl.
+-	 */
++    if ((property_list[1].value == 0) && (property_list[2].value == 0))
++	return DI_WALK_CONTINUE;
+ 
+-	prg_p->status = PCITOOL_SUCCESS;
+-	prg_p->offset = 0;
+-	prg_p->data = 0;
+-	prg_p->user_version = PCITOOL_USER_VERSION;
++    pci_base->device_class = property_list[0].value;
++    pci_base->device_id = property_list[1].value;
++    pci_base->vendor_id = property_list[2].value;
++    pci_base->revision = property_list[3].value;
++    pci_base->subvendor_id = property_list[4].value;
++    pci_base->subdevice_id = property_list[5].value;
+ 
+-	errno = 0;
+-	if (((rval = ioctl(nexus->fd, PCITOOL_DEVICE_GET_REG, prg_p)) != 0) ||
+-	    (prg_p->data == 0xffffffff)) {
+-
+-	    /*
+-	     * Accept errno == EINVAL along with status of
+-	     * PCITOOL_OUT_OF_RANGE because some systems
+-	     * don't implement the full range of config space.
+-	     * Leave the loop quietly in this case.
+-	     */
+-	    if ((errno == EINVAL) ||
+-		(prg_p->status == PCITOOL_OUT_OF_RANGE)) {
+-		break;
+-	    }
+-
+-	    /*
+-	     * Exit silently with ENXIO as this means that there are
+-	     * no devices under the pci root nexus.
+-	     */
+-	    else if ((errno == ENXIO) &&
+-		     (prg_p->status == PCITOOL_IO_ERROR)) {
+-		break;
+-	    }
+-
+-	    /*
+-	     * Expect errno == EFAULT along with status of
+-	     * PCITOOL_INVALID_ADDRESS because there won't be
+-	     * devices at each stop.  Quit on any other error.
+-	     */
+-	    else if (((errno != EFAULT) ||
+-		      (prg_p->status != PCITOOL_INVALID_ADDRESS)) &&
+-		     (prg_p->data != 0xffffffff)) {
+-#ifdef __sparc
+-/* on sparc, devices can be enumerated discontiguously. Do not quit */
+-		rval = 0;
+-#endif
+-		break;
+-	    }
+-
+-	    /*
+-	     * If no function at this location,
+-	     * just advance to the next function.
+-	     */
+-	    else {
+-		rval = 0;
+-	    }
+-
+-	    /*
+-	     * Data came back as 0.
+-	     * Treat as unresponsive device and check next device.
+-	     */
+-	} else if (prg_p->data == 0) {
+-	    rval = 0;
+-	    break;	/* Func loop. */
+-
+-	    /* Found something. */
+-	} else {
+-	    config_hdr.dwords[0] = (uint32_t)prg_p->data;
+-
+-	    /* Get the rest of the PCI header. */
+-	    if ((rval = get_config_header(nexus->fd, prg_p->bus_no,
+-					  prg_p->dev_no, prg_p->func_no,
+-					  &config_hdr)) != 0) {
+-		break;
+-	    }
+-
+-	    /*
+-	     * Special case for the type of Southbridge found on
+-	     * Ultra-45 and other sun4u fire workstations.
+-	     */
+-	    if ((config_hdr.dwords[0] == U45_SB_DEVID_VID) &&
+-		(config_hdr.dwords[2] == U45_SB_CLASS_RID)) {
+-		rval = ECANCELED;
+-		break;
+-	    }
+-
+-	    /*
+-	     * Found one device with bus number, device number and
+-	     * function number.
+-	     */
+-
+-	    pci_base = &pinfo->devices[pinfo->num_devices].base;
+-
+-	    pci_base->domain = nexus->domain;
+-	    pci_base->bus = prg_p->bus_no;
+-	    pci_base->dev = prg_p->dev_no;
+-	    pci_base->func = func;
+-
+-	    /*
+-	     * for the format of device_class, see struct pci_device;
+-	     */
+-
+-	    pci_base->device_class =
+-		(GET_CONFIG_VAL_8(PCI_CONF_BASCLASS) << 16) |
+-		(GET_CONFIG_VAL_8(PCI_CONF_SUBCLASS) << 8) |
+-		GET_CONFIG_VAL_8(PCI_CONF_PROGCLASS);
+-
+-	    pci_base->revision		= GET_CONFIG_VAL_8(PCI_CONF_REVID);
+-	    pci_base->vendor_id		= GET_CONFIG_VAL_16(PCI_CONF_VENID);
+-	    pci_base->device_id		= GET_CONFIG_VAL_16(PCI_CONF_DEVID);
+-	    pci_base->subvendor_id 	= GET_CONFIG_VAL_16(PCI_CONF_SUBVENID);
+-	    pci_base->subdevice_id 	= GET_CONFIG_VAL_16(PCI_CONF_SUBSYSID);
+-	    pci_base->irq		= GET_CONFIG_VAL_8(PCI_CONF_ILINE);
+-
+-	    pinfo->devices[pinfo->num_devices].header_type
+-					= GET_CONFIG_VAL_8(PCI_CONF_HEADER);
+-
+ #ifdef DEBUG
+-	    fprintf(stderr,
+-		    "nexus = %s, busno = %x, devno = %x, funcno = %x\n",
+-		    nexus->path, prg_p->bus_no, prg_p->dev_no, func);
++    fprintf(stderr,
++	    "nexus = %s, domain = %x, busno = %x, devno = %x, funcno = %x\n",
++	    nexus->path, pci_base->domain, pci_base->bus, pci_base->dev, pci_base->func);
+ #endif
+ 
+-	    pinfo->num_devices++;
+-	    if (pinfo->num_devices == pinfo->num_allocated_elems) {
+-		struct pci_device_private *new_devs;
+-		size_t new_num_elems = pinfo->num_allocated_elems * 2;
++    pinfo->num_devices++;
++    if (pinfo->num_devices == pinfo->num_allocated_elems) {
++	struct pci_device_private *new_devs;
++	size_t new_num_elems = pinfo->num_allocated_elems * 2;
+ 
+-		new_devs = realloc(pinfo->devices,
+-			new_num_elems * sizeof (struct pci_device_private));
+-		if (new_devs == NULL) {
+-		    (void) fprintf(stderr,
+-			           "Error allocating memory for PCI devices:"
+-				   " %s\n discarding additional devices\n",
+-				   strerror(errno));
+-		    return (rval);
+-		}
+-		(void) memset(&new_devs[pinfo->num_devices], 0,
+-			pinfo->num_allocated_elems *
+-			sizeof (struct pci_device_private));
+-		pinfo->num_allocated_elems = new_num_elems;
+-		pinfo->devices = new_devs;
+-	    }
+-
+-	    /*
+-	     * Accommodate devices which state their
+-	     * multi-functionality only in their function 0 config
+-	     * space.  Note multi-functionality throughout probing
+-	     * of all of this device's functions.
+-	     */
+-	    if (config_hdr.bytes[PCI_CONF_HEADER] & PCI_HEADER_MULTI) {
+-		multi_function_device = B_TRUE;
+-	    }
++	new_devs = realloc(pinfo->devices,
++	new_num_elems * sizeof (struct pci_device_private));
++	if (new_devs == NULL) {
++	    (void) fprintf(stderr,
++	           "Error allocating memory for PCI devices:"
++		   " %s\n discarding additional devices\n",
++		   strerror(errno));
++	    ((probe_args_t *)arg)->ret = 1;
++	    return (DI_WALK_TERMINATE);
+ 	}
++	(void) memset(&new_devs[pinfo->num_devices], 0,
++		pinfo->num_allocated_elems *
++		sizeof (struct pci_device_private));
++	pinfo->num_allocated_elems = new_num_elems;
++	pinfo->devices = new_devs;
+     }
+ 
+-    return (rval);
++    return (DI_WALK_CONTINUE);
+ }
+ 
+ 
+ /*
+- * Solaris version
+- * Probe a given nexus config space for devices.
+- *
+- * fd is the file descriptor of the nexus.
+- * input_args contains commandline options as specified by the user.
+- */
+-static int
+-do_probe(nexus_t *nexus, probe_info_t *pinfo)
+-{
+-    pcitool_reg_t prg;
+-    uint32_t bus;
+-    uint8_t dev;
+-    uint32_t last_bus = nexus->last_bus;
+-    uint8_t last_dev = PCI_REG_DEV_M >> PCI_REG_DEV_SHIFT;
+-    uint8_t first_bus = nexus->first_bus;
+-    uint8_t first_dev = 0;
+-    int rval = 0;
+-
+-    prg.barnum = 0;	/* Config space. */
+-
+-    /* Must read in 4-byte quantities. */
+-    prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + NATIVE_ENDIAN;
+-
+-    prg.data = 0;
+-
+-    /*
+-     * Loop through all valid bus / dev / func combinations to check for
+-     * all devices, with the following exceptions:
+-     *
+-     * When nothing is found at function 0 of a bus / dev combination, skip
+-     * the other functions of that bus / dev combination.
+-     *
+-     * When a found device's function 0 is probed and it is determined that
+-     * it is not a multifunction device, skip probing of that device's
+-     * other functions.
+-     */
+-    for (bus = first_bus; ((bus <= last_bus) && (rval == 0)); bus++) {
+-	prg.bus_no = (uint8_t)bus;
+-
+-	for (dev = first_dev; ((dev <= last_dev) && (rval == 0)); dev++) {
+-	    prg.dev_no = dev;
+-	    rval = probe_dev(nexus, &prg, pinfo);
+-	}
+-
+-	/*
+-	 * Ultra-45 southbridge workaround:
+-	 * ECANCELED tells to skip to the next bus.
+-	 */
+-	if (rval == ECANCELED) {
+-	    rval = 0;
+-	}
+-    }
+-
+-    return (rval);
+-}
+-
+-/*
+  * This function is called from di_walk_minor() when any PROBE is processed
+  */
+ static int
+@@ -579,11 +318,11 @@
+     int pci_node = 0;
+     int first_bus = 0, last_bus = PCI_REG_BUS_G(PCI_REG_BUS_M);
+     int domain = 0;
++    di_node_t rnode =  DI_NODE_NIL;
+ #ifdef __sparc
+     int bus_range_found = 0;
+     int device_type_found = 0;
+     di_prom_prop_t prom_prop;
+-    di_node_t rnode =  DI_NODE_NIL;
+ #endif
+ 
+ 
+@@ -590,6 +329,7 @@
+ #ifdef DEBUG
+     nexus_name = di_devfs_minor_path(minor);
+     fprintf(stderr, "-- device name: %s\n", nexus_name);
++    di_devfs_path_free(nexus_name);
+ #endif
+ 
+     for (prop = di_prop_next(di_node, NULL); prop != NULL;
+@@ -698,6 +438,8 @@
+ #endif
+ 
+     if ((fd = open(nexus_path, O_RDWR | O_CLOEXEC)) >= 0) {
++	probe_args_t args;
++
+ 	nexus->fd = fd;
+ 	nexus->path = strdup(nexus_path);
+ 	nexus_dev_path = di_devfs_path(di_node);
+@@ -704,44 +446,32 @@
+ 	nexus->dev_path = strdup(nexus_dev_path);
+ 	di_devfs_path_free(nexus_dev_path);
+ 
+-#ifdef __sparc
+ 	if ((rnode = di_init(nexus->dev_path, DINFOCPYALL)) == DI_NODE_NIL) {
+ 	    (void) fprintf(stderr, "di_init failed: %s\n", strerror(errno));
++	    close(nexus->fd);
++	    free(nexus->path);
++	    free(nexus->dev_path);
++	    free(nexus);
+ 	    return (DI_WALK_TERMINATE);
+ 	}
+ 
+-	if ((bdf_table = calloc(INITIAL_NUM_DEVICES,
+-			sizeof (bdf_table_info_t))) == NULL) {
+-	    di_fini(rnode);
+-	    return (DI_WALK_TERMINATE);
+-	}
+-	num_bdfs = 0;
+-	num_allocated_bdfs = INITIAL_NUM_DEVICES;
++	/* Walk through devices under the rnode */
++	args.pinfo = pinfo;
++	args.nexus = nexus; 
++	args.ret = 0;
+ 
+-	/* Create a bdf table for the nexus node */
+-	(void) di_walk_node(rnode, DI_WALK_CLDFIRST, (void *)NULL, create_bdf_table);
+-#endif 
+-
+-	if ((do_probe(nexus, pinfo) != 0) && (errno != ENXIO)) {
+-	    (void) fprintf(stderr, "Error probing node %s: %s\n",
+-			   nexus_path, strerror(errno));
+-	    (void) close(fd);
++	(void) di_walk_node(rnode, DI_WALK_CLDFIRST, (void *)&args, probe_device_node);
++	if (args.ret) {
++	    close(nexus->fd);
+ 	    free(nexus->path);
+ 	    free(nexus->dev_path);
+ 	    free(nexus);
+-	} else {
+-	    nexus->next = nexus_list;
+-	    nexus_list = nexus;
++	    di_fini(rnode);
++	    return (DI_WALK_TERMINATE);
+ 	}
+-#ifdef __sparc
+-	if (bdf_table) {
+-	    free (bdf_table);
+-	    bdf_table = NULL;
+-	    num_bdfs = 0;
+-	    num_allocated_bdfs = 0;
+-	}
+-	di_fini(rnode);
+-#endif
++
++	nexus->next = nexus_list;
++	nexus_list = nexus;
+     } else {
+ 	(void) fprintf(stderr, "Error opening %s: %s\n",
+ 		       nexus_path, strerror(errno));
+@@ -748,6 +478,10 @@
+ 	free(nexus);
+     }
+ 
++    if (rnode != DI_NODE_NIL) {
++	di_fini(rnode);
++    }
++
+     return DI_WALK_CONTINUE;
+ }
+ 
+@@ -832,6 +566,10 @@
+     if ( (nexus = find_nexus_for_bus(dev->domain, dev->bus)) == NULL )
+ 	return ENODEV;
+ 
++    pci_device_cfg_read_u8(dev, &priv->header_type, PCI_CONF_HEADER);
++
++    pci_device_cfg_read_u8(dev, (uint8_t *)&dev->irq, PCI_CONF_ILINE);
++       
+     /*
+      * starting to find if it is MEM/MEM64/IO
+      * using libdevinfo
+@@ -848,10 +586,10 @@
+     }
+ 
+     if (args.node != DI_NODE_NIL) {
++	int *prop;
+ #ifdef __sparc
+ 	di_minor_t minor;
+ #endif
+-	int *prop;
+ 
+ 	priv->is_primary = 0;
+