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.
24106e8bd4SRob Johnston  * Copyright 2019 Joyent, Inc.
257aec1d6eScindi  */
267aec1d6eScindi 
2760348818STarik Soydan #include <alloca.h>
287aec1d6eScindi #include <assert.h>
2960348818STarik Soydan #include <fm/topo_mod.h>
3060348818STarik Soydan #include <libnvpair.h>
317aec1d6eScindi #include <string.h>
320eb822a1Scindi #include <sys/fm/protocol.h>
337aec1d6eScindi 
340eb822a1Scindi #include <did.h>
350eb822a1Scindi #include <pcibus.h>
360eb822a1Scindi #include <pcibus_labels.h>
377aec1d6eScindi 
387aec1d6eScindi extern slotnm_rewrite_t *Slot_Rewrites;
397aec1d6eScindi extern physlot_names_t *Physlot_Names;
407aec1d6eScindi extern missing_names_t *Missing_Names;
417aec1d6eScindi 
4260348818STarik Soydan /*
4360348818STarik Soydan  * Do a platform specific label lookup based on physical slot number.
4460348818STarik Soydan  */
457aec1d6eScindi static const char *
pci_label_physlot_lookup(topo_mod_t * mod,char * platform,did_t * dp)4660348818STarik Soydan pci_label_physlot_lookup(topo_mod_t *mod, char *platform, did_t *dp)
477aec1d6eScindi {
487aec1d6eScindi 	const char *rlabel = NULL;
497aec1d6eScindi 	int n, p, i;
507aec1d6eScindi 
51a4aef2baSTarik Soydan 	topo_mod_dprintf(mod, "%s: doing a lookup for platform=%s\n",
52a4aef2baSTarik Soydan 	    __func__, platform);
53a4aef2baSTarik Soydan 
5460348818STarik Soydan 	if ((n = did_physlot(dp)) < 0 || Physlot_Names == NULL ||
5594ed70baSzx 	    platform == NULL)
567aec1d6eScindi 		return (NULL);
577aec1d6eScindi 
58a4aef2baSTarik Soydan 	topo_mod_dprintf(mod, "%s: doing a lookup for physlot=%d\n",
59a4aef2baSTarik Soydan 	    __func__, n);
60a4aef2baSTarik Soydan 
617aec1d6eScindi 	for (p = 0; p < Physlot_Names->psn_nplats; p++) {
62a4aef2baSTarik Soydan 		topo_mod_dprintf(mod, "%s: comparing against platform=%s\n",
63a4aef2baSTarik Soydan 		    __func__, Physlot_Names->psn_names[p].pnm_platform);
640db3240dSStephen Hanson 		if (strcasecmp(Physlot_Names->psn_names[p].pnm_platform,
657aec1d6eScindi 		    platform) != 0)
667aec1d6eScindi 			continue;
67a4aef2baSTarik Soydan 		topo_mod_dprintf(mod, "%s: found lookup table for this "
68a4aef2baSTarik Soydan 		    "platform\n", __func__);
697aec1d6eScindi 		for (i = 0; i < Physlot_Names->psn_names[p].pnm_nnames; i++) {
707aec1d6eScindi 			physnm_t ps;
717aec1d6eScindi 			ps = Physlot_Names->psn_names[p].pnm_names[i];
727aec1d6eScindi 			if (ps.ps_num == n) {
73a4aef2baSTarik Soydan 				topo_mod_dprintf(mod, "%s: matched entry=%d, "
74a4aef2baSTarik Soydan 				    "label=%s\n", __func__, i, ps.ps_label);
757aec1d6eScindi 				rlabel = ps.ps_label;
767aec1d6eScindi 				break;
777aec1d6eScindi 			}
787aec1d6eScindi 		}
797aec1d6eScindi 		break;
807aec1d6eScindi 	}
8160348818STarik Soydan 	if (rlabel != NULL) {
82a4aef2baSTarik Soydan 		topo_mod_dprintf(mod, "%s: returning label=%s\n",
83a4aef2baSTarik Soydan 		    __func__, rlabel);
8460348818STarik Soydan 	}
857aec1d6eScindi 	return (rlabel);
867aec1d6eScindi }
877aec1d6eScindi 
8860348818STarik Soydan /*
8960348818STarik Soydan  * Do a platform specific label lookup based on slot name.
9060348818STarik Soydan  */
917aec1d6eScindi static const char *
pci_label_slotname_lookup(topo_mod_t * mod,char * platform,const char * label,did_t * dp)92a4aef2baSTarik Soydan pci_label_slotname_lookup(topo_mod_t *mod, char *platform,
93a4aef2baSTarik Soydan     const char *label, did_t *dp)
947aec1d6eScindi {
957aec1d6eScindi 	const char *rlabel = label;
96a4aef2baSTarik Soydan 	int s, i, ret;
977aec1d6eScindi 
98a4aef2baSTarik Soydan 	if (Slot_Rewrites == NULL || platform == NULL)
997aec1d6eScindi 		return (rlabel);
1007aec1d6eScindi 
101a4aef2baSTarik Soydan 	topo_mod_dprintf(mod, "%s: doing a lookup for platform=%s\n",
102a4aef2baSTarik Soydan 	    __func__, platform);
103a4aef2baSTarik Soydan 
1047aec1d6eScindi 	for (s = 0; s < Slot_Rewrites->srw_nplats; s++) {
105a4aef2baSTarik Soydan 		topo_mod_dprintf(mod, "%s: comparing against platform=%s\n",
106a4aef2baSTarik Soydan 		    __func__, Slot_Rewrites->srw_platrewrites[s].prw_platform);
1070db3240dSStephen Hanson 		if (strcasecmp(Slot_Rewrites->srw_platrewrites[s].prw_platform,
1087aec1d6eScindi 		    platform) != 0)
1097aec1d6eScindi 			continue;
110a4aef2baSTarik Soydan 		topo_mod_dprintf(mod, "%s: found lookup table for this "
111a4aef2baSTarik Soydan 		    "platform\n", __func__);
1127aec1d6eScindi 		for (i = 0;
1137aec1d6eScindi 		    i < Slot_Rewrites->srw_platrewrites[s].prw_nrewrites;
1147aec1d6eScindi 		    i++) {
1157aec1d6eScindi 			slot_rwd_t rw;
1167aec1d6eScindi 			rw = Slot_Rewrites->srw_platrewrites[s].prw_rewrites[i];
1177aec1d6eScindi 			if (strcmp(rw.srw_obp, label) == 0) {
118a4aef2baSTarik Soydan 				topo_mod_dprintf(mod, "%s: matched entry=%d, "
119a4aef2baSTarik Soydan 				    "old_label=%s, new_label=%s\n",
1200db3240dSStephen Hanson 				    __func__, i, rw.srw_obp,
1210db3240dSStephen Hanson 				    rw.srw_new ? rw.srw_new : NULL);
122a4aef2baSTarik Soydan 				/*
123a4aef2baSTarik Soydan 				 * If a test function is specified then call
124a4aef2baSTarik Soydan 				 * it to do an additional check.
125a4aef2baSTarik Soydan 				 */
126a4aef2baSTarik Soydan 				if (rw.srw_test != NULL) {
127a4aef2baSTarik Soydan 					topo_mod_dprintf(mod,
128a4aef2baSTarik Soydan 					    "%s: calling test function=%p\n",
129a4aef2baSTarik Soydan 					    __func__, rw.srw_test);
13058d4b16fSRobert Mustacchi 					if ((ret = rw.srw_test(mod, dp)) != 0)
131a4aef2baSTarik Soydan 						rlabel = rw.srw_new;
132a4aef2baSTarik Soydan 					topo_mod_dprintf(mod,
133a4aef2baSTarik Soydan 					    "%s: test function return=%d\n",
134a4aef2baSTarik Soydan 					    __func__, ret);
135a4aef2baSTarik Soydan 				} else {
136a4aef2baSTarik Soydan 					rlabel = rw.srw_new;
137a4aef2baSTarik Soydan 				}
1387aec1d6eScindi 				break;
1397aec1d6eScindi 			}
1407aec1d6eScindi 		}
1417aec1d6eScindi 		break;
1427aec1d6eScindi 	}
1430db3240dSStephen Hanson 	topo_mod_dprintf(mod, "%s: returning label=%s\n", __func__,
1440db3240dSStephen Hanson 	    rlabel ? rlabel : "NULL");
1457aec1d6eScindi 	return (rlabel);
1467aec1d6eScindi }
1477aec1d6eScindi 
14860348818STarik Soydan /*
14960348818STarik Soydan  * Do a platform specific label lookup based on bus, dev, etc.
15060348818STarik Soydan  */
1517aec1d6eScindi static const char *
pci_label_missing_lookup(topo_mod_t * mod,char * platform,did_t * dp)15260348818STarik Soydan pci_label_missing_lookup(topo_mod_t *mod, char *platform, did_t *dp)
1537aec1d6eScindi {
1547aec1d6eScindi 	const char *rlabel = NULL;
1557aec1d6eScindi 	int board, bridge, rc, bus, dev;
156a4aef2baSTarik Soydan 	int p, i, ret;
1577aec1d6eScindi 
158a4aef2baSTarik Soydan 	if (Missing_Names == NULL || platform == NULL)
1597aec1d6eScindi 		return (NULL);
160a4aef2baSTarik Soydan 
1617aec1d6eScindi 	bridge = did_bridge(dp);
1627aec1d6eScindi 	board = did_board(dp);
1637aec1d6eScindi 	rc = did_rc(dp);
1647aec1d6eScindi 	did_BDF(dp, &bus, &dev, NULL);
1657aec1d6eScindi 
166a4aef2baSTarik Soydan 	topo_mod_dprintf(mod, "%s: doing a lookup for platform=%s, "
167a4aef2baSTarik Soydan 	    "board=%d, bridge=%d, rc=%d, bus=%d, dev=%d\n",
168a4aef2baSTarik Soydan 	    __func__, platform, board, bridge, rc, bus, dev);
1697aec1d6eScindi 
1707aec1d6eScindi 	for (p = 0; p < Missing_Names->mn_nplats; p++) {
171a4aef2baSTarik Soydan 		topo_mod_dprintf(mod, "%s: comparing against platform=%s\n",
172a4aef2baSTarik Soydan 		    __func__, Missing_Names->mn_names[p].pdl_platform);
1730db3240dSStephen Hanson 		if (strcasecmp(Missing_Names->mn_names[p].pdl_platform,
1747aec1d6eScindi 		    platform) != 0)
1757aec1d6eScindi 			continue;
176a4aef2baSTarik Soydan 		topo_mod_dprintf(mod, "%s: found lookup table for this "
177a4aef2baSTarik Soydan 		    "platform\n", __func__);
1787aec1d6eScindi 		for (i = 0; i < Missing_Names->mn_names[p].pdl_nnames; i++) {
1797aec1d6eScindi 			devlab_t m;
1807aec1d6eScindi 			m = Missing_Names->mn_names[p].pdl_names[i];
1817aec1d6eScindi 			if (m.dl_board == board && m.dl_bridge == bridge &&
1820db3240dSStephen Hanson 			    m.dl_rc == rc &&
1830db3240dSStephen Hanson 			    (m.dl_bus == -1 || m.dl_bus == bus) &&
1840db3240dSStephen Hanson 			    (m.dl_dev == -1 || m.dl_dev == dev)) {
185a4aef2baSTarik Soydan 				topo_mod_dprintf(mod, "%s: matched entry=%d, "
186a4aef2baSTarik Soydan 				    "label=%s\n", __func__, i, m.dl_label);
187a4aef2baSTarik Soydan 				/*
188a4aef2baSTarik Soydan 				 * If a test function is specified then call
189a4aef2baSTarik Soydan 				 * it to do an additional test.
190a4aef2baSTarik Soydan 				 */
191a4aef2baSTarik Soydan 				if (m.dl_test != NULL) {
192a4aef2baSTarik Soydan 					topo_mod_dprintf(mod,
193a4aef2baSTarik Soydan 					    "%s: calling test function=%p\n",
194a4aef2baSTarik Soydan 					    __func__, m.dl_test);
19558d4b16fSRobert Mustacchi 					if ((ret = m.dl_test(mod, dp)) != 0)
196a4aef2baSTarik Soydan 						rlabel = m.dl_label;
197a4aef2baSTarik Soydan 					topo_mod_dprintf(mod,
198a4aef2baSTarik Soydan 					    "%s: test function return=%d\n",
199a4aef2baSTarik Soydan 					    __func__, ret);
2000db3240dSStephen Hanson 					if (ret)
2010db3240dSStephen Hanson 						break;
202a4aef2baSTarik Soydan 				} else {
203a4aef2baSTarik Soydan 					rlabel = m.dl_label;
2040db3240dSStephen Hanson 					break;
205a4aef2baSTarik Soydan 				}
2067aec1d6eScindi 			}
2077aec1d6eScindi 		}
2087aec1d6eScindi 		break;
2097aec1d6eScindi 	}
21060348818STarik Soydan 	if (rlabel != NULL) {
211a4aef2baSTarik Soydan 		topo_mod_dprintf(mod, "%s: match found, label=%s\n",
212a4aef2baSTarik Soydan 		    __func__, rlabel);
21360348818STarik Soydan 	}
2147aec1d6eScindi 	return (rlabel);
2157aec1d6eScindi }
2167aec1d6eScindi 
21760348818STarik Soydan /*
21860348818STarik Soydan  * Do an overall slot label lookup for the device node.
21960348818STarik Soydan  */
22060348818STarik Soydan char *
pci_slot_label_lookup(topo_mod_t * mod,tnode_t * node,did_t * dp,did_t * pdp)22160348818STarik Soydan pci_slot_label_lookup(topo_mod_t *mod, tnode_t *node, did_t *dp, did_t *pdp)
2227aec1d6eScindi {
22360348818STarik Soydan 	tnode_t *anode, *apnode;
22460348818STarik Soydan 	did_t *adp, *apdp;
22558d4b16fSRobert Mustacchi 	char *plat, *pp, *l = NULL, *ancestor_l = NULL, *new_l = NULL;
22660348818STarik Soydan 	int err, b, d, f, done = 0;
22760348818STarik Soydan 	size_t len;
2287aec1d6eScindi 
22960348818STarik Soydan 	did_BDF(dp, &b, &d, &f);
230a4aef2baSTarik Soydan 
231a4aef2baSTarik Soydan 	topo_mod_dprintf(mod, "%s: entry: node=%p, node_name=%s, "
232*6597d6fcSRobert Mustacchi 	    "node_inst=%" PRIu64 ", dp=%p, dp_bdf=%d/%d/%d, pdp=%p\n",
233a4aef2baSTarik Soydan 	    __func__, node, topo_node_name(node), topo_node_instance(node),
234a4aef2baSTarik Soydan 	    dp, b, d, f, pdp);
23560348818STarik Soydan 
23660348818STarik Soydan 	/*
23760348818STarik Soydan 	 * If this device has a physical slot number then check if
23860348818STarik Soydan 	 * an ancestor also has a slot label.
23960348818STarik Soydan 	 *
24060348818STarik Soydan 	 * If an ancestor has a slot label, then this node's label
24160348818STarik Soydan 	 * is generated by concatenating a default label onto the
24260348818STarik Soydan 	 * ancestor's label.
24360348818STarik Soydan 	 *
24460348818STarik Soydan 	 * We grab pairs of ancestors (parent and child) as we go up
24560348818STarik Soydan 	 * the tree because the parent is checked for the presence
24660348818STarik Soydan 	 * of a slot while the child contains the label.
24760348818STarik Soydan 	 *
24860348818STarik Soydan 	 * Note that this algorithm only applies to nodes which have
249106e8bd4SRob Johnston 	 * a physical slot number. (i.e. PCIE devices or PCI/PCIX
25060348818STarik Soydan 	 * devices off of a PCIE to PCIX switch)
25160348818STarik Soydan 	 */
25260348818STarik Soydan 	if (did_physlot(pdp) >= 0) {
25360348818STarik Soydan 
254a4aef2baSTarik Soydan 		topo_mod_dprintf(mod, "%s: node=%p: node has a physical "
255a4aef2baSTarik Soydan 		    "slot=%d, checking ancestors for slots\n",
256a4aef2baSTarik Soydan 		    __func__, node, did_physlot(pdp));
25760348818STarik Soydan 
25860348818STarik Soydan 		/*
25960348818STarik Soydan 		 * Get this device's physical slot name.
26060348818STarik Soydan 		 */
26160348818STarik Soydan 		l = (char *)did_physlot_name(pdp, d);
26260348818STarik Soydan 		anode = topo_node_parent(node);
26360348818STarik Soydan 
26460348818STarik Soydan 		/*
26560348818STarik Soydan 		 * Check ancestors for a slot label until we
26660348818STarik Soydan 		 * either find one or hit a non-pci device.
26760348818STarik Soydan 		 */
26860348818STarik Soydan 		while (!done) {
26960348818STarik Soydan 
27060348818STarik Soydan 			/*
27160348818STarik Soydan 			 * Get next ancestor node and data pointers.
27260348818STarik Soydan 			 */
27360348818STarik Soydan 			anode = topo_node_parent(anode);
27460348818STarik Soydan 			if (anode != NULL) {
27560348818STarik Soydan 				adp = did_find(mod,
27660348818STarik Soydan 				    topo_node_getspecific(anode));
27760348818STarik Soydan 				apnode = topo_node_parent(anode);
27860348818STarik Soydan 				if (apnode != NULL)
27960348818STarik Soydan 					apdp = did_find(mod,
28060348818STarik Soydan 					    topo_node_getspecific(apnode));
28160348818STarik Soydan 				else
28260348818STarik Soydan 					apdp = NULL;
28360348818STarik Soydan 			} else {
28460348818STarik Soydan 				apnode = NULL;
28560348818STarik Soydan 				apdp = adp = NULL;
28660348818STarik Soydan 			}
28760348818STarik Soydan 
288a4aef2baSTarik Soydan 			topo_mod_dprintf(mod, "%s: node=%p: checking next "
289a4aef2baSTarik Soydan 			    "two ancestors: anode=%p, adp=%p "
290a4aef2baSTarik Soydan 			    "apnode=%p, apdp=%p\n",
291a4aef2baSTarik Soydan 			    __func__, node, anode, adp, apnode, apdp);
29260348818STarik Soydan 			if ((anode != NULL) && (adp != NULL)) {
29360348818STarik Soydan 				did_BDF(adp, &b, &d, &f);
294a4aef2baSTarik Soydan 				topo_mod_dprintf(mod, "%s: node=%p: "
295*6597d6fcSRobert Mustacchi 				    "anode_name=%s[%" PRIu64 "], "
296*6597d6fcSRobert Mustacchi 				    "anode_bdf=%d/%d/%d\n", __func__, node,
297*6597d6fcSRobert Mustacchi 				    topo_node_name(anode),
29860348818STarik Soydan 				    topo_node_instance(anode), b, d, f);
29960348818STarik Soydan 			}
30060348818STarik Soydan 			if ((apnode != NULL) && (apdp != NULL)) {
30160348818STarik Soydan 				did_BDF(apdp, &b, &d, &f);
302a4aef2baSTarik Soydan 				topo_mod_dprintf(mod, "%s: node=%p: "
303*6597d6fcSRobert Mustacchi 				    "apnode_name=%s[%" PRIu64 "], "
30460348818STarik Soydan 				    "apnode_bdf=%d/%d/%d\n",
305a4aef2baSTarik Soydan 				    __func__, node, topo_node_name(apnode),
30660348818STarik Soydan 				    topo_node_instance(apnode), b, d, f);
30760348818STarik Soydan 			}
30860348818STarik Soydan 
30960348818STarik Soydan 			/*
31060348818STarik Soydan 			 * If the ancestors do not exist or are not pci
31160348818STarik Soydan 			 * devices then we're done searching.
31260348818STarik Soydan 			 *
31360348818STarik Soydan 			 * Otherwise, if the ancestor has a physical slot,
31460348818STarik Soydan 			 * and it is a different slot than the one we
31560348818STarik Soydan 			 * started with then lookup the ancestor label,
31660348818STarik Soydan 			 * and we're done.
31760348818STarik Soydan 			 */
31860348818STarik Soydan 			if ((anode == NULL) || (adp == NULL) ||
31960348818STarik Soydan 			    (apnode == NULL) || (apdp == NULL)) {
32060348818STarik Soydan 				done++;
32160348818STarik Soydan 			} else if (did_physlot_exists(apdp) &&
32260348818STarik Soydan 			    (apdp != pdp)) {
32360348818STarik Soydan 				if (topo_node_label(anode, &ancestor_l,
32460348818STarik Soydan 				    &err) != 0) {
32560348818STarik Soydan 					topo_mod_dprintf(mod,
326a4aef2baSTarik Soydan 					    "%s: node=%p: topo_node_label() "
327a4aef2baSTarik Soydan 					    "FAILED!", __func__, node);
32860348818STarik Soydan 					(void) topo_mod_seterrno(mod, err);
32960348818STarik Soydan 					return (NULL);
33060348818STarik Soydan 				}
33160348818STarik Soydan 				done++;
332a4aef2baSTarik Soydan 				topo_mod_dprintf(mod, "%s: node=%p: found "
333a4aef2baSTarik Soydan 				    "ancestor with a slot, label=%s ",
334a4aef2baSTarik Soydan 				    __func__, node, ancestor_l);
33560348818STarik Soydan 			}
33660348818STarik Soydan 		}
33760348818STarik Soydan 		if (ancestor_l == NULL) {
338a4aef2baSTarik Soydan 			topo_mod_dprintf(mod, "%s: node=%p: no ancestor "
339a4aef2baSTarik Soydan 			    "slot found\n", __func__, node);
34060348818STarik Soydan 		}
3417aec1d6eScindi 	}
3420eb822a1Scindi 
3430eb822a1Scindi 	/*
34460348818STarik Soydan 	 * If we found an ancestor with a slot label, and this node has
34560348818STarik Soydan 	 * a physical slot number label then concatenate the two to form
34660348818STarik Soydan 	 * this node's label. Otherwise, do a full slot label lookup.
3470eb822a1Scindi 	 */
34860348818STarik Soydan 	if (ancestor_l && l) {
349a4aef2baSTarik Soydan 		topo_mod_dprintf(mod, "%s: node=%p: concatenating "
350a4aef2baSTarik Soydan 		    "ancestor_l=%s and l=%s\n",
351a4aef2baSTarik Soydan 		    __func__, node, ancestor_l, l);
35260348818STarik Soydan 		len = strlen(ancestor_l) + strlen(l) + 2;
35360348818STarik Soydan 		new_l = alloca(len);
35460348818STarik Soydan 		(void) snprintf(new_l, len, "%s/%s", ancestor_l, l);
35560348818STarik Soydan 		l = new_l;
35660348818STarik Soydan 	} else {
35760348818STarik Soydan 		/*
35860348818STarik Soydan 		 * Get platform name used for lookups.
35960348818STarik Soydan 		 */
36060348818STarik Soydan 		if (topo_prop_get_string(node, FM_FMRI_AUTHORITY,
36160348818STarik Soydan 		    FM_FMRI_AUTH_PRODUCT, &plat, &err) < 0) {
36260348818STarik Soydan 			(void) topo_mod_seterrno(mod, err);
36360348818STarik Soydan 			return (NULL);
36460348818STarik Soydan 		}
36560348818STarik Soydan 		/*
36660348818STarik Soydan 		 * Trim SUNW, from the platform name
36760348818STarik Soydan 		 */
36860348818STarik Soydan 		pp = strchr(plat, ',');
36960348818STarik Soydan 		if (pp == NULL)
37060348818STarik Soydan 			pp = plat;
37160348818STarik Soydan 		else
37260348818STarik Soydan 			++pp;
37360348818STarik Soydan 		/*
37460348818STarik Soydan 		 * Get device number used for lookup.
37560348818STarik Soydan 		 */
37660348818STarik Soydan 		did_BDF(dp, NULL, &d, NULL);
37760348818STarik Soydan 
37860348818STarik Soydan 		/*
37960348818STarik Soydan 		 * The slot label is determined in the following order:
38060348818STarik Soydan 		 * - Platform specific lookup based on physical slot #.
38160348818STarik Soydan 		 * - Platform specific lookup based on default label string.
38260348818STarik Soydan 		 * - Platform specific lookup based on device number.
38360348818STarik Soydan 		 * - Default label.
38460348818STarik Soydan 		 *   The default label is based on the slot names property
38560348818STarik Soydan 		 *   if it exists, else it is a generic name derived from
38660348818STarik Soydan 		 *   the slot #.
38760348818STarik Soydan 		 */
38860348818STarik Soydan 		if ((l = (char *)pci_label_physlot_lookup(mod, pp, pdp))
38960348818STarik Soydan 		    == NULL) {
390106e8bd4SRob Johnston 			if ((l = (char *)did_physlot_name(dp, d)) != NULL) {
39160348818STarik Soydan 				l = (char *)
392a4aef2baSTarik Soydan 				    pci_label_slotname_lookup(mod, pp, l, dp);
3930db3240dSStephen Hanson 			}
3940db3240dSStephen Hanson 			if (l == NULL) {
39560348818STarik Soydan 				l = (char *)
39660348818STarik Soydan 				    pci_label_missing_lookup(mod, pp, dp);
39760348818STarik Soydan 			}
3987aec1d6eScindi 		}
39960348818STarik Soydan 		topo_mod_strfree(mod, plat);
40060348818STarik Soydan 	}
40160348818STarik Soydan 
40260348818STarik Soydan 	/*
40360348818STarik Soydan 	 * If we calculated a slot label,  then save it in the
40460348818STarik Soydan 	 * node's data structure so we can free it later.
40560348818STarik Soydan 	 */
40660348818STarik Soydan 	if (l) {
40760348818STarik Soydan 		if (did_slot_label_get(dp) != NULL)
40860348818STarik Soydan 			topo_mod_strfree(mod, did_slot_label_get(dp));
40960348818STarik Soydan 		l = topo_mod_strdup(mod, l);
41060348818STarik Soydan 		did_slot_label_set(dp, l);
41160348818STarik Soydan 	}
41260348818STarik Soydan 
413a4aef2baSTarik Soydan 	topo_mod_dprintf(mod, "%s: exit: node=%p: label=%s\n",
414a4aef2baSTarik Soydan 	    __func__, node, (l ? l : "NULL"));
41560348818STarik Soydan 
4167aec1d6eScindi 	return (l);
4177aec1d6eScindi }
4187aec1d6eScindi 
4197aec1d6eScindi int
pci_label_cmn(topo_mod_t * mod,tnode_t * node,nvlist_t * in,nvlist_t ** out)4200eb822a1Scindi pci_label_cmn(topo_mod_t *mod, tnode_t *node, nvlist_t *in, nvlist_t **out)
4217aec1d6eScindi {
4227aec1d6eScindi 	uint64_t ptr;
42360348818STarik Soydan 	char *l;
424e5ba14ffSstephh 	did_t *dp, *pdp;
425e5ba14ffSstephh 	tnode_t *pnode;
4267aec1d6eScindi 	char *nm;
4277aec1d6eScindi 	int err;
4287aec1d6eScindi 
4297aec1d6eScindi 	/*
43000d0963fSdilpreet 	 * If it's not a device or a PCI-express bus (which could potentially
43100d0963fSdilpreet 	 * represent a slot, and therefore we might need to capture its slot
43200d0963fSdilpreet 	 * name information), just inherit any label from our parent
4337aec1d6eScindi 	 */
4347aec1d6eScindi 	*out = NULL;
4357aec1d6eScindi 	nm = topo_node_name(node);
43600d0963fSdilpreet 	if (strcmp(nm, PCI_DEVICE) != 0 && strcmp(nm, PCIEX_DEVICE) != 0 &&
43700d0963fSdilpreet 	    strcmp(nm, PCIEX_BUS) != 0) {
4387aec1d6eScindi 		if (topo_node_label_set(node, NULL, &err) < 0)
4397aec1d6eScindi 			if (err != ETOPO_PROP_NOENT)
440724365f7Ssethg 				return (topo_mod_seterrno(mod, err));
4417aec1d6eScindi 		return (0);
4427aec1d6eScindi 	}
4437aec1d6eScindi 
4447aec1d6eScindi 	if (nvlist_lookup_uint64(in, TOPO_METH_LABEL_ARG_NVL, &ptr) != 0) {
445724365f7Ssethg 		topo_mod_dprintf(mod,
446a4aef2baSTarik Soydan 		    "%s: label method argument not found.\n", __func__);
4477aec1d6eScindi 		return (-1);
4487aec1d6eScindi 	}
44980ab886dSwesolows 	dp = (did_t *)(uintptr_t)ptr;
450e5ba14ffSstephh 	pnode = did_gettnode(dp);
451e5ba14ffSstephh 	pdp = did_find(mod, topo_node_getspecific(pnode));
4527aec1d6eScindi 
4537aec1d6eScindi 	/*
45460348818STarik Soydan 	 * Is there a slot label associated with the device?
4557aec1d6eScindi 	 */
45660348818STarik Soydan 	if ((l = pci_slot_label_lookup(mod, node, dp, pdp)) != NULL) {
4577aec1d6eScindi 		nvlist_t *rnvl;
4587aec1d6eScindi 
459724365f7Ssethg 		if (topo_mod_nvalloc(mod, &rnvl, NV_UNIQUE_NAME) != 0 ||
4607aec1d6eScindi 		    nvlist_add_string(rnvl, TOPO_METH_LABEL_RET_STR, l) != 0)
461724365f7Ssethg 			return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
4627aec1d6eScindi 		*out = rnvl;
4637aec1d6eScindi 		return (0);
4647aec1d6eScindi 	} else {
4657aec1d6eScindi 		if (topo_node_label_set(node, NULL, &err) < 0)
4667aec1d6eScindi 			if (err != ETOPO_PROP_NOENT)
467724365f7Ssethg 				return (topo_mod_seterrno(mod, err));
4687aec1d6eScindi 		return (0);
4697aec1d6eScindi 	}
4707aec1d6eScindi }
471e5ba14ffSstephh 
472e5ba14ffSstephh int
pci_fru_cmn(topo_mod_t * mod,tnode_t * node,nvlist_t * in,nvlist_t ** out)473e5ba14ffSstephh pci_fru_cmn(topo_mod_t *mod, tnode_t *node, nvlist_t *in, nvlist_t **out)
474e5ba14ffSstephh {
475e5ba14ffSstephh 	int err = 0;
476e5ba14ffSstephh 	uint64_t ptr;
477e5ba14ffSstephh 	did_t *dp, *pdp;
478e5ba14ffSstephh 	tnode_t *pnode;
479e5ba14ffSstephh 	char *nm;
480e5ba14ffSstephh 
481e5ba14ffSstephh 	*out = NULL;
482e5ba14ffSstephh 	nm = topo_node_name(node);
483d4c0a8c5Sstephh 	if (strcmp(nm, PCI_DEVICE) != 0 && strcmp(nm, PCIEX_DEVICE) != 0 &&
484d4c0a8c5Sstephh 	    strcmp(nm, PCIEX_BUS) != 0)
485e5ba14ffSstephh 		return (0);
486e5ba14ffSstephh 
487e5ba14ffSstephh 	if (nvlist_lookup_uint64(in, "nv1", &ptr) != 0) {
488e5ba14ffSstephh 		topo_mod_dprintf(mod,
489a4aef2baSTarik Soydan 		    "%s: label method argument not found.\n", __func__);
490e5ba14ffSstephh 		return (-1);
491e5ba14ffSstephh 	}
492e5ba14ffSstephh 	dp = (did_t *)(uintptr_t)ptr;
493e5ba14ffSstephh 	pnode = did_gettnode(dp);
494e5ba14ffSstephh 	pdp = did_find(mod, topo_node_getspecific(pnode));
495e5ba14ffSstephh 
496e5ba14ffSstephh 	/*
49760348818STarik Soydan 	 * Is there a slot label associated with the device?
498e5ba14ffSstephh 	 */
49960348818STarik Soydan 	if (pci_slot_label_lookup(mod, pnode, dp, pdp) != NULL) {
500e5ba14ffSstephh 		nvlist_t *rnvl;
501e5ba14ffSstephh 
502e5ba14ffSstephh 		if (topo_node_resource(node, &rnvl, &err) < 0 || rnvl == NULL) {
503a4aef2baSTarik Soydan 			topo_mod_dprintf(mod, "%s: error: %s\n",
504a4aef2baSTarik Soydan 			    __func__, topo_strerror(topo_mod_errno(mod)));
505e5ba14ffSstephh 			return (topo_mod_seterrno(mod, err));
506e5ba14ffSstephh 		}
507e5ba14ffSstephh 		*out = rnvl;
508e5ba14ffSstephh 	}
509e5ba14ffSstephh 	return (0);
510e5ba14ffSstephh }
511