1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <libnvpair.h>
30 #include <fm/topo_mod.h>
31 #include <assert.h>
32 #include <string.h>
33 #include <sys/fm/protocol.h>
34 
35 #include <did.h>
36 #include <pcibus.h>
37 #include <pcibus_labels.h>
38 
39 extern slotnm_rewrite_t *Slot_Rewrites;
40 extern physlot_names_t *Physlot_Names;
41 extern missing_names_t *Missing_Names;
42 
43 static const char *
44 pci_physslot_name_lookup(char *platform, did_t *dp)
45 {
46 	const char *rlabel = NULL;
47 	int n, p, i;
48 
49 	if ((n = did_physslot(dp)) < 0 || Physlot_Names == NULL)
50 		return (NULL);
51 
52 	for (p = 0; p < Physlot_Names->psn_nplats; p++) {
53 		if (strcmp(Physlot_Names->psn_names[p].pnm_platform,
54 		    platform) != 0)
55 			continue;
56 		for (i = 0; i < Physlot_Names->psn_names[p].pnm_nnames; i++) {
57 			physnm_t ps;
58 			ps = Physlot_Names->psn_names[p].pnm_names[i];
59 			if (ps.ps_num == n) {
60 				rlabel = ps.ps_label;
61 				break;
62 			}
63 		}
64 		break;
65 	}
66 	return (rlabel);
67 }
68 
69 static const char *
70 pci_slotname_rewrite(char *platform, const char *label)
71 {
72 	const char *rlabel = label;
73 	int s, i;
74 
75 	if (Slot_Rewrites == NULL)
76 		return (rlabel);
77 
78 	for (s = 0; s < Slot_Rewrites->srw_nplats; s++) {
79 		if (strcmp(Slot_Rewrites->srw_platrewrites[s].prw_platform,
80 		    platform) != 0)
81 			continue;
82 		for (i = 0;
83 		    i < Slot_Rewrites->srw_platrewrites[s].prw_nrewrites;
84 		    i++) {
85 			slot_rwd_t rw;
86 			rw = Slot_Rewrites->srw_platrewrites[s].prw_rewrites[i];
87 			if (strcmp(rw.srw_obp, label) == 0) {
88 				rlabel = rw.srw_new;
89 				break;
90 			}
91 		}
92 		break;
93 	}
94 	assert(rlabel != NULL);
95 	return (rlabel);
96 }
97 
98 static const char *
99 pci_missing_match(topo_mod_t *mod, char *platform, did_t *dp)
100 {
101 	const char *rlabel = NULL;
102 	int board, bridge, rc, bus, dev;
103 	int p, i;
104 
105 	if (Missing_Names == NULL)
106 		return (NULL);
107 	bridge = did_bridge(dp);
108 	board = did_board(dp);
109 	rc = did_rc(dp);
110 	did_BDF(dp, &bus, &dev, NULL);
111 
112 	topo_mod_dprintf(mod, "Missing a name for %d, %d, %d, %d, %d ?\n",
113 	    board, bridge, rc, bus, dev);
114 
115 	for (p = 0; p < Missing_Names->mn_nplats; p++) {
116 		if (strcmp(Missing_Names->mn_names[p].pdl_platform,
117 		    platform) != 0)
118 			continue;
119 		for (i = 0; i < Missing_Names->mn_names[p].pdl_nnames; i++) {
120 			devlab_t m;
121 			m = Missing_Names->mn_names[p].pdl_names[i];
122 			if (m.dl_board == board && m.dl_bridge == bridge &&
123 			    m.dl_rc == rc && m.dl_bus == bus &&
124 			    m.dl_dev == dev) {
125 				rlabel = m.dl_label;
126 				break;
127 			}
128 		}
129 		break;
130 	}
131 	return (rlabel);
132 }
133 
134 static const char *
135 pci_slotname_lookup(topo_mod_t *mod, tnode_t *node, did_t *dp)
136 {
137 	const char *l;
138 	char *plat, *pp;
139 	int err;
140 	int d;
141 
142 	if (topo_prop_get_string(node,
143 	    FM_FMRI_AUTHORITY, FM_FMRI_AUTH_PRODUCT, &plat, &err) < 0) {
144 		(void) topo_mod_seterrno(mod, err);
145 		return (NULL);
146 	}
147 
148 	/*
149 	 * Trim SUNW, from the platform name
150 	 */
151 	pp = strchr(plat, ',');
152 	++pp;
153 
154 	did_BDF(dp, NULL, &d, NULL);
155 	if ((l = pci_physslot_name_lookup(pp, dp)) == NULL)
156 		if ((l = did_label(dp, d)) != NULL) {
157 			l = pci_slotname_rewrite(pp, l);
158 		} else {
159 			l = pci_missing_match(mod, pp, dp);
160 		}
161 	topo_mod_strfree(mod, plat);
162 	return (l);
163 }
164 
165 int
166 pci_label_cmn(topo_mod_t *mod, tnode_t *node, nvlist_t *in, nvlist_t **out)
167 {
168 	uint64_t ptr;
169 	const char *l;
170 	did_t *dp;
171 	char *nm;
172 	int err;
173 
174 	/*
175 	 * If it's not a device or a PCI-express bus (which could potentially
176 	 * represent a slot, and therefore we might need to capture its slot
177 	 * name information), just inherit any label from our parent
178 	 */
179 	*out = NULL;
180 	nm = topo_node_name(node);
181 	if (strcmp(nm, PCI_DEVICE) != 0 && strcmp(nm, PCIEX_DEVICE) != 0 &&
182 	    strcmp(nm, PCIEX_BUS) != 0) {
183 		if (topo_node_label_set(node, NULL, &err) < 0)
184 			if (err != ETOPO_PROP_NOENT)
185 				return (topo_mod_seterrno(mod, err));
186 		return (0);
187 	}
188 
189 	if (nvlist_lookup_uint64(in, TOPO_METH_LABEL_ARG_NVL, &ptr) != 0) {
190 		topo_mod_dprintf(mod,
191 		    "label method argument not found.\n");
192 		return (-1);
193 	}
194 	dp = (did_t *)(uintptr_t)ptr;
195 
196 	/*
197 	 * Is there a slotname associated with the device?
198 	 */
199 	if ((l = pci_slotname_lookup(mod, node, dp)) != NULL) {
200 		nvlist_t *rnvl;
201 
202 		if (topo_mod_nvalloc(mod, &rnvl, NV_UNIQUE_NAME) != 0 ||
203 		    nvlist_add_string(rnvl, TOPO_METH_LABEL_RET_STR, l) != 0)
204 			return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
205 		*out = rnvl;
206 		return (0);
207 	} else {
208 		if (topo_node_label_set(node, NULL, &err) < 0)
209 			if (err != ETOPO_PROP_NOENT)
210 				return (topo_mod_seterrno(mod, err));
211 		return (0);
212 	}
213 }
214