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.
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.
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]
23 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
28 #include <fm/topo_mod.h>
29 #include <libnvpair.h>
31 #include <sys/fm/protocol.h>
35 #include <pcibus_labels.h>
37 extern slotnm_rewrite_t
*Slot_Rewrites
;
38 extern physlot_names_t
*Physlot_Names
;
39 extern missing_names_t
*Missing_Names
;
42 * Do a platform specific label lookup based on physical slot number.
45 pci_label_physlot_lookup(topo_mod_t
*mod
, char *platform
, did_t
*dp
)
47 const char *rlabel
= NULL
;
50 topo_mod_dprintf(mod
, "%s: doing a lookup for platform=%s\n",
53 if ((n
= did_physlot(dp
)) < 0 || Physlot_Names
== NULL
||
57 topo_mod_dprintf(mod
, "%s: doing a lookup for physlot=%d\n",
60 for (p
= 0; p
< Physlot_Names
->psn_nplats
; p
++) {
61 topo_mod_dprintf(mod
, "%s: comparing against platform=%s\n",
62 __func__
, Physlot_Names
->psn_names
[p
].pnm_platform
);
63 if (strcasecmp(Physlot_Names
->psn_names
[p
].pnm_platform
,
66 topo_mod_dprintf(mod
, "%s: found lookup table for this "
67 "platform\n", __func__
);
68 for (i
= 0; i
< Physlot_Names
->psn_names
[p
].pnm_nnames
; i
++) {
70 ps
= Physlot_Names
->psn_names
[p
].pnm_names
[i
];
72 topo_mod_dprintf(mod
, "%s: matched entry=%d, "
73 "label=%s\n", __func__
, i
, ps
.ps_label
);
81 topo_mod_dprintf(mod
, "%s: returning label=%s\n",
88 * Do a platform specific label lookup based on slot name.
91 pci_label_slotname_lookup(topo_mod_t
*mod
, char *platform
,
92 const char *label
, did_t
*dp
)
94 const char *rlabel
= label
;
97 if (Slot_Rewrites
== NULL
|| platform
== NULL
)
100 topo_mod_dprintf(mod
, "%s: doing a lookup for platform=%s\n",
103 for (s
= 0; s
< Slot_Rewrites
->srw_nplats
; s
++) {
104 topo_mod_dprintf(mod
, "%s: comparing against platform=%s\n",
105 __func__
, Slot_Rewrites
->srw_platrewrites
[s
].prw_platform
);
106 if (strcasecmp(Slot_Rewrites
->srw_platrewrites
[s
].prw_platform
,
109 topo_mod_dprintf(mod
, "%s: found lookup table for this "
110 "platform\n", __func__
);
112 i
< Slot_Rewrites
->srw_platrewrites
[s
].prw_nrewrites
;
115 rw
= Slot_Rewrites
->srw_platrewrites
[s
].prw_rewrites
[i
];
116 if (strcmp(rw
.srw_obp
, label
) == 0) {
117 topo_mod_dprintf(mod
, "%s: matched entry=%d, "
118 "old_label=%s, new_label=%s\n",
119 __func__
, i
, rw
.srw_obp
,
120 rw
.srw_new
? rw
.srw_new
: NULL
);
122 * If a test function is specified then call
123 * it to do an additional check.
125 if (rw
.srw_test
!= NULL
) {
126 topo_mod_dprintf(mod
,
127 "%s: calling test function=%p\n",
128 __func__
, rw
.srw_test
);
129 if (ret
= rw
.srw_test(mod
, dp
))
131 topo_mod_dprintf(mod
,
132 "%s: test function return=%d\n",
142 topo_mod_dprintf(mod
, "%s: returning label=%s\n", __func__
,
143 rlabel
? rlabel
: "NULL");
148 * Do a platform specific label lookup based on bus, dev, etc.
151 pci_label_missing_lookup(topo_mod_t
*mod
, char *platform
, did_t
*dp
)
153 const char *rlabel
= NULL
;
154 int board
, bridge
, rc
, bus
, dev
;
157 if (Missing_Names
== NULL
|| platform
== NULL
)
160 bridge
= did_bridge(dp
);
161 board
= did_board(dp
);
163 did_BDF(dp
, &bus
, &dev
, NULL
);
165 topo_mod_dprintf(mod
, "%s: doing a lookup for platform=%s, "
166 "board=%d, bridge=%d, rc=%d, bus=%d, dev=%d\n",
167 __func__
, platform
, board
, bridge
, rc
, bus
, dev
);
169 for (p
= 0; p
< Missing_Names
->mn_nplats
; p
++) {
170 topo_mod_dprintf(mod
, "%s: comparing against platform=%s\n",
171 __func__
, Missing_Names
->mn_names
[p
].pdl_platform
);
172 if (strcasecmp(Missing_Names
->mn_names
[p
].pdl_platform
,
175 topo_mod_dprintf(mod
, "%s: found lookup table for this "
176 "platform\n", __func__
);
177 for (i
= 0; i
< Missing_Names
->mn_names
[p
].pdl_nnames
; i
++) {
179 m
= Missing_Names
->mn_names
[p
].pdl_names
[i
];
180 if (m
.dl_board
== board
&& m
.dl_bridge
== bridge
&&
182 (m
.dl_bus
== -1 || m
.dl_bus
== bus
) &&
183 (m
.dl_dev
== -1 || m
.dl_dev
== dev
)) {
184 topo_mod_dprintf(mod
, "%s: matched entry=%d, "
185 "label=%s\n", __func__
, i
, m
.dl_label
);
187 * If a test function is specified then call
188 * it to do an additional test.
190 if (m
.dl_test
!= NULL
) {
191 topo_mod_dprintf(mod
,
192 "%s: calling test function=%p\n",
193 __func__
, m
.dl_test
);
194 if (ret
= m
.dl_test(mod
, dp
))
196 topo_mod_dprintf(mod
,
197 "%s: test function return=%d\n",
209 if (rlabel
!= NULL
) {
210 topo_mod_dprintf(mod
, "%s: match found, label=%s\n",
217 * Do an overall slot label lookup for the device node.
220 pci_slot_label_lookup(topo_mod_t
*mod
, tnode_t
*node
, did_t
*dp
, did_t
*pdp
)
222 tnode_t
*anode
, *apnode
;
224 char *plat
, *pp
, *l
, *ancestor_l
= NULL
, *new_l
= NULL
;
225 int err
, b
, d
, f
, done
= 0;
228 did_BDF(dp
, &b
, &d
, &f
);
230 topo_mod_dprintf(mod
, "%s: entry: node=%p, node_name=%s, "
231 "node_inst=%d, dp=%p, dp_bdf=%d/%d/%d, pdp=%p\n",
232 __func__
, node
, topo_node_name(node
), topo_node_instance(node
),
236 * If this device has a physical slot number then check if
237 * an ancestor also has a slot label.
239 * If an ancestor has a slot label, then this node's label
240 * is generated by concatenating a default label onto the
243 * We grab pairs of ancestors (parent and child) as we go up
244 * the tree because the parent is checked for the presence
245 * of a slot while the child contains the label.
247 * Note that this algorithm only applies to nodes which have
248 * a physcal slot number. (i.e. PCIE devices or PCI/PCIX
249 * devices off of a PCIE to PCIX switch)
251 if (did_physlot(pdp
) >= 0) {
253 topo_mod_dprintf(mod
, "%s: node=%p: node has a physical "
254 "slot=%d, checking ancestors for slots\n",
255 __func__
, node
, did_physlot(pdp
));
258 * Get this device's physical slot name.
260 l
= (char *)did_physlot_name(pdp
, d
);
262 anode
= topo_node_parent(node
);
265 * Check ancestors for a slot label until we
266 * either find one or hit a non-pci device.
271 * Get next ancestor node and data pointers.
273 anode
= topo_node_parent(anode
);
276 topo_node_getspecific(anode
));
277 apnode
= topo_node_parent(anode
);
280 topo_node_getspecific(apnode
));
288 topo_mod_dprintf(mod
, "%s: node=%p: checking next "
289 "two ancestors: anode=%p, adp=%p "
290 "apnode=%p, apdp=%p\n",
291 __func__
, node
, anode
, adp
, apnode
, apdp
);
292 if ((anode
!= NULL
) && (adp
!= NULL
)) {
293 did_BDF(adp
, &b
, &d
, &f
);
294 topo_mod_dprintf(mod
, "%s: node=%p: "
295 "anode_name=%s[%d], anode_bdf=%d/%d/%d\n",
296 __func__
, node
, topo_node_name(anode
),
297 topo_node_instance(anode
), b
, d
, f
);
299 if ((apnode
!= NULL
) && (apdp
!= NULL
)) {
300 did_BDF(apdp
, &b
, &d
, &f
);
301 topo_mod_dprintf(mod
, "%s: node=%p: "
302 "apnode_name=%s[%d], "
303 "apnode_bdf=%d/%d/%d\n",
304 __func__
, node
, topo_node_name(apnode
),
305 topo_node_instance(apnode
), b
, d
, f
);
309 * If the ancestors do not exist or are not pci
310 * devices then we're done searching.
312 * Otherwise, if the ancestor has a physical slot,
313 * and it is a different slot than the one we
314 * started with then lookup the ancestor label,
317 if ((anode
== NULL
) || (adp
== NULL
) ||
318 (apnode
== NULL
) || (apdp
== NULL
)) {
320 } else if (did_physlot_exists(apdp
) &&
322 if (topo_node_label(anode
, &ancestor_l
,
324 topo_mod_dprintf(mod
,
325 "%s: node=%p: topo_node_label() "
326 "FAILED!", __func__
, node
);
327 (void) topo_mod_seterrno(mod
, err
);
331 topo_mod_dprintf(mod
, "%s: node=%p: found "
332 "ancestor with a slot, label=%s ",
333 __func__
, node
, ancestor_l
);
336 if (ancestor_l
== NULL
) {
337 topo_mod_dprintf(mod
, "%s: node=%p: no ancestor "
338 "slot found\n", __func__
, node
);
343 * If we found an ancestor with a slot label, and this node has
344 * a physical slot number label then concatenate the two to form
345 * this node's label. Otherwise, do a full slot label lookup.
347 if (ancestor_l
&& l
) {
348 topo_mod_dprintf(mod
, "%s: node=%p: concatenating "
349 "ancestor_l=%s and l=%s\n",
350 __func__
, node
, ancestor_l
, l
);
351 len
= strlen(ancestor_l
) + strlen(l
) + 2;
353 (void) snprintf(new_l
, len
, "%s/%s", ancestor_l
, l
);
357 * Get platform name used for lookups.
359 if (topo_prop_get_string(node
, FM_FMRI_AUTHORITY
,
360 FM_FMRI_AUTH_PRODUCT
, &plat
, &err
) < 0) {
361 (void) topo_mod_seterrno(mod
, err
);
365 * Trim SUNW, from the platform name
367 pp
= strchr(plat
, ',');
373 * Get device number used for lookup.
375 did_BDF(dp
, NULL
, &d
, NULL
);
378 * The slot label is determined in the following order:
379 * - Platform specific lookup based on physical slot #.
380 * - Platform specific lookup based on default label string.
381 * - Platform specific lookup based on device number.
383 * The default label is based on the slot names property
384 * if it exists, else it is a generic name derived from
387 if ((l
= (char *)pci_label_physlot_lookup(mod
, pp
, pdp
))
389 if ((l
= (char *)did_physlot_name(pdp
, d
)) != NULL
) {
391 pci_label_slotname_lookup(mod
, pp
, l
, dp
);
395 pci_label_missing_lookup(mod
, pp
, dp
);
398 topo_mod_strfree(mod
, plat
);
402 * If we calculated a slot label, then save it in the
403 * node's data structure so we can free it later.
406 if (did_slot_label_get(dp
) != NULL
)
407 topo_mod_strfree(mod
, did_slot_label_get(dp
));
408 l
= topo_mod_strdup(mod
, l
);
409 did_slot_label_set(dp
, l
);
412 topo_mod_dprintf(mod
, "%s: exit: node=%p: label=%s\n",
413 __func__
, node
, (l
? l
: "NULL"));
419 pci_label_cmn(topo_mod_t
*mod
, tnode_t
*node
, nvlist_t
*in
, nvlist_t
**out
)
429 * If it's not a device or a PCI-express bus (which could potentially
430 * represent a slot, and therefore we might need to capture its slot
431 * name information), just inherit any label from our parent
434 nm
= topo_node_name(node
);
435 if (strcmp(nm
, PCI_DEVICE
) != 0 && strcmp(nm
, PCIEX_DEVICE
) != 0 &&
436 strcmp(nm
, PCIEX_BUS
) != 0) {
437 if (topo_node_label_set(node
, NULL
, &err
) < 0)
438 if (err
!= ETOPO_PROP_NOENT
)
439 return (topo_mod_seterrno(mod
, err
));
443 if (nvlist_lookup_uint64(in
, TOPO_METH_LABEL_ARG_NVL
, &ptr
) != 0) {
444 topo_mod_dprintf(mod
,
445 "%s: label method argument not found.\n", __func__
);
448 dp
= (did_t
*)(uintptr_t)ptr
;
449 pnode
= did_gettnode(dp
);
450 pdp
= did_find(mod
, topo_node_getspecific(pnode
));
453 * Is there a slot label associated with the device?
455 if ((l
= pci_slot_label_lookup(mod
, node
, dp
, pdp
)) != NULL
) {
458 if (topo_mod_nvalloc(mod
, &rnvl
, NV_UNIQUE_NAME
) != 0 ||
459 nvlist_add_string(rnvl
, TOPO_METH_LABEL_RET_STR
, l
) != 0)
460 return (topo_mod_seterrno(mod
, EMOD_FMRI_NVL
));
464 if (topo_node_label_set(node
, NULL
, &err
) < 0)
465 if (err
!= ETOPO_PROP_NOENT
)
466 return (topo_mod_seterrno(mod
, err
));
472 pci_fru_cmn(topo_mod_t
*mod
, tnode_t
*node
, nvlist_t
*in
, nvlist_t
**out
)
481 nm
= topo_node_name(node
);
482 if (strcmp(nm
, PCI_DEVICE
) != 0 && strcmp(nm
, PCIEX_DEVICE
) != 0 &&
483 strcmp(nm
, PCIEX_BUS
) != 0)
486 if (nvlist_lookup_uint64(in
, "nv1", &ptr
) != 0) {
487 topo_mod_dprintf(mod
,
488 "%s: label method argument not found.\n", __func__
);
491 dp
= (did_t
*)(uintptr_t)ptr
;
492 pnode
= did_gettnode(dp
);
493 pdp
= did_find(mod
, topo_node_getspecific(pnode
));
496 * Is there a slot label associated with the device?
498 if (pci_slot_label_lookup(mod
, pnode
, dp
, pdp
) != NULL
) {
501 if (topo_node_resource(node
, &rnvl
, &err
) < 0 || rnvl
== NULL
) {
502 topo_mod_dprintf(mod
, "%s: error: %s\n",
503 __func__
, topo_strerror(topo_mod_errno(mod
)));
504 return (topo_mod_seterrno(mod
, err
));