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 /*
23*0db3240dSStephen Hanson  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
247aec1d6eScindi  */
257aec1d6eScindi 
267aec1d6eScindi /*
277aec1d6eScindi  * did.c
287aec1d6eScindi  *	The acronym did means "Dev-Info-Data".  Many properties and
297aec1d6eScindi  *	characteristics of topology nodes are, with a bit of coaxing
307aec1d6eScindi  *	derived from devinfo nodes.  These routines do some of the
317aec1d6eScindi  *	derivation and also encapsulate the discoveries in did_t
327aec1d6eScindi  *	structures that get associated with topology nodes as their
337aec1d6eScindi  *	"private" data.
347aec1d6eScindi  */
357aec1d6eScindi #include <alloca.h>
367aec1d6eScindi #include <assert.h>
377aec1d6eScindi #include <string.h>
387aec1d6eScindi #include <strings.h>
397aec1d6eScindi #include <sys/types.h>
400eb822a1Scindi #include <fm/topo_mod.h>
417aec1d6eScindi #include <libnvpair.h>
427aec1d6eScindi #include <libdevinfo.h>
437aec1d6eScindi #include <sys/pcie.h>
447aec1d6eScindi 
450eb822a1Scindi #include <hostbridge.h>
460eb822a1Scindi #include <pcibus.h>
470eb822a1Scindi #include <did_props.h>
480eb822a1Scindi 
497aec1d6eScindi #include "did_impl.h"
507aec1d6eScindi 
517aec1d6eScindi static void slotnm_destroy(slotnm_t *);
527aec1d6eScindi 
537aec1d6eScindi static slotnm_t *
547aec1d6eScindi slotnm_create(topo_mod_t *mp, int dev, char *str)
557aec1d6eScindi {
567aec1d6eScindi 	slotnm_t *p;
577aec1d6eScindi 
587aec1d6eScindi 	if ((p = topo_mod_alloc(mp, sizeof (slotnm_t))) == NULL)
597aec1d6eScindi 		return (NULL);
607aec1d6eScindi 	p->snm_mod = mp;
617aec1d6eScindi 	p->snm_next = NULL;
627aec1d6eScindi 	p->snm_dev = dev;
6360348818STarik Soydan 	p->snm_name = topo_mod_strdup(mp, str);
6460348818STarik Soydan 	if (p->snm_name == NULL) {
657aec1d6eScindi 		slotnm_destroy(p);
667aec1d6eScindi 		return (NULL);
677aec1d6eScindi 	}
687aec1d6eScindi 	return (p);
697aec1d6eScindi }
707aec1d6eScindi 
717aec1d6eScindi static void
727aec1d6eScindi slotnm_destroy(slotnm_t *p)
737aec1d6eScindi {
747aec1d6eScindi 	if (p == NULL)
757aec1d6eScindi 		return;
767aec1d6eScindi 	slotnm_destroy(p->snm_next);
7760348818STarik Soydan 	if (p->snm_name != NULL)
7860348818STarik Soydan 		topo_mod_strfree(p->snm_mod, p->snm_name);
797aec1d6eScindi 	topo_mod_free(p->snm_mod, p, sizeof (slotnm_t));
807aec1d6eScindi }
817aec1d6eScindi 
827aec1d6eScindi static int
8349fbdd30SErwin T Tsaur di_devtype_get(topo_mod_t *mp, di_node_t src, char **devtype)
847aec1d6eScindi {
850b6016e6Shueston 	int sz;
860b6016e6Shueston 	uchar_t *buf;
877aec1d6eScindi 
887aec1d6eScindi 	/*
8949fbdd30SErwin T Tsaur 	 * For PCI the device type defined the type of device directly below.
9049fbdd30SErwin T Tsaur 	 * For PCIe RP and Switches, the device-type should be "pciex".  For
9149fbdd30SErwin T Tsaur 	 * PCIe-PCI and PCI-PCI bridges it should be "pci".  NICs = "network",
9249fbdd30SErwin T Tsaur 	 * Graphics = "display", etc..
937aec1d6eScindi 	 */
9449fbdd30SErwin T Tsaur 	if (di_bytes_get(mp, src, DI_DEVTYPPROP, &sz, &buf) == 0) {
9549fbdd30SErwin T Tsaur 		*devtype = topo_mod_strdup(mp, (char *)buf);
9649fbdd30SErwin T Tsaur 	} else {
9749fbdd30SErwin T Tsaur 		*devtype = NULL;
987aec1d6eScindi 	}
9949fbdd30SErwin T Tsaur 
10049fbdd30SErwin T Tsaur 	if (*devtype != NULL)
10149fbdd30SErwin T Tsaur 		return (0);
10249fbdd30SErwin T Tsaur 	return (-1);
10349fbdd30SErwin T Tsaur }
10449fbdd30SErwin T Tsaur 
105*0db3240dSStephen Hanson typedef struct smbios_slot_cb {
106*0db3240dSStephen Hanson 	int		cb_slotnum;
107*0db3240dSStephen Hanson 	const char	*cb_label;
108*0db3240dSStephen Hanson } smbios_slot_cb_t;
109*0db3240dSStephen Hanson 
110*0db3240dSStephen Hanson static int
111*0db3240dSStephen Hanson di_smbios_find_slot(smbios_hdl_t *shp, const smbios_struct_t *strp, void *data)
112*0db3240dSStephen Hanson {
113*0db3240dSStephen Hanson 	smbios_slot_cb_t *cbp = data;
114*0db3240dSStephen Hanson 	smbios_slot_t slot;
115*0db3240dSStephen Hanson 
116*0db3240dSStephen Hanson 	if (strp->smbstr_type != SMB_TYPE_SLOT ||
117*0db3240dSStephen Hanson 	    smbios_info_slot(shp, strp->smbstr_id, &slot) != 0)
118*0db3240dSStephen Hanson 		return (0);
119*0db3240dSStephen Hanson 
120*0db3240dSStephen Hanson 	if (slot.smbl_id == cbp->cb_slotnum) {
121*0db3240dSStephen Hanson 		cbp->cb_label = slot.smbl_name;
122*0db3240dSStephen Hanson 		return (1);
123*0db3240dSStephen Hanson 	}
124*0db3240dSStephen Hanson 
125*0db3240dSStephen Hanson 	return (0);
126*0db3240dSStephen Hanson }
127*0db3240dSStephen Hanson 
12849fbdd30SErwin T Tsaur static int
12960348818STarik Soydan di_physlotinfo_get(topo_mod_t *mp, di_node_t src, int *slotnum, char **slotname)
13049fbdd30SErwin T Tsaur {
13149fbdd30SErwin T Tsaur 	char *slotbuf;
13249fbdd30SErwin T Tsaur 	int sz;
13349fbdd30SErwin T Tsaur 	uchar_t *buf;
134*0db3240dSStephen Hanson 	smbios_hdl_t *shp;
135*0db3240dSStephen Hanson 	boolean_t got_slotprop = B_FALSE;
13649fbdd30SErwin T Tsaur 
13749fbdd30SErwin T Tsaur 	*slotnum = -1;
13860348818STarik Soydan 
139*0db3240dSStephen Hanson 	(void) di_uintprop_get(mp, src, DI_PHYSPROP, (uint_t *)slotnum);
1407aec1d6eScindi 
1417aec1d6eScindi 	/*
1420b6016e6Shueston 	 * For PCI-Express, there is only one downstream device, so check for
1430b6016e6Shueston 	 * a slot-names property, and if it exists, ignore the slotmask value
1440b6016e6Shueston 	 * and use the string as the label.
1457aec1d6eScindi 	 */
1460eb822a1Scindi 	if (di_bytes_get(mp, src, DI_SLOTPROP, &sz, &buf) == 0 &&
147724365f7Ssethg 	    sz > 4) {
148*0db3240dSStephen Hanson 		/*
149*0db3240dSStephen Hanson 		 * If there is a DI_SLOTPROP of the form SlotX (ie set up from
150*0db3240dSStephen Hanson 		 * the IRQ routing table) then trust that in preference to
151*0db3240dSStephen Hanson 		 * DI_PHYSPROP (which is set up from the PCIe slotcap reg).
152*0db3240dSStephen Hanson 		 */
153*0db3240dSStephen Hanson 		got_slotprop = B_TRUE;
154*0db3240dSStephen Hanson 		(void) sscanf((char *)&buf[4], "Slot%d", slotnum);
155*0db3240dSStephen Hanson 	}
156*0db3240dSStephen Hanson 
157*0db3240dSStephen Hanson 	if (*slotnum == -1)
158*0db3240dSStephen Hanson 		return (0);
159*0db3240dSStephen Hanson 
160*0db3240dSStephen Hanson 	/*
161*0db3240dSStephen Hanson 	 * Order of preference
162*0db3240dSStephen Hanson 	 * 1) take slotnum and look up in SMBIOS table
163*0db3240dSStephen Hanson 	 * 2) use slot-names
164*0db3240dSStephen Hanson 	 * 3) fabricate name based on slotnum
165*0db3240dSStephen Hanson 	 */
166*0db3240dSStephen Hanson 	if ((shp = topo_mod_smbios(mp)) != NULL) {
167*0db3240dSStephen Hanson 		/*
168*0db3240dSStephen Hanson 		 * The PCI spec describes slot number 0 as reserved for
169*0db3240dSStephen Hanson 		 * internal PCI devices.  Not all platforms respect
170*0db3240dSStephen Hanson 		 * this, so we have to treat slot 0 as a valid device.
171*0db3240dSStephen Hanson 		 * But other platforms use 0 to identify an internal
172*0db3240dSStephen Hanson 		 * device.  We deal with this by letting SMBIOS be the
173*0db3240dSStephen Hanson 		 * final decision maker.  If SMBIOS is supported, but
174*0db3240dSStephen Hanson 		 * the given slot number is not represented in the
175*0db3240dSStephen Hanson 		 * SMBIOS tables, then ignore the slot entirely.
176*0db3240dSStephen Hanson 		 */
177*0db3240dSStephen Hanson 		smbios_slot_cb_t cbdata;
178*0db3240dSStephen Hanson 
179*0db3240dSStephen Hanson 		cbdata.cb_slotnum = *slotnum;
180*0db3240dSStephen Hanson 		cbdata.cb_label = NULL;
181*0db3240dSStephen Hanson 		if (smbios_iter(shp, di_smbios_find_slot, &cbdata) <= 0)
182*0db3240dSStephen Hanson 			return (0);
183*0db3240dSStephen Hanson 		slotbuf = (char *)cbdata.cb_label;
184*0db3240dSStephen Hanson 		topo_mod_dprintf(mp, "%s: node=%p: using smbios name\n",
185*0db3240dSStephen Hanson 		    __func__, src);
186*0db3240dSStephen Hanson 	} else if (got_slotprop == B_TRUE) {
1870b6016e6Shueston 		slotbuf = (char *)&buf[4];
188*0db3240dSStephen Hanson 		topo_mod_dprintf(mp, "%s: node=%p: found %s property\n",
189*0db3240dSStephen Hanson 		    __func__, src, DI_SLOTPROP);
1900b6016e6Shueston 	} else {
1910b6016e6Shueston 		/*
1920b6016e6Shueston 		 * Make generic description string "SLOT <num>", allow up to
1930b6016e6Shueston 		 * 10 digits for number
1940b6016e6Shueston 		 */
1950b6016e6Shueston 		slotbuf = alloca(16);
1960b6016e6Shueston 		(void) snprintf(slotbuf, 16, "SLOT %d", *slotnum);
197*0db3240dSStephen Hanson 		topo_mod_dprintf(mp, "%s: node=%p: using generic slot name\n",
198*0db3240dSStephen Hanson 		    __func__, src);
1990b6016e6Shueston 	}
20060348818STarik Soydan 	if ((*slotname = topo_mod_strdup(mp, slotbuf)) == NULL)
2017aec1d6eScindi 		return (-1);
2027aec1d6eScindi 
203*0db3240dSStephen Hanson 	topo_mod_dprintf(mp, "%s: node=%p: slotname=%s\n",
204*0db3240dSStephen Hanson 	    __func__, src, *slotname);
20560348818STarik Soydan 
2067aec1d6eScindi 	return (0);
2077aec1d6eScindi }
2087aec1d6eScindi 
2097aec1d6eScindi static int
21060348818STarik Soydan di_slotinfo_get(topo_mod_t *mp, di_node_t src, int *nslots,
21160348818STarik Soydan     slotnm_t **slotnames)
2127aec1d6eScindi {
2137aec1d6eScindi 	slotnm_t *lastslot = NULL;
2147aec1d6eScindi 	slotnm_t *newslot;
2157aec1d6eScindi 	uchar_t *slotbuf;
2167aec1d6eScindi 	uint_t slotmap = 0;
2177aec1d6eScindi 	char *slotname;
2187aec1d6eScindi 	int andbit;
2197aec1d6eScindi 	int sz = -1;
2207aec1d6eScindi 
22160348818STarik Soydan 	*slotnames = NULL;
2227aec1d6eScindi 	*nslots = 0;
2230eb822a1Scindi 	if (di_bytes_get(mp, src, DI_SLOTPROP, &sz, &slotbuf) < 0)
2247aec1d6eScindi 		return (0);
2257aec1d6eScindi 	if (sz < sizeof (uint_t))
2267aec1d6eScindi 		return (0);
2277aec1d6eScindi 	bcopy(slotbuf, &slotmap, sizeof (uint_t));
2287aec1d6eScindi 	if (slotmap == 0)
2297aec1d6eScindi 		return (0);
2307aec1d6eScindi 
2317aec1d6eScindi 	slotname = (char *)&slotbuf[4];
2327aec1d6eScindi 	for (andbit = 0; andbit < 32; andbit++) {
2337aec1d6eScindi 		if (slotmap & (1 << andbit)) {
2347aec1d6eScindi 			char *s = slotname;
2357aec1d6eScindi 			slotname += strlen(s) + 1;
2367aec1d6eScindi 			if ((newslot = slotnm_create(mp, andbit, s)) == NULL) {
23760348818STarik Soydan 				slotnm_destroy(*slotnames);
23860348818STarik Soydan 				*slotnames = NULL;
2397aec1d6eScindi 				*nslots = 0;
2407aec1d6eScindi 				return (-1);
2417aec1d6eScindi 			}
2427aec1d6eScindi 			if (lastslot == NULL)
24360348818STarik Soydan 				*slotnames = lastslot = newslot;
244c863ec5cSstephh 			else {
2457aec1d6eScindi 				lastslot->snm_next = newslot;
246c863ec5cSstephh 				lastslot = newslot;
247c863ec5cSstephh 			}
2487aec1d6eScindi 			(*nslots)++;
2497aec1d6eScindi 		}
2507aec1d6eScindi 	}
2517aec1d6eScindi 	return (0);
2527aec1d6eScindi }
2537aec1d6eScindi 
2547aec1d6eScindi int
25560348818STarik Soydan did_physlot(did_t *did)
2567aec1d6eScindi {
2577aec1d6eScindi 	assert(did != NULL);
2587aec1d6eScindi 	return (did->dp_physlot);
2597aec1d6eScindi }
2607aec1d6eScindi 
26160348818STarik Soydan int
26260348818STarik Soydan did_physlot_exists(did_t *did)
26360348818STarik Soydan {
26460348818STarik Soydan 	assert(did != NULL);
26560348818STarik Soydan 	return ((did->dp_physlot >= 0) || (did->dp_nslots > 0));
26660348818STarik Soydan }
26760348818STarik Soydan 
2687aec1d6eScindi did_t *
2690eb822a1Scindi did_create(topo_mod_t *mp, di_node_t src,
2700eb822a1Scindi     int ibrd, int ibrdge, int irc, int ibus)
2717aec1d6eScindi {
2727aec1d6eScindi 	did_t *np;
2737aec1d6eScindi 	did_t *pd;
2747aec1d6eScindi 	uint_t code;
2757aec1d6eScindi 	uint_t reg;
2767aec1d6eScindi 
2770eb822a1Scindi 	if ((pd = did_hash_lookup(mp, src)) != NULL) {
2787aec1d6eScindi 		topo_mod_dprintf(mp, "Attempt to create existing did_t.\n");
2797aec1d6eScindi 		assert(ibus == TRUST_BDF || (pd->dp_bus == ibus));
2807aec1d6eScindi 		return (pd);
2817aec1d6eScindi 	}
2827aec1d6eScindi 
2837aec1d6eScindi 	if ((np = topo_mod_zalloc(mp, sizeof (did_t))) == NULL)
2847aec1d6eScindi 		return (NULL);
2857aec1d6eScindi 	np->dp_mod = mp;
2867aec1d6eScindi 	np->dp_src = src;
2870eb822a1Scindi 	np->dp_hash = (did_hash_t *)topo_mod_getspecific(mp);
28840e5e17bSzx 	np->dp_tnode = NULL;
2897aec1d6eScindi 
2907aec1d6eScindi 	/*
2917aec1d6eScindi 	 * We must have a reg prop and from it we extract the bus #,
2927aec1d6eScindi 	 * device #, and function #.
2937aec1d6eScindi 	 */
2940eb822a1Scindi 	if (di_uintprop_get(mp, src, DI_REGPROP, &reg) < 0) {
2957aec1d6eScindi 		topo_mod_free(mp, np, sizeof (did_t));
2967aec1d6eScindi 		return (NULL);
2977aec1d6eScindi 	}
2987aec1d6eScindi 	np->dp_board = ibrd;
2997aec1d6eScindi 	np->dp_bridge = ibrdge;
3007aec1d6eScindi 	np->dp_rc = irc;
3017aec1d6eScindi 	if (ibus == TRUST_BDF)
3027aec1d6eScindi 		np->dp_bus = PCI_REG_BUS_G(reg);
3037aec1d6eScindi 	else
3047aec1d6eScindi 		np->dp_bus = ibus;
3057aec1d6eScindi 	np->dp_dev = PCI_REG_DEV_G(reg);
3067aec1d6eScindi 	np->dp_fn = PCI_REG_FUNC_G(reg);
30700d0963fSdilpreet 	np->dp_bdf = (PCI_REG_BUS_G(reg) << 8) | (PCI_REG_DEV_G(reg) << 3) |
30800d0963fSdilpreet 	    PCI_REG_FUNC_G(reg);
3097aec1d6eScindi 	/*
3107aec1d6eScindi 	 * There *may* be a class code we can capture.  If there wasn't
3117aec1d6eScindi 	 * one, capture that fact by setting the class value to -1.
3127aec1d6eScindi 	 */
3130eb822a1Scindi 	if (di_uintprop_get(mp, src, DI_CCPROP, &code) == 0) {
3147aec1d6eScindi 		np->dp_class = GETCLASS(code);
3157aec1d6eScindi 		np->dp_subclass = GETSUBCLASS(code);
3167aec1d6eScindi 	} else {
3177aec1d6eScindi 		np->dp_class = -1;
3187aec1d6eScindi 	}
3197aec1d6eScindi 	/*
32049fbdd30SErwin T Tsaur 	 * There *may* be a device type we can capture.
3217aec1d6eScindi 	 */
32249fbdd30SErwin T Tsaur 	(void) di_devtype_get(mp, src, &np->dp_devtype);
323*0db3240dSStephen Hanson 
324*0db3240dSStephen Hanson 	if (irc >= 0) {
325*0db3240dSStephen Hanson 		/*
326*0db3240dSStephen Hanson 		 * This is a pciex node.
327*0db3240dSStephen Hanson 		 */
328*0db3240dSStephen Hanson 		if (di_physlotinfo_get(mp, src, &np->dp_physlot,
329*0db3240dSStephen Hanson 		    &np->dp_physlot_name) < 0) {
330*0db3240dSStephen Hanson 			if (np->dp_devtype != NULL)
331*0db3240dSStephen Hanson 				topo_mod_strfree(mp, np->dp_devtype);
332*0db3240dSStephen Hanson 			topo_mod_free(mp, np, sizeof (did_t));
333*0db3240dSStephen Hanson 			return (NULL);
334*0db3240dSStephen Hanson 		}
335*0db3240dSStephen Hanson 	} else {
336*0db3240dSStephen Hanson 		/*
337*0db3240dSStephen Hanson 		 * This is a pci node.
338*0db3240dSStephen Hanson 		 */
339*0db3240dSStephen Hanson 		if (di_slotinfo_get(mp, src, &np->dp_nslots,
340*0db3240dSStephen Hanson 		    &np->dp_slotnames) < 0) {
341*0db3240dSStephen Hanson 			if (np->dp_devtype != NULL)
342*0db3240dSStephen Hanson 				topo_mod_strfree(mp, np->dp_devtype);
343*0db3240dSStephen Hanson 			topo_mod_free(mp, np, sizeof (did_t));
344*0db3240dSStephen Hanson 			return (NULL);
345*0db3240dSStephen Hanson 		}
3467aec1d6eScindi 	}
3470eb822a1Scindi 	did_hash_insert(mp, src, np);
3487aec1d6eScindi 	did_hold(np);
3497aec1d6eScindi 	return (np);
3507aec1d6eScindi }
3517aec1d6eScindi 
3527aec1d6eScindi did_t *
3537aec1d6eScindi did_link_get(did_t *dp)
3547aec1d6eScindi {
3557aec1d6eScindi 	assert(dp != NULL);
3567aec1d6eScindi 	return (dp->dp_link);
3577aec1d6eScindi }
3587aec1d6eScindi 
3597aec1d6eScindi did_t *
3607aec1d6eScindi did_chain_get(did_t *dp)
3617aec1d6eScindi {
3627aec1d6eScindi 	assert(dp != NULL);
3637aec1d6eScindi 	return (dp->dp_chain);
3647aec1d6eScindi }
3657aec1d6eScindi 
3667aec1d6eScindi void
3670eb822a1Scindi did_link_set(topo_mod_t *mod, tnode_t *head, did_t *tail)
3687aec1d6eScindi {
3697aec1d6eScindi 	did_t *hd, *pd;
3707aec1d6eScindi 
3717aec1d6eScindi 	assert(head != NULL);
3720eb822a1Scindi 	pd = hd = did_find(mod, topo_node_getspecific(head));
3737aec1d6eScindi 	assert(hd != NULL);
3747aec1d6eScindi 	while ((hd = did_link_get(hd)) != NULL)
3757aec1d6eScindi 		pd = hd;
3767aec1d6eScindi 	pd->dp_link = tail;
3777aec1d6eScindi 	tail->dp_link = NULL;
3787aec1d6eScindi }
3797aec1d6eScindi 
3807aec1d6eScindi void
3817aec1d6eScindi did_did_link_set(did_t *from, did_t *to)
3827aec1d6eScindi {
3837aec1d6eScindi 	assert(from != NULL && to != NULL);
3847aec1d6eScindi 	from->dp_link = to;
3857aec1d6eScindi }
3867aec1d6eScindi 
3877aec1d6eScindi void
3887aec1d6eScindi did_did_chain_set(did_t *from, did_t *to)
3897aec1d6eScindi {
3907aec1d6eScindi 	assert(from != NULL && to != NULL);
3917aec1d6eScindi 	from->dp_chain = to;
3927aec1d6eScindi }
3937aec1d6eScindi 
3947aec1d6eScindi void
3957aec1d6eScindi did_destroy(did_t *dp)
3967aec1d6eScindi {
3977aec1d6eScindi 	assert(dp != NULL);
3987aec1d6eScindi 
3997aec1d6eScindi 	/*
4007aec1d6eScindi 	 * did_destroy() is called only from did_hash_destroy() when
4017aec1d6eScindi 	 * all references to the did_t have been released.  We can
4027aec1d6eScindi 	 * safely destroy the did_t.  If at some later time, more
4037aec1d6eScindi 	 * fine-grained reference count control is desired, this
4047aec1d6eScindi 	 * code will need to change
4057aec1d6eScindi 	 */
4067aec1d6eScindi 
40749fbdd30SErwin T Tsaur 	if (dp->dp_devtype != NULL)
40849fbdd30SErwin T Tsaur 		topo_mod_strfree(dp->dp_mod, dp->dp_devtype);
40960348818STarik Soydan 	if (dp->dp_physlot_name != NULL)
41060348818STarik Soydan 		topo_mod_strfree(dp->dp_mod, dp->dp_physlot_name);
41160348818STarik Soydan 	if (dp->dp_slot_label != NULL)
41260348818STarik Soydan 		topo_mod_strfree(dp->dp_mod, dp->dp_slot_label);
4137aec1d6eScindi 	slotnm_destroy(dp->dp_slotnames);
4147aec1d6eScindi 	topo_mod_free(dp->dp_mod, dp, sizeof (did_t));
4157aec1d6eScindi }
4167aec1d6eScindi 
4177aec1d6eScindi void
4187aec1d6eScindi did_hold(did_t *dp)
4197aec1d6eScindi {
4207aec1d6eScindi 	assert(dp != NULL);
4217aec1d6eScindi 	dp->dp_refcnt++;
4227aec1d6eScindi }
4237aec1d6eScindi 
4247aec1d6eScindi void
4257aec1d6eScindi did_rele(did_t *dp)
4267aec1d6eScindi {
4277aec1d6eScindi 	assert(dp != NULL);
4287aec1d6eScindi 	assert(dp->dp_refcnt > 0);
4297aec1d6eScindi 	dp->dp_refcnt--;
4307aec1d6eScindi }
4317aec1d6eScindi 
4327aec1d6eScindi di_node_t
4337aec1d6eScindi did_dinode(did_t *dp)
4347aec1d6eScindi {
4357aec1d6eScindi 	assert(dp != NULL);
4367aec1d6eScindi 	assert(dp->dp_src != NULL);
4377aec1d6eScindi 	return (dp->dp_src);
4387aec1d6eScindi }
4397aec1d6eScindi 
4407aec1d6eScindi topo_mod_t *
4417aec1d6eScindi did_mod(did_t *dp)
4427aec1d6eScindi {
4437aec1d6eScindi 	assert(dp != NULL);
4447aec1d6eScindi 	return (dp->dp_mod);
4457aec1d6eScindi }
4467aec1d6eScindi 
4477aec1d6eScindi void
4487aec1d6eScindi did_markrc(did_t *dp)
4497aec1d6eScindi {
4507aec1d6eScindi 	assert(dp != NULL);
4517aec1d6eScindi 	dp->dp_excap |= PCIE_PCIECAP_DEV_TYPE_ROOT;
4527aec1d6eScindi }
4537aec1d6eScindi 
4547aec1d6eScindi void
4557aec1d6eScindi did_BDF(did_t *dp, int *bus, int *dev, int *fn)
4567aec1d6eScindi {
4577aec1d6eScindi 	assert(dp != NULL);
4587aec1d6eScindi 	if (bus != NULL)
4597aec1d6eScindi 		*bus = dp->dp_bus;
4607aec1d6eScindi 	if (dev != NULL)
4617aec1d6eScindi 		*dev = dp->dp_dev;
4627aec1d6eScindi 	if (fn != NULL)
4637aec1d6eScindi 		*fn = dp->dp_fn;
4647aec1d6eScindi }
4657aec1d6eScindi 
4667aec1d6eScindi int
4677aec1d6eScindi did_board(did_t *did)
4687aec1d6eScindi {
4697aec1d6eScindi 	assert(did != NULL);
4707aec1d6eScindi 	return (did->dp_board);
4717aec1d6eScindi }
4727aec1d6eScindi 
4737aec1d6eScindi int
4747aec1d6eScindi did_bridge(did_t *did)
4757aec1d6eScindi {
4767aec1d6eScindi 	assert(did != NULL);
4777aec1d6eScindi 	return (did->dp_bridge);
4787aec1d6eScindi }
4797aec1d6eScindi 
4807aec1d6eScindi int
4817aec1d6eScindi did_rc(did_t *did)
4827aec1d6eScindi {
4837aec1d6eScindi 	assert(did != NULL);
4847aec1d6eScindi 	return (did->dp_rc);
4857aec1d6eScindi }
4867aec1d6eScindi 
4877aec1d6eScindi int
4887aec1d6eScindi did_excap(did_t *dp)
4897aec1d6eScindi {
4907aec1d6eScindi 	assert(dp != NULL);
4917aec1d6eScindi 	return ((int)dp->dp_excap);
4927aec1d6eScindi }
4937aec1d6eScindi 
49449fbdd30SErwin T Tsaur void
49549fbdd30SErwin T Tsaur did_excap_set(did_t *dp, int type)
49649fbdd30SErwin T Tsaur {
49749fbdd30SErwin T Tsaur 	dp->dp_excap = type;
49849fbdd30SErwin T Tsaur }
49949fbdd30SErwin T Tsaur 
50000d0963fSdilpreet int
50100d0963fSdilpreet did_bdf(did_t *dp)
50200d0963fSdilpreet {
50300d0963fSdilpreet 	assert(dp != NULL);
50400d0963fSdilpreet 	return ((int)dp->dp_bdf);
50500d0963fSdilpreet }
50600d0963fSdilpreet 
5077aec1d6eScindi const char *
50860348818STarik Soydan did_physlot_name(did_t *dp, int dev)
5097aec1d6eScindi {
5107aec1d6eScindi 	slotnm_t *slot;
5117aec1d6eScindi 
5127aec1d6eScindi 	assert(dp != NULL);
513*0db3240dSStephen Hanson 
514*0db3240dSStephen Hanson 	/*
515*0db3240dSStephen Hanson 	 * For pciex, name will be in dp_physlot_name
516*0db3240dSStephen Hanson 	 */
51760348818STarik Soydan 	if (dp->dp_physlot_name != NULL)
51860348818STarik Soydan 		return (dp->dp_physlot_name);
519*0db3240dSStephen Hanson 
520*0db3240dSStephen Hanson 	/*
521*0db3240dSStephen Hanson 	 * For pci, name will be in dp_slotnames
522*0db3240dSStephen Hanson 	 */
5237aec1d6eScindi 	for (slot = dp->dp_slotnames; slot != NULL; slot = slot->snm_next)
5247aec1d6eScindi 		if (slot->snm_dev == dev)
5257aec1d6eScindi 			break;
5267aec1d6eScindi 	if (slot != NULL)
52760348818STarik Soydan 		return (slot->snm_name);
5287aec1d6eScindi 	return (NULL);
5297aec1d6eScindi }
5307aec1d6eScindi 
53160348818STarik Soydan char *
53260348818STarik Soydan did_slot_label_get(did_t *did)
53360348818STarik Soydan {
53460348818STarik Soydan 	assert(did != NULL);
53560348818STarik Soydan 	return (did->dp_slot_label);
53660348818STarik Soydan }
53760348818STarik Soydan 
53860348818STarik Soydan void
53960348818STarik Soydan did_slot_label_set(did_t *did, char *l)
54060348818STarik Soydan {
54160348818STarik Soydan 	assert(did != NULL);
54260348818STarik Soydan 	did->dp_slot_label = l;
54360348818STarik Soydan }
54460348818STarik Soydan 
5457aec1d6eScindi did_t *
5460eb822a1Scindi did_find(topo_mod_t *mp, di_node_t dn)
5477aec1d6eScindi {
5480eb822a1Scindi 	return (did_hash_lookup(mp, dn));
5497aec1d6eScindi }
5507aec1d6eScindi 
5517aec1d6eScindi int
5520eb822a1Scindi pci_BDF_get(topo_mod_t *mp, di_node_t dn, int *bus, int *dev, int *fn)
5537aec1d6eScindi {
5547aec1d6eScindi 	did_t *dp;
5557aec1d6eScindi 
5560eb822a1Scindi 	if ((dp = did_find(mp, dn)) == NULL)
5577aec1d6eScindi 		return (-1);
5587aec1d6eScindi 	*bus = dp->dp_bus;
5597aec1d6eScindi 	*dev = dp->dp_dev;
5607aec1d6eScindi 	*fn = dp->dp_fn;
5617aec1d6eScindi 	did_rele(dp);
5627aec1d6eScindi 	return (0);
5637aec1d6eScindi }
5647aec1d6eScindi 
5657aec1d6eScindi int
5660eb822a1Scindi pci_classcode_get(topo_mod_t *mp, di_node_t dn, uint_t *class, uint_t *sub)
5677aec1d6eScindi {
5687aec1d6eScindi 	did_t *dp;
5697aec1d6eScindi 
5700eb822a1Scindi 	if ((dp = did_find(mp, dn)) == NULL)
5717aec1d6eScindi 		return (-1);
5727aec1d6eScindi 	if (dp->dp_class < 0) {
5737aec1d6eScindi 		did_rele(dp);
5747aec1d6eScindi 		return (-1);
5757aec1d6eScindi 	}
5767aec1d6eScindi 	*class = dp->dp_class;
5777aec1d6eScindi 	*sub = dp->dp_subclass;
5787aec1d6eScindi 	did_rele(dp);
5797aec1d6eScindi 	return (0);
5807aec1d6eScindi }
5817aec1d6eScindi 
58249fbdd30SErwin T Tsaur char *
58349fbdd30SErwin T Tsaur pci_devtype_get(topo_mod_t *mp, di_node_t dn)
58449fbdd30SErwin T Tsaur {
58549fbdd30SErwin T Tsaur 	did_t *dp;
58649fbdd30SErwin T Tsaur 
58749fbdd30SErwin T Tsaur 	if ((dp = did_find(mp, dn)) == NULL)
58849fbdd30SErwin T Tsaur 		return (NULL);
58949fbdd30SErwin T Tsaur 	did_rele(dp);
59049fbdd30SErwin T Tsaur 	return (dp->dp_devtype);
59149fbdd30SErwin T Tsaur }
59249fbdd30SErwin T Tsaur 
5937aec1d6eScindi int
5940eb822a1Scindi pciex_cap_get(topo_mod_t *mp, di_node_t dn)
5957aec1d6eScindi {
5967aec1d6eScindi 	did_t *dp;
5977aec1d6eScindi 
5980eb822a1Scindi 	if ((dp = did_find(mp, dn)) == NULL)
5997aec1d6eScindi 		return (-1);
6007aec1d6eScindi 	did_rele(dp);
6017aec1d6eScindi 	return (dp->dp_excap);
6027aec1d6eScindi }
6037aec1d6eScindi 
6040eb822a1Scindi void
6050eb822a1Scindi did_setspecific(topo_mod_t *mp, void *data)
6060eb822a1Scindi {
6070eb822a1Scindi 	did_t *hbdid;
6080eb822a1Scindi 
6090eb822a1Scindi 	hbdid = (did_t *)data;
6100eb822a1Scindi 	topo_mod_setspecific(mp, hbdid->dp_hash);
6110eb822a1Scindi }
61240e5e17bSzx 
61340e5e17bSzx void
61440e5e17bSzx did_settnode(did_t *pd, tnode_t *tn)
61540e5e17bSzx {
61640e5e17bSzx 	assert(tn != NULL);
61740e5e17bSzx 	pd->dp_tnode = tn;
61840e5e17bSzx }
61940e5e17bSzx 
62040e5e17bSzx tnode_t *
62140e5e17bSzx did_gettnode(did_t *pd)
62240e5e17bSzx {
62340e5e17bSzx 	return (pd->dp_tnode);
62440e5e17bSzx }
625