17aec1d6eScindi /*
27aec1d6eScindi  * CDDL HEADER START
37aec1d6eScindi  *
47aec1d6eScindi  * The contents of this file are subject to the terms of the
57aec1d6eScindi  * Common Development and Distribution License (the "License").
67aec1d6eScindi  * You may not use this file except in compliance with the License.
77aec1d6eScindi  *
87aec1d6eScindi  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97aec1d6eScindi  * or http://www.opensolaris.org/os/licensing.
107aec1d6eScindi  * See the License for the specific language governing permissions
117aec1d6eScindi  * and limitations under the License.
127aec1d6eScindi  *
137aec1d6eScindi  * When distributing Covered Code, include this CDDL HEADER in each
147aec1d6eScindi  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157aec1d6eScindi  * If applicable, add the following below this CDDL HEADER, with the
167aec1d6eScindi  * fields enclosed by brackets "[]" replaced with your own identifying
177aec1d6eScindi  * information: Portions Copyright [yyyy] [name of copyright owner]
187aec1d6eScindi  *
197aec1d6eScindi  * CDDL HEADER END
207aec1d6eScindi  */
217aec1d6eScindi 
227aec1d6eScindi /*
230db3240dSStephen Hanson  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24*106e8bd4SRob Johnston  * Copyright 2019 Joyent, Inc.
257aec1d6eScindi  */
267aec1d6eScindi 
277aec1d6eScindi /*
287aec1d6eScindi  * did.c
297aec1d6eScindi  *	The acronym did means "Dev-Info-Data".  Many properties and
307aec1d6eScindi  *	characteristics of topology nodes are, with a bit of coaxing
317aec1d6eScindi  *	derived from devinfo nodes.  These routines do some of the
327aec1d6eScindi  *	derivation and also encapsulate the discoveries in did_t
337aec1d6eScindi  *	structures that get associated with topology nodes as their
347aec1d6eScindi  *	"private" data.
357aec1d6eScindi  */
367aec1d6eScindi #include <alloca.h>
377aec1d6eScindi #include <assert.h>
387aec1d6eScindi #include <string.h>
397aec1d6eScindi #include <strings.h>
407aec1d6eScindi #include <sys/types.h>
410eb822a1Scindi #include <fm/topo_mod.h>
427aec1d6eScindi #include <libnvpair.h>
437aec1d6eScindi #include <libdevinfo.h>
447aec1d6eScindi #include <sys/pcie.h>
457aec1d6eScindi 
460eb822a1Scindi #include <hostbridge.h>
470eb822a1Scindi #include <pcibus.h>
480eb822a1Scindi #include <did_props.h>
490eb822a1Scindi 
507aec1d6eScindi #include "did_impl.h"
517aec1d6eScindi 
527aec1d6eScindi static void slotnm_destroy(slotnm_t *);
537aec1d6eScindi 
547aec1d6eScindi static slotnm_t *
slotnm_create(topo_mod_t * mp,int dev,char * str)557aec1d6eScindi slotnm_create(topo_mod_t *mp, int dev, char *str)
567aec1d6eScindi {
577aec1d6eScindi 	slotnm_t *p;
587aec1d6eScindi 
597aec1d6eScindi 	if ((p = topo_mod_alloc(mp, sizeof (slotnm_t))) == NULL)
607aec1d6eScindi 		return (NULL);
617aec1d6eScindi 	p->snm_mod = mp;
627aec1d6eScindi 	p->snm_next = NULL;
637aec1d6eScindi 	p->snm_dev = dev;
6460348818STarik Soydan 	p->snm_name = topo_mod_strdup(mp, str);
6560348818STarik Soydan 	if (p->snm_name == NULL) {
667aec1d6eScindi 		slotnm_destroy(p);
677aec1d6eScindi 		return (NULL);
687aec1d6eScindi 	}
697aec1d6eScindi 	return (p);
707aec1d6eScindi }
717aec1d6eScindi 
727aec1d6eScindi static void
slotnm_destroy(slotnm_t * p)737aec1d6eScindi slotnm_destroy(slotnm_t *p)
747aec1d6eScindi {
757aec1d6eScindi 	if (p == NULL)
767aec1d6eScindi 		return;
777aec1d6eScindi 	slotnm_destroy(p->snm_next);
7860348818STarik Soydan 	if (p->snm_name != NULL)
7960348818STarik Soydan 		topo_mod_strfree(p->snm_mod, p->snm_name);
807aec1d6eScindi 	topo_mod_free(p->snm_mod, p, sizeof (slotnm_t));
817aec1d6eScindi }
827aec1d6eScindi 
837aec1d6eScindi static int
di_devtype_get(topo_mod_t * mp,di_node_t src,char ** devtype)8449fbdd30SErwin T Tsaur di_devtype_get(topo_mod_t *mp, di_node_t src, char **devtype)
857aec1d6eScindi {
860b6016e6Shueston 	int sz;
870b6016e6Shueston 	uchar_t *buf;
887aec1d6eScindi 
897aec1d6eScindi 	/*
9049fbdd30SErwin T Tsaur 	 * For PCI the device type defined the type of device directly below.
9149fbdd30SErwin T Tsaur 	 * For PCIe RP and Switches, the device-type should be "pciex".  For
9249fbdd30SErwin T Tsaur 	 * PCIe-PCI and PCI-PCI bridges it should be "pci".  NICs = "network",
9349fbdd30SErwin T Tsaur 	 * Graphics = "display", etc..
947aec1d6eScindi 	 */
9549fbdd30SErwin T Tsaur 	if (di_bytes_get(mp, src, DI_DEVTYPPROP, &sz, &buf) == 0) {
9649fbdd30SErwin T Tsaur 		*devtype = topo_mod_strdup(mp, (char *)buf);
9749fbdd30SErwin T Tsaur 	} else {
9849fbdd30SErwin T Tsaur 		*devtype = NULL;
997aec1d6eScindi 	}
10049fbdd30SErwin T Tsaur 
10149fbdd30SErwin T Tsaur 	if (*devtype != NULL)
10249fbdd30SErwin T Tsaur 		return (0);
10349fbdd30SErwin T Tsaur 	return (-1);
10449fbdd30SErwin T Tsaur }
10549fbdd30SErwin T Tsaur 
1060db3240dSStephen Hanson typedef struct smbios_slot_cb {
1070db3240dSStephen Hanson 	int		cb_slotnum;
108*106e8bd4SRob Johnston 	int		cb_bdf;
1090db3240dSStephen Hanson 	const char	*cb_label;
1100db3240dSStephen Hanson } smbios_slot_cb_t;
1110db3240dSStephen Hanson 
1120db3240dSStephen Hanson static int
di_smbios_find_slot_by_bdf(smbios_hdl_t * shp,const smbios_struct_t * strp,void * data)113*106e8bd4SRob Johnston di_smbios_find_slot_by_bdf(smbios_hdl_t *shp, const smbios_struct_t *strp,
114*106e8bd4SRob Johnston     void *data)
115*106e8bd4SRob Johnston {
116*106e8bd4SRob Johnston 	smbios_slot_cb_t *cbp = data;
117*106e8bd4SRob Johnston 	smbios_slot_t slot;
118*106e8bd4SRob Johnston 	int bus, df;
119*106e8bd4SRob Johnston 
120*106e8bd4SRob Johnston 	bus = (cbp->cb_bdf & 0xFF00) >> 8;
121*106e8bd4SRob Johnston 	df = cbp->cb_bdf & 0xFF;
122*106e8bd4SRob Johnston 
123*106e8bd4SRob Johnston 	if (strp->smbstr_type != SMB_TYPE_SLOT ||
124*106e8bd4SRob Johnston 	    smbios_info_slot(shp, strp->smbstr_id, &slot) != 0)
125*106e8bd4SRob Johnston 		return (0);
126*106e8bd4SRob Johnston 
127*106e8bd4SRob Johnston 	if (slot.smbl_bus == bus && slot.smbl_df == df) {
128*106e8bd4SRob Johnston 		cbp->cb_label = slot.smbl_name;
129*106e8bd4SRob Johnston 		cbp->cb_slotnum = slot.smbl_id;
130*106e8bd4SRob Johnston 		return (1);
131*106e8bd4SRob Johnston 	}
132*106e8bd4SRob Johnston 
133*106e8bd4SRob Johnston 	return (0);
134*106e8bd4SRob Johnston }
135*106e8bd4SRob Johnston 
136*106e8bd4SRob Johnston static int
di_smbios_find_slot_by_id(smbios_hdl_t * shp,const smbios_struct_t * strp,void * data)137*106e8bd4SRob Johnston di_smbios_find_slot_by_id(smbios_hdl_t *shp, const smbios_struct_t *strp,
138*106e8bd4SRob Johnston     void *data)
1390db3240dSStephen Hanson {
1400db3240dSStephen Hanson 	smbios_slot_cb_t *cbp = data;
1410db3240dSStephen Hanson 	smbios_slot_t slot;
1420db3240dSStephen Hanson 
1430db3240dSStephen Hanson 	if (strp->smbstr_type != SMB_TYPE_SLOT ||
1440db3240dSStephen Hanson 	    smbios_info_slot(shp, strp->smbstr_id, &slot) != 0)
1450db3240dSStephen Hanson 		return (0);
1460db3240dSStephen Hanson 
1470db3240dSStephen Hanson 	if (slot.smbl_id == cbp->cb_slotnum) {
1480db3240dSStephen Hanson 		cbp->cb_label = slot.smbl_name;
1490db3240dSStephen Hanson 		return (1);
1500db3240dSStephen Hanson 	}
1510db3240dSStephen Hanson 
1520db3240dSStephen Hanson 	return (0);
1530db3240dSStephen Hanson }
1540db3240dSStephen Hanson 
15549fbdd30SErwin T Tsaur static int
di_physlotinfo_get(topo_mod_t * mp,di_node_t src,int bdf,int * slotnum,char ** slotname)156*106e8bd4SRob Johnston di_physlotinfo_get(topo_mod_t *mp, di_node_t src, int bdf, int *slotnum,
157*106e8bd4SRob Johnston     char **slotname)
15849fbdd30SErwin T Tsaur {
159*106e8bd4SRob Johnston 	char *slotbuf = NULL;
16049fbdd30SErwin T Tsaur 	int sz;
16149fbdd30SErwin T Tsaur 	uchar_t *buf;
1620db3240dSStephen Hanson 	smbios_hdl_t *shp;
1630db3240dSStephen Hanson 	boolean_t got_slotprop = B_FALSE;
16449fbdd30SErwin T Tsaur 
16549fbdd30SErwin T Tsaur 	*slotnum = -1;
16660348818STarik Soydan 
1670db3240dSStephen Hanson 	(void) di_uintprop_get(mp, src, DI_PHYSPROP, (uint_t *)slotnum);
1687aec1d6eScindi 
1697aec1d6eScindi 	/*
1700b6016e6Shueston 	 * For PCI-Express, there is only one downstream device, so check for
1710b6016e6Shueston 	 * a slot-names property, and if it exists, ignore the slotmask value
1720b6016e6Shueston 	 * and use the string as the label.
1737aec1d6eScindi 	 */
1740eb822a1Scindi 	if (di_bytes_get(mp, src, DI_SLOTPROP, &sz, &buf) == 0 &&
175724365f7Ssethg 	    sz > 4) {
1760db3240dSStephen Hanson 		/*
1770db3240dSStephen Hanson 		 * If there is a DI_SLOTPROP of the form SlotX (ie set up from
1780db3240dSStephen Hanson 		 * the IRQ routing table) then trust that in preference to
1790db3240dSStephen Hanson 		 * DI_PHYSPROP (which is set up from the PCIe slotcap reg).
1800db3240dSStephen Hanson 		 */
1810db3240dSStephen Hanson 		got_slotprop = B_TRUE;
1820db3240dSStephen Hanson 		(void) sscanf((char *)&buf[4], "Slot%d", slotnum);
1830db3240dSStephen Hanson 	}
1840db3240dSStephen Hanson 
1850db3240dSStephen Hanson 	/*
186*106e8bd4SRob Johnston 	 * If the system supports SMBIOS (virtual certainty on X86) then we will
187*106e8bd4SRob Johnston 	 * source the label from the Type 9 (Slot) records.  If we're unable
188*106e8bd4SRob Johnston 	 * to correlate the device with a slot record (as would happen with
189*106e8bd4SRob Johnston 	 * onboard PCIe devices), we return without setting slotname, which will
190*106e8bd4SRob Johnston 	 * ultimately result in the node inheriting the FRU label from its
191*106e8bd4SRob Johnston 	 * parent node.
192*106e8bd4SRob Johnston 	 *
193*106e8bd4SRob Johnston 	 * In the absence of any SMBIOS support (i.e. SPARC) then we will use
194*106e8bd4SRob Johnston 	 * the slot-names property, if available.  Otherwise we'll fall back
195*106e8bd4SRob Johnston 	 * to fabricating a label based on the slot number.
1960db3240dSStephen Hanson 	 */
1970db3240dSStephen Hanson 	if ((shp = topo_mod_smbios(mp)) != NULL) {
1980db3240dSStephen Hanson 		/*
1990db3240dSStephen Hanson 		 * The PCI spec describes slot number 0 as reserved for
200*106e8bd4SRob Johnston 		 * internal PCI devices.  Unfortunately, not all platforms
201*106e8bd4SRob Johnston 		 * respect this.  For that reason, we prefer to lookup the slot
202*106e8bd4SRob Johnston 		 * record using the device's BDF.  However, SMBIOS
203*106e8bd4SRob Johnston 		 * implementations prior to 2.6 don't encode the BDF in the
204*106e8bd4SRob Johnston 		 * slot record.  In that case we resort to looking up the
205*106e8bd4SRob Johnston 		 * slot record using the slot number.
2060db3240dSStephen Hanson 		 */
2070db3240dSStephen Hanson 		smbios_slot_cb_t cbdata;
208*106e8bd4SRob Johnston 		smbios_version_t smbv;
209*106e8bd4SRob Johnston 		boolean_t bdf_supp = B_TRUE;
2100db3240dSStephen Hanson 
2110db3240dSStephen Hanson 		cbdata.cb_slotnum = *slotnum;
212*106e8bd4SRob Johnston 		cbdata.cb_bdf = bdf;
2130db3240dSStephen Hanson 		cbdata.cb_label = NULL;
214*106e8bd4SRob Johnston 
215*106e8bd4SRob Johnston 		/*
216*106e8bd4SRob Johnston 		 * The bus and device/fn payload members of the SMBIOS slot
217*106e8bd4SRob Johnston 		 * record were added in SMBIOS 2.6.
218*106e8bd4SRob Johnston 		 */
219*106e8bd4SRob Johnston 		smbios_info_smbios_version(shp, &smbv);
220*106e8bd4SRob Johnston 		if (smbv.smbv_major < 2 ||
221*106e8bd4SRob Johnston 		    (smbv.smbv_major == 2 && smbv.smbv_minor < 6)) {
222*106e8bd4SRob Johnston 			bdf_supp = B_FALSE;
223*106e8bd4SRob Johnston 		}
224*106e8bd4SRob Johnston 
225*106e8bd4SRob Johnston 		/*
226*106e8bd4SRob Johnston 		 * If the SMBIOS implementation is too old to look up the slot
227*106e8bd4SRob Johnston 		 * records by BDF and we weren't able to derive a slotnum then
228*106e8bd4SRob Johnston 		 * there is nothing we can do here.
229*106e8bd4SRob Johnston 		 */
230*106e8bd4SRob Johnston 		if (!bdf_supp && *slotnum == -1)
231*106e8bd4SRob Johnston 			return (0);
232*106e8bd4SRob Johnston 
233*106e8bd4SRob Johnston 		if (bdf_supp)
234*106e8bd4SRob Johnston 			(void) smbios_iter(shp, di_smbios_find_slot_by_bdf,
235*106e8bd4SRob Johnston 			    &cbdata);
236*106e8bd4SRob Johnston 		else
237*106e8bd4SRob Johnston 			(void) smbios_iter(shp, di_smbios_find_slot_by_id,
238*106e8bd4SRob Johnston 			    &cbdata);
239*106e8bd4SRob Johnston 
240*106e8bd4SRob Johnston 		if (cbdata.cb_label == NULL)
2410db3240dSStephen Hanson 			return (0);
242*106e8bd4SRob Johnston 
2430db3240dSStephen Hanson 		slotbuf = (char *)cbdata.cb_label;
244*106e8bd4SRob Johnston 		topo_mod_dprintf(mp, "%s: di_node=%p: using smbios name: %s\n",
245*106e8bd4SRob Johnston 		    __func__, src, slotbuf);
246*106e8bd4SRob Johnston 	} else if (got_slotprop) {
2470b6016e6Shueston 		slotbuf = (char *)&buf[4];
248*106e8bd4SRob Johnston 		topo_mod_dprintf(mp, "%s: di_node=%p: using %s property: %s\n",
249*106e8bd4SRob Johnston 		    __func__, src, DI_SLOTPROP, slotbuf);
2500b6016e6Shueston 	} else {
2510b6016e6Shueston 		/*
2520b6016e6Shueston 		 * Make generic description string "SLOT <num>", allow up to
253*106e8bd4SRob Johnston 		 * 10 digits for number.  Bail, if we weren't able to derive
254*106e8bd4SRob Johnston 		 * a slotnum.
2550b6016e6Shueston 		 */
256*106e8bd4SRob Johnston 		if (*slotnum == -1)
257*106e8bd4SRob Johnston 			return (0);
258*106e8bd4SRob Johnston 
2590b6016e6Shueston 		slotbuf = alloca(16);
2600b6016e6Shueston 		(void) snprintf(slotbuf, 16, "SLOT %d", *slotnum);
261*106e8bd4SRob Johnston 		topo_mod_dprintf(mp, "%s: di_node=%p: using fabricated slot "
262*106e8bd4SRob Johnston 		    "name: %s\n", __func__, src, slotbuf);
2630b6016e6Shueston 	}
26460348818STarik Soydan 
265*106e8bd4SRob Johnston 	if ((*slotname = topo_mod_strdup(mp, slotbuf)) == NULL) {
266*106e8bd4SRob Johnston 		/* topo errno set */
267*106e8bd4SRob Johnston 		return (-1);
268*106e8bd4SRob Johnston 	}
2697aec1d6eScindi 	return (0);
2707aec1d6eScindi }
2717aec1d6eScindi 
2727aec1d6eScindi static int
di_slotinfo_get(topo_mod_t * mp,di_node_t src,int * nslots,slotnm_t ** slotnames)27360348818STarik Soydan di_slotinfo_get(topo_mod_t *mp, di_node_t src, int *nslots,
27460348818STarik Soydan     slotnm_t **slotnames)
2757aec1d6eScindi {
2767aec1d6eScindi 	slotnm_t *lastslot = NULL;
2777aec1d6eScindi 	slotnm_t *newslot;
2787aec1d6eScindi 	uchar_t *slotbuf;
2797aec1d6eScindi 	uint_t slotmap = 0;
2807aec1d6eScindi 	char *slotname;
2817aec1d6eScindi 	int andbit;
2827aec1d6eScindi 	int sz = -1;
2837aec1d6eScindi 
28460348818STarik Soydan 	*slotnames = NULL;
2857aec1d6eScindi 	*nslots = 0;
2860eb822a1Scindi 	if (di_bytes_get(mp, src, DI_SLOTPROP, &sz, &slotbuf) < 0)
2877aec1d6eScindi 		return (0);
2887aec1d6eScindi 	if (sz < sizeof (uint_t))
2897aec1d6eScindi 		return (0);
2907aec1d6eScindi 	bcopy(slotbuf, &slotmap, sizeof (uint_t));
2917aec1d6eScindi 	if (slotmap == 0)
2927aec1d6eScindi 		return (0);
2937aec1d6eScindi 
2947aec1d6eScindi 	slotname = (char *)&slotbuf[4];
2957aec1d6eScindi 	for (andbit = 0; andbit < 32; andbit++) {
2967aec1d6eScindi 		if (slotmap & (1 << andbit)) {
2977aec1d6eScindi 			char *s = slotname;
2987aec1d6eScindi 			slotname += strlen(s) + 1;
2997aec1d6eScindi 			if ((newslot = slotnm_create(mp, andbit, s)) == NULL) {
30060348818STarik Soydan 				slotnm_destroy(*slotnames);
30160348818STarik Soydan 				*slotnames = NULL;
3027aec1d6eScindi 				*nslots = 0;
3037aec1d6eScindi 				return (-1);
3047aec1d6eScindi 			}
3057aec1d6eScindi 			if (lastslot == NULL)
30660348818STarik Soydan 				*slotnames = lastslot = newslot;
307c863ec5cSstephh 			else {
3087aec1d6eScindi 				lastslot->snm_next = newslot;
309c863ec5cSstephh 				lastslot = newslot;
310c863ec5cSstephh 			}
3117aec1d6eScindi 			(*nslots)++;
3127aec1d6eScindi 		}
3137aec1d6eScindi 	}
3147aec1d6eScindi 	return (0);
3157aec1d6eScindi }
3167aec1d6eScindi 
3177aec1d6eScindi int
did_physlot(did_t * did)31860348818STarik Soydan did_physlot(did_t *did)
3197aec1d6eScindi {
3207aec1d6eScindi 	assert(did != NULL);
3217aec1d6eScindi 	return (did->dp_physlot);
3227aec1d6eScindi }
3237aec1d6eScindi 
32460348818STarik Soydan int
did_physlot_exists(did_t * did)32560348818STarik Soydan did_physlot_exists(did_t *did)
32660348818STarik Soydan {
32760348818STarik Soydan 	assert(did != NULL);
32860348818STarik Soydan 	return ((did->dp_physlot >= 0) || (did->dp_nslots > 0));
32960348818STarik Soydan }
33060348818STarik Soydan 
3317aec1d6eScindi did_t *
did_create(topo_mod_t * mp,di_node_t src,int ibrd,int ibrdge,int irc,int ibus)3320eb822a1Scindi did_create(topo_mod_t *mp, di_node_t src,
3330eb822a1Scindi     int ibrd, int ibrdge, int irc, int ibus)
3347aec1d6eScindi {
3357aec1d6eScindi 	did_t *np;
3367aec1d6eScindi 	did_t *pd;
3377aec1d6eScindi 	uint_t code;
3387aec1d6eScindi 	uint_t reg;
3397aec1d6eScindi 
3400eb822a1Scindi 	if ((pd = did_hash_lookup(mp, src)) != NULL) {
3417aec1d6eScindi 		topo_mod_dprintf(mp, "Attempt to create existing did_t.\n");
3427aec1d6eScindi 		assert(ibus == TRUST_BDF || (pd->dp_bus == ibus));
3437aec1d6eScindi 		return (pd);
3447aec1d6eScindi 	}
3457aec1d6eScindi 
3467aec1d6eScindi 	if ((np = topo_mod_zalloc(mp, sizeof (did_t))) == NULL)
3477aec1d6eScindi 		return (NULL);
3487aec1d6eScindi 	np->dp_mod = mp;
3497aec1d6eScindi 	np->dp_src = src;
3500eb822a1Scindi 	np->dp_hash = (did_hash_t *)topo_mod_getspecific(mp);
35140e5e17bSzx 	np->dp_tnode = NULL;
3527aec1d6eScindi 
3537aec1d6eScindi 	/*
3547aec1d6eScindi 	 * We must have a reg prop and from it we extract the bus #,
3557aec1d6eScindi 	 * device #, and function #.
3567aec1d6eScindi 	 */
3570eb822a1Scindi 	if (di_uintprop_get(mp, src, DI_REGPROP, &reg) < 0) {
3587aec1d6eScindi 		topo_mod_free(mp, np, sizeof (did_t));
3597aec1d6eScindi 		return (NULL);
3607aec1d6eScindi 	}
3617aec1d6eScindi 	np->dp_board = ibrd;
3627aec1d6eScindi 	np->dp_bridge = ibrdge;
3637aec1d6eScindi 	np->dp_rc = irc;
3647aec1d6eScindi 	if (ibus == TRUST_BDF)
3657aec1d6eScindi 		np->dp_bus = PCI_REG_BUS_G(reg);
3667aec1d6eScindi 	else
3677aec1d6eScindi 		np->dp_bus = ibus;
3687aec1d6eScindi 	np->dp_dev = PCI_REG_DEV_G(reg);
3697aec1d6eScindi 	np->dp_fn = PCI_REG_FUNC_G(reg);
37000d0963fSdilpreet 	np->dp_bdf = (PCI_REG_BUS_G(reg) << 8) | (PCI_REG_DEV_G(reg) << 3) |
37100d0963fSdilpreet 	    PCI_REG_FUNC_G(reg);
3727aec1d6eScindi 	/*
3737aec1d6eScindi 	 * There *may* be a class code we can capture.  If there wasn't
3747aec1d6eScindi 	 * one, capture that fact by setting the class value to -1.
3757aec1d6eScindi 	 */
3760eb822a1Scindi 	if (di_uintprop_get(mp, src, DI_CCPROP, &code) == 0) {
3777aec1d6eScindi 		np->dp_class = GETCLASS(code);
3787aec1d6eScindi 		np->dp_subclass = GETSUBCLASS(code);
3797aec1d6eScindi 	} else {
3807aec1d6eScindi 		np->dp_class = -1;
3817aec1d6eScindi 	}
3827aec1d6eScindi 	/*
38349fbdd30SErwin T Tsaur 	 * There *may* be a device type we can capture.
3847aec1d6eScindi 	 */
38549fbdd30SErwin T Tsaur 	(void) di_devtype_get(mp, src, &np->dp_devtype);
3860db3240dSStephen Hanson 
3870db3240dSStephen Hanson 	if (irc >= 0) {
3880db3240dSStephen Hanson 		/*
3890db3240dSStephen Hanson 		 * This is a pciex node.
3900db3240dSStephen Hanson 		 */
391*106e8bd4SRob Johnston 		if (di_physlotinfo_get(mp, src, np->dp_bdf, &np->dp_physlot,
3920db3240dSStephen Hanson 		    &np->dp_physlot_name) < 0) {
3930db3240dSStephen Hanson 			if (np->dp_devtype != NULL)
3940db3240dSStephen Hanson 				topo_mod_strfree(mp, np->dp_devtype);
3950db3240dSStephen Hanson 			topo_mod_free(mp, np, sizeof (did_t));
3960db3240dSStephen Hanson 			return (NULL);
3970db3240dSStephen Hanson 		}
3980db3240dSStephen Hanson 	} else {
3990db3240dSStephen Hanson 		/*
4000db3240dSStephen Hanson 		 * This is a pci node.
4010db3240dSStephen Hanson 		 */
40205b58617SStephen Hanson 		np->dp_physlot = -1;
4030db3240dSStephen Hanson 		if (di_slotinfo_get(mp, src, &np->dp_nslots,
4040db3240dSStephen Hanson 		    &np->dp_slotnames) < 0) {
4050db3240dSStephen Hanson 			if (np->dp_devtype != NULL)
4060db3240dSStephen Hanson 				topo_mod_strfree(mp, np->dp_devtype);
4070db3240dSStephen Hanson 			topo_mod_free(mp, np, sizeof (did_t));
4080db3240dSStephen Hanson 			return (NULL);
4090db3240dSStephen Hanson 		}
4107aec1d6eScindi 	}
4110eb822a1Scindi 	did_hash_insert(mp, src, np);
4127aec1d6eScindi 	did_hold(np);
4137aec1d6eScindi 	return (np);
4147aec1d6eScindi }
4157aec1d6eScindi 
4167aec1d6eScindi did_t *
did_link_get(did_t * dp)4177aec1d6eScindi did_link_get(did_t *dp)
4187aec1d6eScindi {
4197aec1d6eScindi 	assert(dp != NULL);
4207aec1d6eScindi 	return (dp->dp_link);
4217aec1d6eScindi }
4227aec1d6eScindi 
4237aec1d6eScindi did_t *
did_chain_get(did_t * dp)4247aec1d6eScindi did_chain_get(did_t *dp)
4257aec1d6eScindi {
4267aec1d6eScindi 	assert(dp != NULL);
4277aec1d6eScindi 	return (dp->dp_chain);
4287aec1d6eScindi }
4297aec1d6eScindi 
4307aec1d6eScindi void
did_link_set(topo_mod_t * mod,tnode_t * head,did_t * tail)4310eb822a1Scindi did_link_set(topo_mod_t *mod, tnode_t *head, did_t *tail)
4327aec1d6eScindi {
4337aec1d6eScindi 	did_t *hd, *pd;
4347aec1d6eScindi 
4357aec1d6eScindi 	assert(head != NULL);
4360eb822a1Scindi 	pd = hd = did_find(mod, topo_node_getspecific(head));
4377aec1d6eScindi 	assert(hd != NULL);
4387aec1d6eScindi 	while ((hd = did_link_get(hd)) != NULL)
4397aec1d6eScindi 		pd = hd;
4407aec1d6eScindi 	pd->dp_link = tail;
4417aec1d6eScindi 	tail->dp_link = NULL;
4427aec1d6eScindi }
4437aec1d6eScindi 
4447aec1d6eScindi void
did_did_link_set(did_t * from,did_t * to)4457aec1d6eScindi did_did_link_set(did_t *from, did_t *to)
4467aec1d6eScindi {
4477aec1d6eScindi 	assert(from != NULL && to != NULL);
4487aec1d6eScindi 	from->dp_link = to;
4497aec1d6eScindi }
4507aec1d6eScindi 
4517aec1d6eScindi void
did_did_chain_set(did_t * from,did_t * to)4527aec1d6eScindi did_did_chain_set(did_t *from, did_t *to)
4537aec1d6eScindi {
4547aec1d6eScindi 	assert(from != NULL && to != NULL);
4557aec1d6eScindi 	from->dp_chain = to;
4567aec1d6eScindi }
4577aec1d6eScindi 
4587aec1d6eScindi void
did_destroy(did_t * dp)4597aec1d6eScindi did_destroy(did_t *dp)
4607aec1d6eScindi {
4617aec1d6eScindi 	assert(dp != NULL);
4627aec1d6eScindi 
4637aec1d6eScindi 	/*
4647aec1d6eScindi 	 * did_destroy() is called only from did_hash_destroy() when
4657aec1d6eScindi 	 * all references to the did_t have been released.  We can
4667aec1d6eScindi 	 * safely destroy the did_t.  If at some later time, more
4677aec1d6eScindi 	 * fine-grained reference count control is desired, this
4687aec1d6eScindi 	 * code will need to change
4697aec1d6eScindi 	 */
4707aec1d6eScindi 
47149fbdd30SErwin T Tsaur 	if (dp->dp_devtype != NULL)
47249fbdd30SErwin T Tsaur 		topo_mod_strfree(dp->dp_mod, dp->dp_devtype);
47360348818STarik Soydan 	if (dp->dp_physlot_name != NULL)
47460348818STarik Soydan 		topo_mod_strfree(dp->dp_mod, dp->dp_physlot_name);
47560348818STarik Soydan 	if (dp->dp_slot_label != NULL)
47660348818STarik Soydan 		topo_mod_strfree(dp->dp_mod, dp->dp_slot_label);
4777aec1d6eScindi 	slotnm_destroy(dp->dp_slotnames);
4787aec1d6eScindi 	topo_mod_free(dp->dp_mod, dp, sizeof (did_t));
4797aec1d6eScindi }
4807aec1d6eScindi 
4817aec1d6eScindi void
did_hold(did_t * dp)4827aec1d6eScindi did_hold(did_t *dp)
4837aec1d6eScindi {
4847aec1d6eScindi 	assert(dp != NULL);
4857aec1d6eScindi 	dp->dp_refcnt++;
4867aec1d6eScindi }
4877aec1d6eScindi 
4887aec1d6eScindi void
did_rele(did_t * dp)4897aec1d6eScindi did_rele(did_t *dp)
4907aec1d6eScindi {
4917aec1d6eScindi 	assert(dp != NULL);
4927aec1d6eScindi 	assert(dp->dp_refcnt > 0);
4937aec1d6eScindi 	dp->dp_refcnt--;
4947aec1d6eScindi }
4957aec1d6eScindi 
4967aec1d6eScindi di_node_t
did_dinode(did_t * dp)4977aec1d6eScindi did_dinode(did_t *dp)
4987aec1d6eScindi {
4997aec1d6eScindi 	assert(dp != NULL);
5007aec1d6eScindi 	assert(dp->dp_src != NULL);
5017aec1d6eScindi 	return (dp->dp_src);
5027aec1d6eScindi }
5037aec1d6eScindi 
5047aec1d6eScindi topo_mod_t *
did_mod(did_t * dp)5057aec1d6eScindi did_mod(did_t *dp)
5067aec1d6eScindi {
5077aec1d6eScindi 	assert(dp != NULL);
5087aec1d6eScindi 	return (dp->dp_mod);
5097aec1d6eScindi }
5107aec1d6eScindi 
5117aec1d6eScindi void
did_markrc(did_t * dp)5127aec1d6eScindi did_markrc(did_t *dp)
5137aec1d6eScindi {
5147aec1d6eScindi 	assert(dp != NULL);
5157aec1d6eScindi 	dp->dp_excap |= PCIE_PCIECAP_DEV_TYPE_ROOT;
5167aec1d6eScindi }
5177aec1d6eScindi 
5187aec1d6eScindi void
did_BDF(did_t * dp,int * bus,int * dev,int * fn)5197aec1d6eScindi did_BDF(did_t *dp, int *bus, int *dev, int *fn)
5207aec1d6eScindi {
5217aec1d6eScindi 	assert(dp != NULL);
5227aec1d6eScindi 	if (bus != NULL)
5237aec1d6eScindi 		*bus = dp->dp_bus;
5247aec1d6eScindi 	if (dev != NULL)
5257aec1d6eScindi 		*dev = dp->dp_dev;
5267aec1d6eScindi 	if (fn != NULL)
5277aec1d6eScindi 		*fn = dp->dp_fn;
5287aec1d6eScindi }
5297aec1d6eScindi 
5307aec1d6eScindi int
did_board(did_t * did)5317aec1d6eScindi did_board(did_t *did)
5327aec1d6eScindi {
5337aec1d6eScindi 	assert(did != NULL);
5347aec1d6eScindi 	return (did->dp_board);
5357aec1d6eScindi }
5367aec1d6eScindi 
5377aec1d6eScindi int
did_bridge(did_t * did)5387aec1d6eScindi did_bridge(did_t *did)
5397aec1d6eScindi {
5407aec1d6eScindi 	assert(did != NULL);
5417aec1d6eScindi 	return (did->dp_bridge);
5427aec1d6eScindi }
5437aec1d6eScindi 
5447aec1d6eScindi int
did_rc(did_t * did)5457aec1d6eScindi did_rc(did_t *did)
5467aec1d6eScindi {
5477aec1d6eScindi 	assert(did != NULL);
5487aec1d6eScindi 	return (did->dp_rc);
5497aec1d6eScindi }
5507aec1d6eScindi 
5517aec1d6eScindi int
did_excap(did_t * dp)5527aec1d6eScindi did_excap(did_t *dp)
5537aec1d6eScindi {
5547aec1d6eScindi 	assert(dp != NULL);
5557aec1d6eScindi 	return ((int)dp->dp_excap);
5567aec1d6eScindi }
5577aec1d6eScindi 
55849fbdd30SErwin T Tsaur void
did_excap_set(did_t * dp,int type)55949fbdd30SErwin T Tsaur did_excap_set(did_t *dp, int type)
56049fbdd30SErwin T Tsaur {
56149fbdd30SErwin T Tsaur 	dp->dp_excap = type;
56249fbdd30SErwin T Tsaur }
56349fbdd30SErwin T Tsaur 
56400d0963fSdilpreet int
did_bdf(did_t * dp)56500d0963fSdilpreet did_bdf(did_t *dp)
56600d0963fSdilpreet {
56700d0963fSdilpreet 	assert(dp != NULL);
56800d0963fSdilpreet 	return ((int)dp->dp_bdf);
56900d0963fSdilpreet }
57000d0963fSdilpreet 
5717aec1d6eScindi const char *
did_physlot_name(did_t * dp,int dev)57260348818STarik Soydan did_physlot_name(did_t *dp, int dev)
5737aec1d6eScindi {
5747aec1d6eScindi 	slotnm_t *slot;
5757aec1d6eScindi 
5767aec1d6eScindi 	assert(dp != NULL);
5770db3240dSStephen Hanson 
5780db3240dSStephen Hanson 	/*
5790db3240dSStephen Hanson 	 * For pciex, name will be in dp_physlot_name
5800db3240dSStephen Hanson 	 */
58160348818STarik Soydan 	if (dp->dp_physlot_name != NULL)
58260348818STarik Soydan 		return (dp->dp_physlot_name);
5830db3240dSStephen Hanson 
5840db3240dSStephen Hanson 	/*
5850db3240dSStephen Hanson 	 * For pci, name will be in dp_slotnames
5860db3240dSStephen Hanson 	 */
5877aec1d6eScindi 	for (slot = dp->dp_slotnames; slot != NULL; slot = slot->snm_next)
5887aec1d6eScindi 		if (slot->snm_dev == dev)
5897aec1d6eScindi 			break;
5907aec1d6eScindi 	if (slot != NULL)
59160348818STarik Soydan 		return (slot->snm_name);
5927aec1d6eScindi 	return (NULL);
5937aec1d6eScindi }
5947aec1d6eScindi 
59560348818STarik Soydan char *
did_slot_label_get(did_t * did)59660348818STarik Soydan did_slot_label_get(did_t *did)
59760348818STarik Soydan {
59860348818STarik Soydan 	assert(did != NULL);
59960348818STarik Soydan 	return (did->dp_slot_label);
60060348818STarik Soydan }
60160348818STarik Soydan 
60260348818STarik Soydan void
did_slot_label_set(did_t * did,char * l)60360348818STarik Soydan did_slot_label_set(did_t *did, char *l)
60460348818STarik Soydan {
60560348818STarik Soydan 	assert(did != NULL);
60660348818STarik Soydan 	did->dp_slot_label = l;
60760348818STarik Soydan }
60860348818STarik Soydan 
6097aec1d6eScindi did_t *
did_find(topo_mod_t * mp,di_node_t dn)6100eb822a1Scindi did_find(topo_mod_t *mp, di_node_t dn)
6117aec1d6eScindi {
6120eb822a1Scindi 	return (did_hash_lookup(mp, dn));
6137aec1d6eScindi }
6147aec1d6eScindi 
6157aec1d6eScindi int
pci_BDF_get(topo_mod_t * mp,di_node_t dn,int * bus,int * dev,int * fn)6160eb822a1Scindi pci_BDF_get(topo_mod_t *mp, di_node_t dn, int *bus, int *dev, int *fn)
6177aec1d6eScindi {
6187aec1d6eScindi 	did_t *dp;
6197aec1d6eScindi 
6200eb822a1Scindi 	if ((dp = did_find(mp, dn)) == NULL)
6217aec1d6eScindi 		return (-1);
6227aec1d6eScindi 	*bus = dp->dp_bus;
6237aec1d6eScindi 	*dev = dp->dp_dev;
6247aec1d6eScindi 	*fn = dp->dp_fn;
6257aec1d6eScindi 	did_rele(dp);
6267aec1d6eScindi 	return (0);
6277aec1d6eScindi }
6287aec1d6eScindi 
6297aec1d6eScindi int
pci_classcode_get(topo_mod_t * mp,di_node_t dn,uint_t * class,uint_t * sub)6300eb822a1Scindi pci_classcode_get(topo_mod_t *mp, di_node_t dn, uint_t *class, uint_t *sub)
6317aec1d6eScindi {
6327aec1d6eScindi 	did_t *dp;
6337aec1d6eScindi 
6340eb822a1Scindi 	if ((dp = did_find(mp, dn)) == NULL)
6357aec1d6eScindi 		return (-1);
6367aec1d6eScindi 	if (dp->dp_class < 0) {
6377aec1d6eScindi 		did_rele(dp);
6387aec1d6eScindi 		return (-1);
6397aec1d6eScindi 	}
6407aec1d6eScindi 	*class = dp->dp_class;
6417aec1d6eScindi 	*sub = dp->dp_subclass;
6427aec1d6eScindi 	did_rele(dp);
6437aec1d6eScindi 	return (0);
6447aec1d6eScindi }
6457aec1d6eScindi 
64649fbdd30SErwin T Tsaur char *
pci_devtype_get(topo_mod_t * mp,di_node_t dn)64749fbdd30SErwin T Tsaur pci_devtype_get(topo_mod_t *mp, di_node_t dn)
64849fbdd30SErwin T Tsaur {
64949fbdd30SErwin T Tsaur 	did_t *dp;
65049fbdd30SErwin T Tsaur 
65149fbdd30SErwin T Tsaur 	if ((dp = did_find(mp, dn)) == NULL)
65249fbdd30SErwin T Tsaur 		return (NULL);
65349fbdd30SErwin T Tsaur 	did_rele(dp);
65449fbdd30SErwin T Tsaur 	return (dp->dp_devtype);
65549fbdd30SErwin T Tsaur }
65649fbdd30SErwin T Tsaur 
6577aec1d6eScindi int
pciex_cap_get(topo_mod_t * mp,di_node_t dn)6580eb822a1Scindi pciex_cap_get(topo_mod_t *mp, di_node_t dn)
6597aec1d6eScindi {
6607aec1d6eScindi 	did_t *dp;
6617aec1d6eScindi 
6620eb822a1Scindi 	if ((dp = did_find(mp, dn)) == NULL)
6637aec1d6eScindi 		return (-1);
6647aec1d6eScindi 	did_rele(dp);
6657aec1d6eScindi 	return (dp->dp_excap);
6667aec1d6eScindi }
6677aec1d6eScindi 
6680eb822a1Scindi void
did_setspecific(topo_mod_t * mp,void * data)6690eb822a1Scindi did_setspecific(topo_mod_t *mp, void *data)
6700eb822a1Scindi {
6710eb822a1Scindi 	did_t *hbdid;
6720eb822a1Scindi 
6730eb822a1Scindi 	hbdid = (did_t *)data;
6740eb822a1Scindi 	topo_mod_setspecific(mp, hbdid->dp_hash);
6750eb822a1Scindi }
67640e5e17bSzx 
67740e5e17bSzx void
did_settnode(did_t * pd,tnode_t * tn)67840e5e17bSzx did_settnode(did_t *pd, tnode_t *tn)
67940e5e17bSzx {
68040e5e17bSzx 	assert(tn != NULL);
68140e5e17bSzx 	pd->dp_tnode = tn;
68240e5e17bSzx }
68340e5e17bSzx 
68440e5e17bSzx tnode_t *
did_gettnode(did_t * pd)68540e5e17bSzx did_gettnode(did_t *pd)
68640e5e17bSzx {
68740e5e17bSzx 	return (pd->dp_tnode);
68840e5e17bSzx }
689