solx_devfs.c revision 86ea1d58
14f5e7dd7Smrg/*
24f5e7dd7Smrg * (C) Copyright IBM Corporation 2006
386ea1d58Smrg * Copyright (c) 2007, 2009, 2011, 2012, 2013 Oracle and/or its affiliates.
44f5e7dd7Smrg * All Rights Reserved.
54f5e7dd7Smrg *
64f5e7dd7Smrg * Permission is hereby granted, free of charge, to any person obtaining a
74f5e7dd7Smrg * copy of this software and associated documentation files (the "Software"),
84f5e7dd7Smrg * to deal in the Software without restriction, including without limitation
94f5e7dd7Smrg * on the rights to use, copy, modify, merge, publish, distribute, sub
104f5e7dd7Smrg * license, and/or sell copies of the Software, and to permit persons to whom
114f5e7dd7Smrg * the Software is furnished to do so, subject to the following conditions:
124f5e7dd7Smrg *
134f5e7dd7Smrg * The above copyright notice and this permission notice (including the next
144f5e7dd7Smrg * paragraph) shall be included in all copies or substantial portions of the
154f5e7dd7Smrg * Software.
164f5e7dd7Smrg *
174f5e7dd7Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
184f5e7dd7Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
194f5e7dd7Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
204f5e7dd7Smrg * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
214f5e7dd7Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
224f5e7dd7Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
234f5e7dd7Smrg * DEALINGS IN THE SOFTWARE.
244f5e7dd7Smrg */
254f5e7dd7Smrg/*
264f5e7dd7Smrg * Solaris devfs interfaces
274f5e7dd7Smrg */
284f5e7dd7Smrg
294f5e7dd7Smrg#include <stdlib.h>
304f5e7dd7Smrg#include <strings.h>
314f5e7dd7Smrg#include <stdio.h>
324f5e7dd7Smrg#include <unistd.h>
334f5e7dd7Smrg#include <sys/types.h>
344f5e7dd7Smrg#include <fcntl.h>
354f5e7dd7Smrg#include <sys/mman.h>
364f5e7dd7Smrg#include <errno.h>
374f5e7dd7Smrg#include <sys/pci.h>
384f5e7dd7Smrg#include <libdevinfo.h>
394f5e7dd7Smrg#include "pci_tools.h"
404f5e7dd7Smrg
4186ea1d58Smrg#ifdef __x86
4286ea1d58Smrg# include <sys/sysi86.h>
4386ea1d58Smrg# include <sys/psw.h>
4486ea1d58Smrg#endif
4586ea1d58Smrg
464f5e7dd7Smrg#include "pciaccess.h"
474f5e7dd7Smrg#include "pciaccess_private.h"
484f5e7dd7Smrg
494f5e7dd7Smrg/* #define DEBUG */
504f5e7dd7Smrg
51cad31331Smrg#define	INITIAL_NUM_DEVICES	256
524f5e7dd7Smrg#define	CELL_NUMS_1275	(sizeof(pci_regspec_t) / sizeof(uint_t))
534f5e7dd7Smrg
544f5e7dd7Smrgtypedef struct i_devnode {
554f5e7dd7Smrg    uint8_t bus;
564f5e7dd7Smrg    uint8_t dev;
574f5e7dd7Smrg    uint8_t func;
584f5e7dd7Smrg    di_node_t node;
594f5e7dd7Smrg} i_devnode_t;
604f5e7dd7Smrg
614f5e7dd7Smrgtypedef struct nexus {
624f5e7dd7Smrg    int fd;
634f5e7dd7Smrg    int first_bus;
644f5e7dd7Smrg    int last_bus;
65cad31331Smrg    int domain;
664f5e7dd7Smrg    char *path;			/* for errors/debugging; fd is all we need */
67cad31331Smrg    char *dev_path;
684f5e7dd7Smrg    struct nexus *next;
694f5e7dd7Smrg} nexus_t;
704f5e7dd7Smrg
71cad31331Smrgtypedef struct probe_info {
72cad31331Smrg    volatile size_t num_allocated_elems;
73cad31331Smrg    volatile size_t num_devices;
74cad31331Smrg    struct pci_device_private * volatile devices;
75cad31331Smrg} probe_info_t;
76cad31331Smrg
7786ea1d58Smrgtypedef struct probe_args {
7886ea1d58Smrg    probe_info_t *pinfo;
7986ea1d58Smrg    nexus_t *nexus;
8086ea1d58Smrg    int ret;
8186ea1d58Smrg} probe_args_t;
8286ea1d58Smrg
8386ea1d58Smrgtypedef struct property_info {
8486ea1d58Smrg    const char *name;
8586ea1d58Smrg    int value;
8686ea1d58Smrg} property_info_t;
8786ea1d58Smrg
884f5e7dd7Smrgstatic nexus_t *nexus_list = NULL;
89cad31331Smrg#if !defined(__sparc)
904f5e7dd7Smrgstatic int xsvc_fd = -1;
91cad31331Smrg#endif
92cad31331Smrg
93cad31331Smrg#ifdef __sparc
94cad31331Smrgstatic di_prom_handle_t di_phdl;
9586ea1d58Smrgstatic size_t  nexus_count = 0;
96cad31331Smrg#endif
974f5e7dd7Smrg
984f5e7dd7Smrg/*
994f5e7dd7Smrg * Read config space in native processor endianness.  Endian-neutral
1004f5e7dd7Smrg * processing can then take place.  On big endian machines, MSB and LSB
1014f5e7dd7Smrg * of little endian data end up switched if read as little endian.
1024f5e7dd7Smrg * They are in correct order if read as big endian.
1034f5e7dd7Smrg */
1044f5e7dd7Smrg#if defined(__sparc)
1054f5e7dd7Smrg# define NATIVE_ENDIAN	PCITOOL_ACC_ATTR_ENDN_BIG
1064f5e7dd7Smrg#elif defined(__x86)
1074f5e7dd7Smrg# define NATIVE_ENDIAN	PCITOOL_ACC_ATTR_ENDN_LTL
1084f5e7dd7Smrg#else
1094f5e7dd7Smrg# error "ISA is neither __sparc nor __x86"
1104f5e7dd7Smrg#endif
1114f5e7dd7Smrg
112cad31331Smrg#ifdef __sparc
113cad31331Smrg#define MAPPING_DEV_PATH(dev)	 (((struct pci_device_private *) dev)->device_string)
114cad31331Smrg#endif
115cad31331Smrg
1164f5e7dd7Smrgstatic nexus_t *
117cad31331Smrgfind_nexus_for_bus( int domain, int bus )
1184f5e7dd7Smrg{
1194f5e7dd7Smrg    nexus_t *nexus;
1204f5e7dd7Smrg
1214f5e7dd7Smrg    for (nexus = nexus_list ; nexus != NULL ; nexus = nexus->next) {
122cad31331Smrg	if ((domain == nexus->domain) &&
123cad31331Smrg	    (bus >= nexus->first_bus) && (bus <= nexus->last_bus)) {
1244f5e7dd7Smrg	    return nexus;
1254f5e7dd7Smrg	}
1264f5e7dd7Smrg    }
1274f5e7dd7Smrg    return NULL;
1284f5e7dd7Smrg}
1294f5e7dd7Smrg
1304f5e7dd7Smrg/*
1314f5e7dd7Smrg * Release all the resources
1324f5e7dd7Smrg * Solaris version
1334f5e7dd7Smrg */
1344f5e7dd7Smrgstatic void
1354f5e7dd7Smrgpci_system_solx_devfs_destroy( void )
1364f5e7dd7Smrg{
1374f5e7dd7Smrg    /*
1384f5e7dd7Smrg     * The memory allocated for pci_sys & devices in create routines
1394f5e7dd7Smrg     * will be freed in pci_system_cleanup.
1404f5e7dd7Smrg     * Need to free system-specific allocations here.
1414f5e7dd7Smrg     */
1424f5e7dd7Smrg    nexus_t *nexus, *next;
1434f5e7dd7Smrg
1444f5e7dd7Smrg    for (nexus = nexus_list ; nexus != NULL ; nexus = next) {
1454f5e7dd7Smrg	next = nexus->next;
1464f5e7dd7Smrg	close(nexus->fd);
1474f5e7dd7Smrg	free(nexus->path);
148cad31331Smrg	free(nexus->dev_path);
1494f5e7dd7Smrg	free(nexus);
1504f5e7dd7Smrg    }
1514f5e7dd7Smrg    nexus_list = NULL;
1524f5e7dd7Smrg
153cad31331Smrg#ifdef __sparc
154cad31331Smrg    if (di_phdl != DI_PROM_HANDLE_NIL)
155cad31331Smrg	(void) di_prom_fini(di_phdl);
156cad31331Smrg#else
1574f5e7dd7Smrg    if (xsvc_fd >= 0) {
1584f5e7dd7Smrg	close(xsvc_fd);
1594f5e7dd7Smrg	xsvc_fd = -1;
1604f5e7dd7Smrg    }
161cad31331Smrg#endif
1624f5e7dd7Smrg}
1634f5e7dd7Smrg
16486ea1d58Smrg
16586ea1d58Smrg#ifdef __sparc
1664f5e7dd7Smrg/*
16786ea1d58Smrg * Release resources per device
1684f5e7dd7Smrg */
16986ea1d58Smrgstatic void
17086ea1d58Smrgpci_system_solx_devfs_destroy_device( struct pci_device *dev )
1714f5e7dd7Smrg{
17286ea1d58Smrg   if (MAPPING_DEV_PATH(dev))
17386ea1d58Smrg	di_devfs_path_free((char *) MAPPING_DEV_PATH(dev));
1744f5e7dd7Smrg}
17586ea1d58Smrg#endif
1764f5e7dd7Smrg
1774f5e7dd7Smrg
1784f5e7dd7Smrgstatic int
17986ea1d58Smrgprobe_device_node(di_node_t node, void *arg)
1804f5e7dd7Smrg{
18186ea1d58Smrg    int *retbuf = NULL;
18286ea1d58Smrg    int len = 0, i;
18386ea1d58Smrg    struct pci_device	*pci_base;
18486ea1d58Smrg    probe_info_t *pinfo = ((probe_args_t *)arg)->pinfo;
18586ea1d58Smrg    nexus_t *nexus = ((probe_args_t *)arg)->nexus;
18686ea1d58Smrg    property_info_t property_list[] = {
18786ea1d58Smrg        { "class-code", 0 },
18886ea1d58Smrg        { "device-id", 0 },
18986ea1d58Smrg        { "vendor-id", 0 },
19086ea1d58Smrg        { "revision-id", 0},
19186ea1d58Smrg        { "subsystem-vendor-id", 0},
19286ea1d58Smrg        { "subsystem-id", 0},
19386ea1d58Smrg    };
19486ea1d58Smrg#define NUM_PROPERTIES		sizeof(property_list)/sizeof(property_info_t)
1954f5e7dd7Smrg
19686ea1d58Smrg    len = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", &retbuf);
1974f5e7dd7Smrg
198cad31331Smrg#ifdef __sparc
19986ea1d58Smrg    if ((len <= 0) && di_phdl)
20086ea1d58Smrg	len = di_prom_prop_lookup_ints(di_phdl, node, "reg", &retbuf);
201cad31331Smrg#endif
2024f5e7dd7Smrg
20386ea1d58Smrg    /* Exclude usb devices */
20486ea1d58Smrg    if (len < 5) {
20586ea1d58Smrg	return DI_WALK_CONTINUE;
20686ea1d58Smrg    }
2074f5e7dd7Smrg
20886ea1d58Smrg    pci_base = &pinfo->devices[pinfo->num_devices].base;
2094f5e7dd7Smrg
21086ea1d58Smrg    pci_base->domain = nexus->domain;
21186ea1d58Smrg    pci_base->bus = PCI_REG_BUS_G(retbuf[0]);
21286ea1d58Smrg    pci_base->dev = PCI_REG_DEV_G(retbuf[0]);
21386ea1d58Smrg    pci_base->func  = PCI_REG_FUNC_G(retbuf[0]);
2144f5e7dd7Smrg
21586ea1d58Smrg    /* Get property values */
21686ea1d58Smrg    for (i = 0; i < NUM_PROPERTIES; i++) {
21786ea1d58Smrg	len = di_prop_lookup_ints(DDI_DEV_T_ANY, node,
21886ea1d58Smrg		property_list[i].name, &retbuf);
219cad31331Smrg#ifdef __sparc
22086ea1d58Smrg	if ((len <= 0) && di_phdl)
22186ea1d58Smrg	    len = di_prom_prop_lookup_ints(di_phdl, node,
22286ea1d58Smrg		property_list[i].name, &retbuf);
223cad31331Smrg#endif
2244f5e7dd7Smrg
22586ea1d58Smrg	if (len > 0)
22686ea1d58Smrg	    property_list[i].value = retbuf[0];
22786ea1d58Smrg	else {
22886ea1d58Smrg	    /* a device must have property "class-code", "device-id", "vendor-id" */
22986ea1d58Smrg	    if (i < 3)
23086ea1d58Smrg		return DI_WALK_CONTINUE;
23186ea1d58Smrg#ifdef DEBUG
23286ea1d58Smrg	    fprintf(stderr, "cannot get property \"%s\" for nexus = %s :\n",
23386ea1d58Smrg		property_list[i].name, nexus->path);
23486ea1d58Smrg	    fprintf(stderr, "	domain = %x, busno = %x, devno = %x, funcno = %x\n",
23586ea1d58Smrg		pci_base->domain, pci_base->bus, pci_base->dev, pci_base->func);
23686ea1d58Smrg#endif
2374f5e7dd7Smrg	}
2384f5e7dd7Smrg    }
2394f5e7dd7Smrg
24086ea1d58Smrg    if ((property_list[1].value == 0) && (property_list[2].value == 0))
24186ea1d58Smrg	return DI_WALK_CONTINUE;
242cad31331Smrg
24386ea1d58Smrg    pci_base->device_class = property_list[0].value;
24486ea1d58Smrg    pci_base->device_id = property_list[1].value;
24586ea1d58Smrg    pci_base->vendor_id = property_list[2].value;
24686ea1d58Smrg    pci_base->revision = property_list[3].value;
24786ea1d58Smrg    pci_base->subvendor_id = property_list[4].value;
24886ea1d58Smrg    pci_base->subdevice_id = property_list[5].value;
249cad31331Smrg
25086ea1d58Smrg#ifdef DEBUG
25186ea1d58Smrg    fprintf(stderr,
25286ea1d58Smrg	    "nexus = %s, domain = %x, busno = %x, devno = %x, funcno = %x\n",
25386ea1d58Smrg	    nexus->path, pci_base->domain, pci_base->bus, pci_base->dev, pci_base->func);
25486ea1d58Smrg#endif
255cad31331Smrg
25686ea1d58Smrg    pinfo->num_devices++;
25786ea1d58Smrg    if (pinfo->num_devices == pinfo->num_allocated_elems) {
25886ea1d58Smrg	struct pci_device_private *new_devs;
25986ea1d58Smrg	size_t new_num_elems = pinfo->num_allocated_elems * 2;
26086ea1d58Smrg
26186ea1d58Smrg	new_devs = realloc(pinfo->devices,
26286ea1d58Smrg	new_num_elems * sizeof (struct pci_device_private));
26386ea1d58Smrg	if (new_devs == NULL) {
26486ea1d58Smrg	    (void) fprintf(stderr,
26586ea1d58Smrg	           "Error allocating memory for PCI devices:"
26686ea1d58Smrg		   " %s\n discarding additional devices\n",
26786ea1d58Smrg		   strerror(errno));
26886ea1d58Smrg	    ((probe_args_t *)arg)->ret = 1;
26986ea1d58Smrg	    return (DI_WALK_TERMINATE);
270cad31331Smrg	}
27186ea1d58Smrg	(void) memset(&new_devs[pinfo->num_devices], 0,
27286ea1d58Smrg		pinfo->num_allocated_elems *
27386ea1d58Smrg		sizeof (struct pci_device_private));
27486ea1d58Smrg	pinfo->num_allocated_elems = new_num_elems;
27586ea1d58Smrg	pinfo->devices = new_devs;
276cad31331Smrg    }
277cad31331Smrg
27886ea1d58Smrg    return (DI_WALK_CONTINUE);
279cad31331Smrg}
2804f5e7dd7Smrg/*
2814f5e7dd7Smrg * This function is called from di_walk_minor() when any PROBE is processed
2824f5e7dd7Smrg */
2834f5e7dd7Smrgstatic int
2844f5e7dd7Smrgprobe_nexus_node(di_node_t di_node, di_minor_t minor, void *arg)
2854f5e7dd7Smrg{
286cad31331Smrg    probe_info_t *pinfo = (probe_info_t *)arg;
287cad31331Smrg    char *nexus_name, *nexus_dev_path;
2884f5e7dd7Smrg    nexus_t *nexus;
2894f5e7dd7Smrg    int fd;
2904f5e7dd7Smrg    char nexus_path[MAXPATHLEN];
2914f5e7dd7Smrg
2924f5e7dd7Smrg    di_prop_t prop;
2934f5e7dd7Smrg    char *strings;
2944f5e7dd7Smrg    int *ints;
2954f5e7dd7Smrg    int numval;
2964f5e7dd7Smrg    int pci_node = 0;
2974f5e7dd7Smrg    int first_bus = 0, last_bus = PCI_REG_BUS_G(PCI_REG_BUS_M);
298cad31331Smrg    int domain = 0;
29986ea1d58Smrg    di_node_t rnode =  DI_NODE_NIL;
300cad31331Smrg#ifdef __sparc
301cad31331Smrg    int bus_range_found = 0;
302cad31331Smrg    int device_type_found = 0;
303cad31331Smrg    di_prom_prop_t prom_prop;
304cad31331Smrg#endif
305cad31331Smrg
3064f5e7dd7Smrg
3074f5e7dd7Smrg#ifdef DEBUG
3084f5e7dd7Smrg    nexus_name = di_devfs_minor_path(minor);
3094f5e7dd7Smrg    fprintf(stderr, "-- device name: %s\n", nexus_name);
31086ea1d58Smrg    di_devfs_path_free(nexus_name);
3114f5e7dd7Smrg#endif
3124f5e7dd7Smrg
3134f5e7dd7Smrg    for (prop = di_prop_next(di_node, NULL); prop != NULL;
3144f5e7dd7Smrg	 prop = di_prop_next(di_node, prop)) {
3154f5e7dd7Smrg
3164f5e7dd7Smrg	const char *prop_name = di_prop_name(prop);
3174f5e7dd7Smrg
3184f5e7dd7Smrg#ifdef DEBUG
3194f5e7dd7Smrg	fprintf(stderr, "   property: %s\n", prop_name);
3204f5e7dd7Smrg#endif
3214f5e7dd7Smrg
3224f5e7dd7Smrg	if (strcmp(prop_name, "device_type") == 0) {
3234f5e7dd7Smrg	    numval = di_prop_strings(prop, &strings);
324cad31331Smrg	    if (numval == 1) {
325cad31331Smrg		if (strncmp(strings, "pci", 3) != 0)
326cad31331Smrg		    /* not a PCI node, bail */
327cad31331Smrg		    return (DI_WALK_CONTINUE);
328cad31331Smrg		else {
329cad31331Smrg		    pci_node = 1;
330cad31331Smrg#ifdef __sparc
331cad31331Smrg		    device_type_found =  1;
332cad31331Smrg#endif
333cad31331Smrg		}
3344f5e7dd7Smrg	    }
3354f5e7dd7Smrg	}
3364f5e7dd7Smrg	else if (strcmp(prop_name, "class-code") == 0) {
3374f5e7dd7Smrg	    /* not a root bus node, bail */
3384f5e7dd7Smrg	    return (DI_WALK_CONTINUE);
3394f5e7dd7Smrg	}
3404f5e7dd7Smrg	else if (strcmp(prop_name, "bus-range") == 0) {
3414f5e7dd7Smrg	    numval = di_prop_ints(prop, &ints);
3424f5e7dd7Smrg	    if (numval == 2) {
3434f5e7dd7Smrg		first_bus = ints[0];
3444f5e7dd7Smrg		last_bus = ints[1];
345cad31331Smrg#ifdef __sparc
346cad31331Smrg		bus_range_found = 1;
347cad31331Smrg#endif
348cad31331Smrg	    }
349cad31331Smrg	}
35086ea1d58Smrg#ifdef __sparc
35186ea1d58Smrg	domain = nexus_count;
35286ea1d58Smrg#else
353cad31331Smrg	else if (strcmp(prop_name, "pciseg") == 0) {
354cad31331Smrg	    numval = di_prop_ints(prop, &ints);
355cad31331Smrg	    if (numval == 1) {
356cad31331Smrg		domain = ints[0];
3574f5e7dd7Smrg	    }
3584f5e7dd7Smrg	}
35986ea1d58Smrg#endif
3604f5e7dd7Smrg    }
3614f5e7dd7Smrg
362cad31331Smrg#ifdef __sparc
363cad31331Smrg    if ((!device_type_found) && di_phdl) {
364cad31331Smrg	numval = di_prom_prop_lookup_strings(di_phdl, di_node,
365cad31331Smrg	    "device_type", &strings);
366cad31331Smrg	if (numval == 1) {
367cad31331Smrg	    if (strncmp(strings, "pci", 3) != 0)
368cad31331Smrg		return (DI_WALK_CONTINUE);
369cad31331Smrg	    else
370cad31331Smrg		pci_node = 1;
371cad31331Smrg	}
372cad31331Smrg    }
373cad31331Smrg
374cad31331Smrg    if ((!bus_range_found) && di_phdl) {
375cad31331Smrg	numval = di_prom_prop_lookup_ints(di_phdl, di_node,
376cad31331Smrg	    "bus-range", &ints);
377cad31331Smrg	if (numval == 2) {
378cad31331Smrg	    first_bus = ints[0];
379cad31331Smrg	    last_bus = ints[1];
380cad31331Smrg	}
381cad31331Smrg    }
382cad31331Smrg#endif
383cad31331Smrg
3844f5e7dd7Smrg    if (pci_node != 1)
3854f5e7dd7Smrg	return (DI_WALK_CONTINUE);
3864f5e7dd7Smrg
3874f5e7dd7Smrg    /* we have a PCI root bus node. */
3884f5e7dd7Smrg    nexus = calloc(1, sizeof(nexus_t));
3894f5e7dd7Smrg    if (nexus == NULL) {
3904f5e7dd7Smrg	(void) fprintf(stderr, "Error allocating memory for nexus: %s\n",
3914f5e7dd7Smrg		       strerror(errno));
3924f5e7dd7Smrg	return (DI_WALK_TERMINATE);
3934f5e7dd7Smrg    }
3944f5e7dd7Smrg    nexus->first_bus = first_bus;
3954f5e7dd7Smrg    nexus->last_bus = last_bus;
396cad31331Smrg    nexus->domain = domain;
397cad31331Smrg
398cad31331Smrg#ifdef __sparc
39986ea1d58Smrg    nexus_count++;
400cad31331Smrg#endif
4014f5e7dd7Smrg
4024f5e7dd7Smrg    nexus_name = di_devfs_minor_path(minor);
4034f5e7dd7Smrg    if (nexus_name == NULL) {
4044f5e7dd7Smrg	(void) fprintf(stderr, "Error getting nexus path: %s\n",
4054f5e7dd7Smrg		       strerror(errno));
4064f5e7dd7Smrg	free(nexus);
4074f5e7dd7Smrg	return (DI_WALK_CONTINUE);
4084f5e7dd7Smrg    }
4094f5e7dd7Smrg
4104f5e7dd7Smrg    snprintf(nexus_path, sizeof(nexus_path), "/devices%s", nexus_name);
4114f5e7dd7Smrg    di_devfs_path_free(nexus_name);
4124f5e7dd7Smrg
4134f5e7dd7Smrg#ifdef DEBUG
4144f5e7dd7Smrg    fprintf(stderr, "nexus = %s, bus-range = %d - %d\n",
4154f5e7dd7Smrg	    nexus_path, first_bus, last_bus);
4164f5e7dd7Smrg#endif
4174f5e7dd7Smrg
418cad31331Smrg    if ((fd = open(nexus_path, O_RDWR | O_CLOEXEC)) >= 0) {
41986ea1d58Smrg	probe_args_t args;
42086ea1d58Smrg
4214f5e7dd7Smrg	nexus->fd = fd;
4224f5e7dd7Smrg	nexus->path = strdup(nexus_path);
423cad31331Smrg	nexus_dev_path = di_devfs_path(di_node);
424cad31331Smrg	nexus->dev_path = strdup(nexus_dev_path);
425cad31331Smrg	di_devfs_path_free(nexus_dev_path);
42686ea1d58Smrg
42786ea1d58Smrg	if ((rnode = di_init(nexus->dev_path, DINFOCPYALL)) == DI_NODE_NIL) {
42886ea1d58Smrg	    (void) fprintf(stderr, "di_init failed: %s\n", strerror(errno));
42986ea1d58Smrg	    close(nexus->fd);
4304f5e7dd7Smrg	    free(nexus->path);
431cad31331Smrg	    free(nexus->dev_path);
4324f5e7dd7Smrg	    free(nexus);
43386ea1d58Smrg	    return (DI_WALK_TERMINATE);
4344f5e7dd7Smrg	}
43586ea1d58Smrg
43686ea1d58Smrg	/* Walk through devices under the rnode */
43786ea1d58Smrg	args.pinfo = pinfo;
43886ea1d58Smrg	args.nexus = nexus;
43986ea1d58Smrg	args.ret = 0;
44086ea1d58Smrg
44186ea1d58Smrg	(void) di_walk_node(rnode, DI_WALK_CLDFIRST, (void *)&args, probe_device_node);
44286ea1d58Smrg	if (args.ret) {
44386ea1d58Smrg	    close(nexus->fd);
44486ea1d58Smrg	    free(nexus->path);
44586ea1d58Smrg	    free(nexus->dev_path);
44686ea1d58Smrg	    free(nexus);
44786ea1d58Smrg	    di_fini(rnode);
44886ea1d58Smrg	    return (DI_WALK_TERMINATE);
44986ea1d58Smrg	}
45086ea1d58Smrg
45186ea1d58Smrg	nexus->next = nexus_list;
45286ea1d58Smrg	nexus_list = nexus;
4534f5e7dd7Smrg    } else {
4544f5e7dd7Smrg	(void) fprintf(stderr, "Error opening %s: %s\n",
4554f5e7dd7Smrg		       nexus_path, strerror(errno));
4564f5e7dd7Smrg	free(nexus);
4574f5e7dd7Smrg    }
4584f5e7dd7Smrg
45986ea1d58Smrg    if (rnode != DI_NODE_NIL) {
46086ea1d58Smrg	di_fini(rnode);
46186ea1d58Smrg    }
46286ea1d58Smrg
4634f5e7dd7Smrg    return DI_WALK_CONTINUE;
4644f5e7dd7Smrg}
4654f5e7dd7Smrg
4664f5e7dd7Smrgstatic int
4674f5e7dd7Smrgfind_target_node(di_node_t node, void *arg)
4684f5e7dd7Smrg{
4694f5e7dd7Smrg    int *regbuf = NULL;
4704f5e7dd7Smrg    int len = 0;
4714f5e7dd7Smrg    uint32_t busno, funcno, devno;
4724f5e7dd7Smrg    i_devnode_t *devnode = (i_devnode_t *)arg;
4734f5e7dd7Smrg
4744f5e7dd7Smrg    /*
4754f5e7dd7Smrg     * Test the property functions, only for testing
4764f5e7dd7Smrg     */
4774f5e7dd7Smrg    /*
4784f5e7dd7Smrg    void *prop = DI_PROP_NIL;
4794f5e7dd7Smrg
4804f5e7dd7Smrg    (void) fprintf(stderr, "start of node 0x%x\n", node->nodeid);
4814f5e7dd7Smrg    while ((prop = di_prop_hw_next(node, prop)) != DI_PROP_NIL) {
4824f5e7dd7Smrg	int i;
4834f5e7dd7Smrg	(void) fprintf(stderr, "name=%s: ", di_prop_name(prop));
4844f5e7dd7Smrg	len = 0;
4854f5e7dd7Smrg	if (!strcmp(di_prop_name(prop), "reg")) {
4864f5e7dd7Smrg	    len = di_prop_ints(prop, &regbuf);
4874f5e7dd7Smrg	}
4884f5e7dd7Smrg	for (i = 0; i < len; i++) {
4894f5e7dd7Smrg	    fprintf(stderr, "0x%0x.", regbuf[i]);
4904f5e7dd7Smrg	}
4914f5e7dd7Smrg	fprintf(stderr, "\n");
4924f5e7dd7Smrg    }
4934f5e7dd7Smrg    (void) fprintf(stderr, "end of node 0x%x\n", node->nodeid);
4944f5e7dd7Smrg    */
4954f5e7dd7Smrg
4964f5e7dd7Smrg    len = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", &regbuf);
4974f5e7dd7Smrg
498cad31331Smrg#ifdef __sparc
499cad31331Smrg    if ((len <= 0) && di_phdl)
500cad31331Smrg	len = di_prom_prop_lookup_ints(di_phdl, node, "reg", &regbuf);
501cad31331Smrg#endif
502cad31331Smrg
5034f5e7dd7Smrg    if (len <= 0) {
5044f5e7dd7Smrg#ifdef DEBUG
5054f5e7dd7Smrg	fprintf(stderr, "error = %x\n", errno);
5064f5e7dd7Smrg	fprintf(stderr, "can not find assigned-address\n");
5074f5e7dd7Smrg#endif
5084f5e7dd7Smrg	return (DI_WALK_CONTINUE);
5094f5e7dd7Smrg    }
5104f5e7dd7Smrg
5114f5e7dd7Smrg    busno = PCI_REG_BUS_G(regbuf[0]);
5124f5e7dd7Smrg    devno = PCI_REG_DEV_G(regbuf[0]);
5134f5e7dd7Smrg    funcno = PCI_REG_FUNC_G(regbuf[0]);
5144f5e7dd7Smrg
5154f5e7dd7Smrg    if ((busno == devnode->bus) &&
5164f5e7dd7Smrg	(devno == devnode->dev) &&
5174f5e7dd7Smrg	(funcno == devnode->func)) {
5184f5e7dd7Smrg	devnode->node = node;
5194f5e7dd7Smrg
5204f5e7dd7Smrg	return (DI_WALK_TERMINATE);
5214f5e7dd7Smrg    }
5224f5e7dd7Smrg
5234f5e7dd7Smrg    return (DI_WALK_CONTINUE);
5244f5e7dd7Smrg}
5254f5e7dd7Smrg
5264f5e7dd7Smrg/*
5274f5e7dd7Smrg * Solaris version
5284f5e7dd7Smrg */
5294f5e7dd7Smrgstatic int
5304f5e7dd7Smrgpci_device_solx_devfs_probe( struct pci_device * dev )
5314f5e7dd7Smrg{
532cad31331Smrg    int err = 0;
5334f5e7dd7Smrg    di_node_t rnode = DI_NODE_NIL;
5344f5e7dd7Smrg    i_devnode_t args = { 0, 0, 0, DI_NODE_NIL };
5354f5e7dd7Smrg    int *regbuf;
5364f5e7dd7Smrg    pci_regspec_t *reg;
5374f5e7dd7Smrg    int i;
5384f5e7dd7Smrg    int len = 0;
5394f5e7dd7Smrg    uint ent = 0;
54086ea1d58Smrg    struct pci_device_private *priv =
54186ea1d58Smrg	(struct pci_device_private *) dev;
542cad31331Smrg    nexus_t *nexus;
5434f5e7dd7Smrg
544cad31331Smrg    if ( (nexus = find_nexus_for_bus(dev->domain, dev->bus)) == NULL )
545cad31331Smrg	return ENODEV;
5464f5e7dd7Smrg
54786ea1d58Smrg    pci_device_cfg_read_u8(dev, &priv->header_type, PCI_CONF_HEADER);
54886ea1d58Smrg
54986ea1d58Smrg    pci_device_cfg_read_u8(dev, (uint8_t *)&dev->irq, PCI_CONF_ILINE);
55086ea1d58Smrg
551cad31331Smrg    /*
552cad31331Smrg     * starting to find if it is MEM/MEM64/IO
553cad31331Smrg     * using libdevinfo
554cad31331Smrg     */
555cad31331Smrg    if ((rnode = di_init(nexus->dev_path, DINFOCPYALL)) == DI_NODE_NIL) {
556cad31331Smrg	err = errno;
557cad31331Smrg	(void) fprintf(stderr, "di_init failed: %s\n", strerror(errno));
558cad31331Smrg    } else {
559cad31331Smrg	args.bus = dev->bus;
560cad31331Smrg	args.dev = dev->dev;
561cad31331Smrg	args.func = dev->func;
562cad31331Smrg	(void) di_walk_node(rnode, DI_WALK_CLDFIRST,
563cad31331Smrg		(void *)&args, find_target_node);
564cad31331Smrg    }
5654f5e7dd7Smrg
566cad31331Smrg    if (args.node != DI_NODE_NIL) {
56786ea1d58Smrg	int *prop;
568cad31331Smrg#ifdef __sparc
569cad31331Smrg	di_minor_t minor;
570cad31331Smrg#endif
5714f5e7dd7Smrg
57286ea1d58Smrg	priv->is_primary = 0;
57386ea1d58Smrg
574cad31331Smrg#ifdef __sparc
575cad31331Smrg	if (minor = di_minor_next(args.node, DI_MINOR_NIL))
576cad31331Smrg	    MAPPING_DEV_PATH(dev) = di_devfs_minor_path (minor);
577cad31331Smrg	else
578cad31331Smrg	    MAPPING_DEV_PATH(dev) = NULL;
579cad31331Smrg#endif
5804f5e7dd7Smrg
58186ea1d58Smrg	if (di_prop_lookup_ints(DDI_DEV_T_ANY, args.node,
58286ea1d58Smrg				"primary-controller", &prop) >= 1) {
58386ea1d58Smrg	    if (prop[0])
58486ea1d58Smrg		priv->is_primary = 1;
58586ea1d58Smrg	}
58686ea1d58Smrg
5874f5e7dd7Smrg	/*
5884f5e7dd7Smrg	 * It will succeed for sure, because it was
5894f5e7dd7Smrg	 * successfully called in find_target_node
5904f5e7dd7Smrg	 */
5914f5e7dd7Smrg	len = di_prop_lookup_ints(DDI_DEV_T_ANY, args.node,
5924f5e7dd7Smrg				  "assigned-addresses",
5934f5e7dd7Smrg				  &regbuf);
5944f5e7dd7Smrg
595cad31331Smrg#ifdef __sparc
596cad31331Smrg	if ((len <= 0) && di_phdl) {
597cad31331Smrg	    len = di_prom_prop_lookup_ints(di_phdl, args.node,
598cad31331Smrg				"assigned-addresses", &regbuf);
599cad31331Smrg	}
600cad31331Smrg#endif
6014f5e7dd7Smrg    }
6024f5e7dd7Smrg
6034f5e7dd7Smrg    if (len <= 0)
6044f5e7dd7Smrg	goto cleanup;
6054f5e7dd7Smrg
6064f5e7dd7Smrg    /*
60786ea1d58Smrg     * Each BAR address get its own region slot in sequence.
60886ea1d58Smrg     * 32 bit BAR:
60986ea1d58Smrg     * BAR 0x10 -> slot0, BAR 0x14 -> slot1...
61086ea1d58Smrg     * 64 bit BAR:
61186ea1d58Smrg     * BAR 0x10 -> slot0, BAR 0x18 -> slot2...,
61286ea1d58Smrg     * slot1 is part of BAR 0x10
6134f5e7dd7Smrg     * Linux give two region slot for 64 bit address.
6144f5e7dd7Smrg     */
61586ea1d58Smrg    for (i = 0; i < len; i = i + (int)CELL_NUMS_1275) {
6164f5e7dd7Smrg
6174f5e7dd7Smrg	reg = (pci_regspec_t *)&regbuf[i];
6184f5e7dd7Smrg	ent = reg->pci_phys_hi & 0xff;
61986ea1d58Smrg
62086ea1d58Smrg	if (ent > PCI_CONF_ROM) {
6214f5e7dd7Smrg	    fprintf(stderr, "error ent = %d\n", ent);
6224f5e7dd7Smrg	    break;
6234f5e7dd7Smrg	}
6244f5e7dd7Smrg	/*
62586ea1d58Smrg	 * G35 broken in BAR0
6264f5e7dd7Smrg	 */
62786ea1d58Smrg	if (ent < PCI_CONF_BASE0) {
62886ea1d58Smrg	    /*
62986ea1d58Smrg	     * VGA resource here and ignore it
63086ea1d58Smrg	     */
6314f5e7dd7Smrg	    break;
63286ea1d58Smrg	} else if (ent == PCI_CONF_ROM) {
63386ea1d58Smrg	    priv->rom_base = reg->pci_phys_low |
63486ea1d58Smrg		((uint64_t)reg->pci_phys_mid << 32);
63586ea1d58Smrg	    dev->rom_size = reg->pci_size_low;
63686ea1d58Smrg	} else {
63786ea1d58Smrg	    ent = (ent - PCI_CONF_BASE0) >> 2;
63886ea1d58Smrg	    /*
63986ea1d58Smrg	     * non relocatable resource is excluded
64086ea1d58Smrg	     * such like 0xa0000, 0x3b0. If it is met,
64186ea1d58Smrg	     * the loop is broken;
64286ea1d58Smrg	     */
64386ea1d58Smrg	    if (!PCI_REG_REG_G(reg->pci_phys_hi))
64486ea1d58Smrg		break;
6454f5e7dd7Smrg
64686ea1d58Smrg	    if (reg->pci_phys_hi & PCI_PREFETCH_B) {
64786ea1d58Smrg		dev->regions[ent].is_prefetchable = 1;
64886ea1d58Smrg	    }
6494f5e7dd7Smrg
6504f5e7dd7Smrg
65186ea1d58Smrg	    dev->regions[ent].base_addr = reg->pci_phys_low |
65286ea1d58Smrg		((uint64_t)reg->pci_phys_mid << 32);
65386ea1d58Smrg	    dev->regions[ent].size = reg->pci_size_low |
65486ea1d58Smrg		((uint64_t)reg->pci_size_hi << 32);
65586ea1d58Smrg
65686ea1d58Smrg	    switch (reg->pci_phys_hi & PCI_REG_ADDR_M) {
65786ea1d58Smrg		case PCI_ADDR_IO:
65886ea1d58Smrg		    dev->regions[ent].is_IO = 1;
65986ea1d58Smrg		    break;
66086ea1d58Smrg		case PCI_ADDR_MEM32:
66186ea1d58Smrg		    break;
66286ea1d58Smrg		case PCI_ADDR_MEM64:
66386ea1d58Smrg		    dev->regions[ent].is_64 = 1;
66486ea1d58Smrg		    /*
66586ea1d58Smrg		     * Skip one slot for 64 bit address
66686ea1d58Smrg		     */
66786ea1d58Smrg		    break;
66886ea1d58Smrg	    }
6694f5e7dd7Smrg	}
6704f5e7dd7Smrg    }
6714f5e7dd7Smrg
6724f5e7dd7Smrg  cleanup:
6734f5e7dd7Smrg    if (rnode != DI_NODE_NIL) {
6744f5e7dd7Smrg	di_fini(rnode);
6754f5e7dd7Smrg    }
6764f5e7dd7Smrg    return (err);
6774f5e7dd7Smrg}
6784f5e7dd7Smrg
679cad31331Smrg/**
68086ea1d58Smrg * Map a memory region for a device using /dev/xsvc (x86) or fb device (sparc)
681cad31331Smrg *
682cad31331Smrg * \param dev   Device whose memory region is to be mapped.
683cad31331Smrg * \param map   Parameters of the mapping that is to be created.
684cad31331Smrg *
685cad31331Smrg * \return
686cad31331Smrg * Zero on success or an \c errno value on failure.
687cad31331Smrg */
688cad31331Smrgstatic int
689cad31331Smrgpci_device_solx_devfs_map_range(struct pci_device *dev,
690cad31331Smrg				struct pci_device_mapping *map)
691cad31331Smrg{
692cad31331Smrg    const int prot = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0)
693cad31331Smrg			? (PROT_READ | PROT_WRITE) : PROT_READ;
694cad31331Smrg    int err = 0;
695cad31331Smrg
69686ea1d58Smrg    const char *map_dev;
697cad31331Smrg    int		map_fd;
698cad31331Smrg
69986ea1d58Smrg#ifdef __sparc
70086ea1d58Smrg    char	map_dev_buf[128];
701cad31331Smrg
70286ea1d58Smrg    if (MAPPING_DEV_PATH(dev)) {
70386ea1d58Smrg	snprintf(map_dev_buf, sizeof (map_dev_buf), "%s%s",
70486ea1d58Smrg		 "/devices", MAPPING_DEV_PATH(dev));
70586ea1d58Smrg	map_dev = map_dev_buf;
706cad31331Smrg    }
70786ea1d58Smrg    else
70886ea1d58Smrg	map_dev = "/dev/fb0";
709cad31331Smrg
71086ea1d58Smrg    map_fd = -1;
711cad31331Smrg#else
712cad31331Smrg    /*
71386ea1d58Smrg     * Still uses xsvc to do the user space mapping on x86/x64,
71486ea1d58Smrg     * caches open fd across multiple calls.
715cad31331Smrg     */
71686ea1d58Smrg    map_dev = "/dev/xsvc";
71786ea1d58Smrg    map_fd = xsvc_fd;
71886ea1d58Smrg#endif
71986ea1d58Smrg
72086ea1d58Smrg    if (map_fd < 0) {
72186ea1d58Smrg	if ((map_fd = open(map_dev, O_RDWR | O_CLOEXEC)) < 0) {
722cad31331Smrg	    err = errno;
72386ea1d58Smrg	    (void) fprintf(stderr, "can not open %s: %s\n", map_dev,
724cad31331Smrg			   strerror(errno));
725cad31331Smrg	    return err;
726cad31331Smrg	}
727cad31331Smrg    }
728cad31331Smrg
72986ea1d58Smrg    map->memory = mmap(NULL, map->size, prot, MAP_SHARED, map_fd, map->base);
730cad31331Smrg    if (map->memory == MAP_FAILED) {
731cad31331Smrg	err = errno;
732cad31331Smrg
733cad31331Smrg	(void) fprintf(stderr, "map rom region =%llx failed: %s\n",
73486ea1d58Smrg		       (unsigned long long) map->base, strerror(errno));
735cad31331Smrg    }
736cad31331Smrg
737cad31331Smrg#ifdef __sparc
738cad31331Smrg    close (map_fd);
739cad31331Smrg#endif
740cad31331Smrg
741cad31331Smrg    return err;
742cad31331Smrg}
743cad31331Smrg
7444f5e7dd7Smrg/*
7454f5e7dd7Smrg * Solaris version: read the VGA ROM data
7464f5e7dd7Smrg */
7474f5e7dd7Smrgstatic int
7484f5e7dd7Smrgpci_device_solx_devfs_read_rom( struct pci_device * dev, void * buffer )
7494f5e7dd7Smrg{
7504f5e7dd7Smrg    int err;
7514f5e7dd7Smrg    struct pci_device_mapping prom = {
7524f5e7dd7Smrg	.base = 0xC0000,
75386ea1d58Smrg	.size = 0x10000,
7544f5e7dd7Smrg	.flags = 0
7554f5e7dd7Smrg    };
75686ea1d58Smrg    struct pci_device_private *priv =
75786ea1d58Smrg	(struct pci_device_private *) dev;
75886ea1d58Smrg
75986ea1d58Smrg    if (priv->rom_base) {
76086ea1d58Smrg	prom.base = priv->rom_base;
76186ea1d58Smrg	prom.size = dev->rom_size;
76286ea1d58Smrg    }
7634f5e7dd7Smrg
7644f5e7dd7Smrg    err = pci_device_solx_devfs_map_range(dev, &prom);
7654f5e7dd7Smrg    if (err == 0) {
7664f5e7dd7Smrg	(void) bcopy(prom.memory, buffer, dev->rom_size);
7674f5e7dd7Smrg
76886ea1d58Smrg	if (munmap(prom.memory, prom.size) == -1) {
7694f5e7dd7Smrg	    err = errno;
7704f5e7dd7Smrg	}
7714f5e7dd7Smrg    }
7724f5e7dd7Smrg    return err;
7734f5e7dd7Smrg}
7744f5e7dd7Smrg
7754f5e7dd7Smrg/*
7764f5e7dd7Smrg * solaris version: Read the configurations space of the devices
7774f5e7dd7Smrg */
7784f5e7dd7Smrgstatic int
7794f5e7dd7Smrgpci_device_solx_devfs_read( struct pci_device * dev, void * data,
7804f5e7dd7Smrg			     pciaddr_t offset, pciaddr_t size,
7814f5e7dd7Smrg			     pciaddr_t * bytes_read )
7824f5e7dd7Smrg{
7834f5e7dd7Smrg    pcitool_reg_t cfg_prg;
7844f5e7dd7Smrg    int err = 0;
78586ea1d58Smrg    unsigned int i = 0;
786cad31331Smrg    nexus_t *nexus;
787cad31331Smrg
788cad31331Smrg    nexus = find_nexus_for_bus(dev->domain, dev->bus);
7894f5e7dd7Smrg
7904f5e7dd7Smrg    *bytes_read = 0;
7914f5e7dd7Smrg
7924f5e7dd7Smrg    if ( nexus == NULL ) {
7934f5e7dd7Smrg	return ENODEV;
7944f5e7dd7Smrg    }
7954f5e7dd7Smrg
7964f5e7dd7Smrg    cfg_prg.offset = offset;
7974f5e7dd7Smrg    cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_1 + NATIVE_ENDIAN;
7984f5e7dd7Smrg    cfg_prg.bus_no = dev->bus;
7994f5e7dd7Smrg    cfg_prg.dev_no = dev->dev;
8004f5e7dd7Smrg    cfg_prg.func_no = dev->func;
8014f5e7dd7Smrg    cfg_prg.barnum = 0;
8024f5e7dd7Smrg    cfg_prg.user_version = PCITOOL_USER_VERSION;
8034f5e7dd7Smrg
8044f5e7dd7Smrg    for (i = 0; i < size; i += PCITOOL_ACC_ATTR_SIZE(PCITOOL_ACC_ATTR_SIZE_1))
8054f5e7dd7Smrg    {
8064f5e7dd7Smrg	cfg_prg.offset = offset + i;
8074f5e7dd7Smrg
8084f5e7dd7Smrg	if ((err = ioctl(nexus->fd, PCITOOL_DEVICE_GET_REG, &cfg_prg)) != 0) {
8094f5e7dd7Smrg	    fprintf(stderr, "read bdf<%s,%x,%x,%x,%llx> config space failure\n",
8104f5e7dd7Smrg		    nexus->path,
8114f5e7dd7Smrg		    cfg_prg.bus_no,
8124f5e7dd7Smrg		    cfg_prg.dev_no,
8134f5e7dd7Smrg		    cfg_prg.func_no,
81486ea1d58Smrg		    (unsigned long long) cfg_prg.offset);
8154f5e7dd7Smrg	    fprintf(stderr, "Failure cause = %x\n", err);
8164f5e7dd7Smrg	    break;
8174f5e7dd7Smrg	}
8184f5e7dd7Smrg
8194f5e7dd7Smrg	((uint8_t *)data)[i] = (uint8_t)cfg_prg.data;
8204f5e7dd7Smrg	/*
8214f5e7dd7Smrg	 * DWORDS Offset or bytes Offset ??
8224f5e7dd7Smrg	 */
8234f5e7dd7Smrg    }
8244f5e7dd7Smrg    *bytes_read = i;
8254f5e7dd7Smrg
8264f5e7dd7Smrg    return (err);
8274f5e7dd7Smrg}
8284f5e7dd7Smrg
8294f5e7dd7Smrg/*
8304f5e7dd7Smrg * Solaris version
8314f5e7dd7Smrg */
8324f5e7dd7Smrgstatic int
8334f5e7dd7Smrgpci_device_solx_devfs_write( struct pci_device * dev, const void * data,
8344f5e7dd7Smrg			     pciaddr_t offset, pciaddr_t size,
8354f5e7dd7Smrg			     pciaddr_t * bytes_written )
8364f5e7dd7Smrg{
8374f5e7dd7Smrg    pcitool_reg_t cfg_prg;
8384f5e7dd7Smrg    int err = 0;
8394f5e7dd7Smrg    int cmd;
840cad31331Smrg    nexus_t *nexus;
841cad31331Smrg
842cad31331Smrg    nexus = find_nexus_for_bus(dev->domain, dev->bus);
8434f5e7dd7Smrg
8444f5e7dd7Smrg    if ( bytes_written != NULL ) {
8454f5e7dd7Smrg	*bytes_written = 0;
8464f5e7dd7Smrg    }
8474f5e7dd7Smrg
8484f5e7dd7Smrg    if ( nexus == NULL ) {
8494f5e7dd7Smrg	return ENODEV;
8504f5e7dd7Smrg    }
8514f5e7dd7Smrg
8524f5e7dd7Smrg    cfg_prg.offset = offset;
8534f5e7dd7Smrg    switch (size) {
8544f5e7dd7Smrg        case 1:
8554f5e7dd7Smrg	    cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_1 + NATIVE_ENDIAN;
856cad31331Smrg	    cfg_prg.data = *((const uint8_t *)data);
8574f5e7dd7Smrg	    break;
8584f5e7dd7Smrg        case 2:
8594f5e7dd7Smrg	    cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_2 + NATIVE_ENDIAN;
860cad31331Smrg	    cfg_prg.data = *((const uint16_t *)data);
8614f5e7dd7Smrg	    break;
8624f5e7dd7Smrg        case 4:
8634f5e7dd7Smrg	    cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + NATIVE_ENDIAN;
864cad31331Smrg	    cfg_prg.data = *((const uint32_t *)data);
8654f5e7dd7Smrg	    break;
8664f5e7dd7Smrg        case 8:
8674f5e7dd7Smrg	    cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_8 + NATIVE_ENDIAN;
868cad31331Smrg	    cfg_prg.data = *((const uint64_t *)data);
8694f5e7dd7Smrg	    break;
8704f5e7dd7Smrg        default:
8714f5e7dd7Smrg	    return EINVAL;
8724f5e7dd7Smrg    }
8734f5e7dd7Smrg    cfg_prg.bus_no = dev->bus;
8744f5e7dd7Smrg    cfg_prg.dev_no = dev->dev;
8754f5e7dd7Smrg    cfg_prg.func_no = dev->func;
8764f5e7dd7Smrg    cfg_prg.barnum = 0;
8774f5e7dd7Smrg    cfg_prg.user_version = PCITOOL_USER_VERSION;
8784f5e7dd7Smrg
8794f5e7dd7Smrg    /*
8804f5e7dd7Smrg     * Check if this device is bridge device.
8814f5e7dd7Smrg     * If it is, it is also a nexus node???
8824f5e7dd7Smrg     * It seems that there is no explicit
8834f5e7dd7Smrg     * PCI nexus device for X86, so not applicable
8844f5e7dd7Smrg     * from pcitool_bus_reg_ops in pci_tools.c
8854f5e7dd7Smrg     */
8864f5e7dd7Smrg    cmd = PCITOOL_DEVICE_SET_REG;
8874f5e7dd7Smrg
8884f5e7dd7Smrg    if ((err = ioctl(nexus->fd, cmd, &cfg_prg)) != 0) {
8894f5e7dd7Smrg	return (err);
8904f5e7dd7Smrg    }
8914f5e7dd7Smrg    *bytes_written = size;
8924f5e7dd7Smrg
8934f5e7dd7Smrg    return (err);
8944f5e7dd7Smrg}
8954f5e7dd7Smrg
89686ea1d58Smrgstatic int pci_device_solx_devfs_boot_vga(struct pci_device *dev)
89786ea1d58Smrg{
89886ea1d58Smrg    struct pci_device_private *priv =
89986ea1d58Smrg	(struct pci_device_private *) dev;
90086ea1d58Smrg
90186ea1d58Smrg    return (priv->is_primary);
90286ea1d58Smrg
90386ea1d58Smrg}
90486ea1d58Smrg
90586ea1d58Smrgstatic struct pci_io_handle *
90686ea1d58Smrgpci_device_solx_devfs_open_legacy_io(struct pci_io_handle *ret,
90786ea1d58Smrg				     struct pci_device *dev,
90886ea1d58Smrg				     pciaddr_t base, pciaddr_t size)
90986ea1d58Smrg{
91086ea1d58Smrg#ifdef __x86
91186ea1d58Smrg    if (sysi86(SI86V86, V86SC_IOPL, PS_IOPL) == 0) {
91286ea1d58Smrg	ret->base = base;
91386ea1d58Smrg	ret->size = size;
91486ea1d58Smrg	return ret;
91586ea1d58Smrg    }
91686ea1d58Smrg#endif
91786ea1d58Smrg    return NULL;
91886ea1d58Smrg}
91986ea1d58Smrg
92086ea1d58Smrgstatic uint32_t
92186ea1d58Smrgpci_device_solx_devfs_read32(struct pci_io_handle *handle, uint32_t reg)
92286ea1d58Smrg{
92386ea1d58Smrg#ifdef __x86
92486ea1d58Smrg    uint16_t port = (uint16_t) (handle->base + reg);
92586ea1d58Smrg    uint32_t ret;
92686ea1d58Smrg    __asm__ __volatile__("inl %1,%0":"=a"(ret):"d"(port));
92786ea1d58Smrg    return ret;
92886ea1d58Smrg#else
92986ea1d58Smrg    return *(uint32_t *)((uintptr_t)handle->memory + reg);
93086ea1d58Smrg#endif
93186ea1d58Smrg}
93286ea1d58Smrg
93386ea1d58Smrgstatic uint16_t
93486ea1d58Smrgpci_device_solx_devfs_read16(struct pci_io_handle *handle, uint32_t reg)
93586ea1d58Smrg{
93686ea1d58Smrg#ifdef __x86
93786ea1d58Smrg    uint16_t port = (uint16_t) (handle->base + reg);
93886ea1d58Smrg    uint16_t ret;
93986ea1d58Smrg    __asm__ __volatile__("inw %1,%0":"=a"(ret):"d"(port));
94086ea1d58Smrg    return ret;
94186ea1d58Smrg#else
94286ea1d58Smrg    return *(uint16_t *)((uintptr_t)handle->memory + reg);
94386ea1d58Smrg#endif
94486ea1d58Smrg}
94586ea1d58Smrg
94686ea1d58Smrgstatic uint8_t
94786ea1d58Smrgpci_device_solx_devfs_read8(struct pci_io_handle *handle, uint32_t reg)
94886ea1d58Smrg{
94986ea1d58Smrg#ifdef __x86
95086ea1d58Smrg    uint16_t port = (uint16_t) (handle->base + reg);
95186ea1d58Smrg    uint8_t ret;
95286ea1d58Smrg    __asm__ __volatile__("inb %1,%0":"=a"(ret):"d"(port));
95386ea1d58Smrg    return ret;
95486ea1d58Smrg#else
95586ea1d58Smrg    return *(uint8_t *)((uintptr_t)handle->memory + reg);
95686ea1d58Smrg#endif
95786ea1d58Smrg}
95886ea1d58Smrg
95986ea1d58Smrgstatic void
96086ea1d58Smrgpci_device_solx_devfs_write32(struct pci_io_handle *handle, uint32_t reg,
96186ea1d58Smrg    uint32_t data)
96286ea1d58Smrg{
96386ea1d58Smrg#ifdef __x86
96486ea1d58Smrg      uint16_t port = (uint16_t) (handle->base + reg);
96586ea1d58Smrg      __asm__ __volatile__("outl %0,%1"::"a"(data), "d"(port));
96686ea1d58Smrg#else
96786ea1d58Smrg      *(uint16_t *)((uintptr_t)handle->memory + reg) = data;
96886ea1d58Smrg#endif
96986ea1d58Smrg}
97086ea1d58Smrg
97186ea1d58Smrgstatic void
97286ea1d58Smrgpci_device_solx_devfs_write16(struct pci_io_handle *handle, uint32_t reg,
97386ea1d58Smrg    uint16_t data)
97486ea1d58Smrg{
97586ea1d58Smrg#ifdef __x86
97686ea1d58Smrg      uint16_t port = (uint16_t) (handle->base + reg);
97786ea1d58Smrg      __asm__ __volatile__("outw %0,%1"::"a"(data), "d"(port));
97886ea1d58Smrg#else
97986ea1d58Smrg    *(uint8_t *)((uintptr_t)handle->memory + reg) = data;
98086ea1d58Smrg#endif
98186ea1d58Smrg}
98286ea1d58Smrg
98386ea1d58Smrgstatic void
98486ea1d58Smrgpci_device_solx_devfs_write8(struct pci_io_handle *handle, uint32_t reg,
98586ea1d58Smrg    uint8_t data)
98686ea1d58Smrg{
98786ea1d58Smrg#ifdef __x86
98886ea1d58Smrg      uint16_t port = (uint16_t) (handle->base + reg);
98986ea1d58Smrg      __asm__ __volatile__("outb %0,%1"::"a"(data), "d"(port));
99086ea1d58Smrg#else
99186ea1d58Smrg      *(uint32_t *)((uintptr_t)handle->memory + reg) = data;
99286ea1d58Smrg#endif
99386ea1d58Smrg}
99486ea1d58Smrg
99586ea1d58Smrgstatic int
99686ea1d58Smrgpci_device_solx_devfs_map_legacy(struct pci_device *dev, pciaddr_t base,
99786ea1d58Smrg				 pciaddr_t size, unsigned map_flags,
99886ea1d58Smrg				 void **addr)
99986ea1d58Smrg{
100086ea1d58Smrg    int err;
100186ea1d58Smrg    struct pci_device_mapping map = {
100286ea1d58Smrg	.base = base,
100386ea1d58Smrg	.size = size,
100486ea1d58Smrg	.flags = map_flags,
100586ea1d58Smrg    };
10064f5e7dd7Smrg
100786ea1d58Smrg    err = pci_device_solx_devfs_map_range(dev, &map);
100886ea1d58Smrg    if (err == 0)
100986ea1d58Smrg	*addr = map.memory;
101086ea1d58Smrg    return err;
101186ea1d58Smrg}
101286ea1d58Smrg
101386ea1d58Smrgstatic int
101486ea1d58Smrgpci_device_solx_devfs_unmap_legacy(struct pci_device *dev,
101586ea1d58Smrg				   void *addr, pciaddr_t size)
101686ea1d58Smrg{
101786ea1d58Smrg    struct pci_device_mapping map = {
101886ea1d58Smrg	.memory = addr,
101986ea1d58Smrg	.size = size,
102086ea1d58Smrg    };
102186ea1d58Smrg
102286ea1d58Smrg    return pci_device_generic_unmap_range(dev, &map);
102386ea1d58Smrg}
1024cad31331Smrg
1025cad31331Smrgstatic const struct pci_system_methods solx_devfs_methods = {
1026cad31331Smrg    .destroy = pci_system_solx_devfs_destroy,
102786ea1d58Smrg#ifdef __sparc
102886ea1d58Smrg    .destroy_device = pci_system_solx_devfs_destroy_device,
102986ea1d58Smrg#else
1030cad31331Smrg    .destroy_device = NULL,
103186ea1d58Smrg#endif
1032cad31331Smrg    .read_rom = pci_device_solx_devfs_read_rom,
1033cad31331Smrg    .probe = pci_device_solx_devfs_probe,
1034cad31331Smrg    .map_range = pci_device_solx_devfs_map_range,
1035cad31331Smrg    .unmap_range = pci_device_generic_unmap_range,
1036cad31331Smrg
1037cad31331Smrg    .read = pci_device_solx_devfs_read,
1038cad31331Smrg    .write = pci_device_solx_devfs_write,
1039cad31331Smrg
104086ea1d58Smrg    .fill_capabilities = pci_fill_capabilities_generic,
104186ea1d58Smrg    .boot_vga = pci_device_solx_devfs_boot_vga,
104286ea1d58Smrg
104386ea1d58Smrg    .open_legacy_io = pci_device_solx_devfs_open_legacy_io,
104486ea1d58Smrg    .read32 = pci_device_solx_devfs_read32,
104586ea1d58Smrg    .read16 = pci_device_solx_devfs_read16,
104686ea1d58Smrg    .read8 = pci_device_solx_devfs_read8,
104786ea1d58Smrg    .write32 = pci_device_solx_devfs_write32,
104886ea1d58Smrg    .write16 = pci_device_solx_devfs_write16,
104986ea1d58Smrg    .write8 = pci_device_solx_devfs_write8,
105086ea1d58Smrg    .map_legacy = pci_device_solx_devfs_map_legacy,
105186ea1d58Smrg    .unmap_legacy = pci_device_solx_devfs_unmap_legacy,
1052cad31331Smrg};
1053cad31331Smrg
1054cad31331Smrg/*
1055cad31331Smrg * Attempt to access PCI subsystem using Solaris's devfs interface.
1056cad31331Smrg * Solaris version
10574f5e7dd7Smrg */
1058cad31331Smrg_pci_hidden int
1059cad31331Smrgpci_system_solx_devfs_create( void )
10604f5e7dd7Smrg{
10614f5e7dd7Smrg    int err = 0;
1062cad31331Smrg    di_node_t di_node;
1063cad31331Smrg    probe_info_t pinfo;
1064cad31331Smrg    struct pci_device_private *devices;
10654f5e7dd7Smrg
1066cad31331Smrg    if (nexus_list != NULL) {
1067cad31331Smrg	return 0;
10684f5e7dd7Smrg    }
10694f5e7dd7Smrg
1070cad31331Smrg    if ((di_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
10714f5e7dd7Smrg	err = errno;
1072cad31331Smrg	(void) fprintf(stderr, "di_init() failed: %s\n",
1073cad31331Smrg		       strerror(errno));
1074cad31331Smrg	return (err);
1075cad31331Smrg    }
10764f5e7dd7Smrg
1077cad31331Smrg    if ((devices = calloc(INITIAL_NUM_DEVICES,
1078cad31331Smrg			sizeof (struct pci_device_private))) == NULL) {
1079cad31331Smrg	err = errno;
1080cad31331Smrg	di_fini(di_node);
1081cad31331Smrg	return (err);
10824f5e7dd7Smrg    }
10834f5e7dd7Smrg
1084cad31331Smrg#ifdef __sparc
1085cad31331Smrg    if ((di_phdl = di_prom_init()) == DI_PROM_HANDLE_NIL)
1086cad31331Smrg	(void) fprintf(stderr, "di_prom_init failed: %s\n", strerror(errno));
1087cad31331Smrg#endif
1088cad31331Smrg
1089cad31331Smrg    pinfo.num_allocated_elems = INITIAL_NUM_DEVICES;
1090cad31331Smrg    pinfo.num_devices = 0;
1091cad31331Smrg    pinfo.devices = devices;
109286ea1d58Smrg#ifdef __sparc
109386ea1d58Smrg    nexus_count = 0;
109486ea1d58Smrg#endif
1095cad31331Smrg    (void) di_walk_minor(di_node, DDI_NT_REGACC, 0, &pinfo, probe_nexus_node);
1096cad31331Smrg
1097cad31331Smrg    di_fini(di_node);
1098cad31331Smrg
1099cad31331Smrg    if ((pci_sys = calloc(1, sizeof (struct pci_system))) == NULL) {
1100cad31331Smrg	err = errno;
1101cad31331Smrg	free(devices);
1102cad31331Smrg	return (err);
1103cad31331Smrg    }
1104cad31331Smrg
1105cad31331Smrg    pci_sys->methods = &solx_devfs_methods;
1106cad31331Smrg    pci_sys->devices = pinfo.devices;
1107cad31331Smrg    pci_sys->num_devices = pinfo.num_devices;
1108cad31331Smrg
1109cad31331Smrg    return (err);
11104f5e7dd7Smrg}
1111