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, ®) < 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