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 2007 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 platform == NULL) 51 return (NULL); 52 53 for (p = 0; p < Physlot_Names->psn_nplats; p++) { 54 if (strcmp(Physlot_Names->psn_names[p].pnm_platform, 55 platform) != 0) 56 continue; 57 for (i = 0; i < Physlot_Names->psn_names[p].pnm_nnames; i++) { 58 physnm_t ps; 59 ps = Physlot_Names->psn_names[p].pnm_names[i]; 60 if (ps.ps_num == n) { 61 rlabel = ps.ps_label; 62 break; 63 } 64 } 65 break; 66 } 67 return (rlabel); 68 } 69 70 static const char * 71 pci_slotname_rewrite(char *platform, const char *label) 72 { 73 const char *rlabel = label; 74 int s, i; 75 76 if (Slot_Rewrites == NULL) 77 return (rlabel); 78 79 for (s = 0; s < Slot_Rewrites->srw_nplats; s++) { 80 if (strcmp(Slot_Rewrites->srw_platrewrites[s].prw_platform, 81 platform) != 0) 82 continue; 83 for (i = 0; 84 i < Slot_Rewrites->srw_platrewrites[s].prw_nrewrites; 85 i++) { 86 slot_rwd_t rw; 87 rw = Slot_Rewrites->srw_platrewrites[s].prw_rewrites[i]; 88 if (strcmp(rw.srw_obp, label) == 0) { 89 rlabel = rw.srw_new; 90 break; 91 } 92 } 93 break; 94 } 95 assert(rlabel != NULL); 96 return (rlabel); 97 } 98 99 static const char * 100 pci_missing_match(topo_mod_t *mod, char *platform, did_t *dp) 101 { 102 const char *rlabel = NULL; 103 int board, bridge, rc, bus, dev; 104 int p, i; 105 106 if (Missing_Names == NULL) 107 return (NULL); 108 bridge = did_bridge(dp); 109 board = did_board(dp); 110 rc = did_rc(dp); 111 did_BDF(dp, &bus, &dev, NULL); 112 113 topo_mod_dprintf(mod, "Missing a name for %d, %d, %d, %d, %d ?\n", 114 board, bridge, rc, bus, dev); 115 116 for (p = 0; p < Missing_Names->mn_nplats; p++) { 117 if (strcmp(Missing_Names->mn_names[p].pdl_platform, 118 platform) != 0) 119 continue; 120 for (i = 0; i < Missing_Names->mn_names[p].pdl_nnames; i++) { 121 devlab_t m; 122 m = Missing_Names->mn_names[p].pdl_names[i]; 123 if (m.dl_board == board && m.dl_bridge == bridge && 124 m.dl_rc == rc && m.dl_bus == bus && 125 m.dl_dev == dev) { 126 rlabel = m.dl_label; 127 break; 128 } 129 } 130 break; 131 } 132 return (rlabel); 133 } 134 135 const char * 136 pci_slotname_lookup(topo_mod_t *mod, tnode_t *node, did_t *dp) 137 { 138 const char *l; 139 char *plat, *pp; 140 int err; 141 int d; 142 143 if (topo_prop_get_string(node, 144 FM_FMRI_AUTHORITY, FM_FMRI_AUTH_PRODUCT, &plat, &err) < 0) { 145 (void) topo_mod_seterrno(mod, err); 146 return (NULL); 147 } 148 149 /* 150 * Trim SUNW, from the platform name 151 */ 152 pp = strchr(plat, ','); 153 if (pp == NULL) 154 pp = plat; 155 else 156 ++pp; 157 158 did_BDF(dp, NULL, &d, NULL); 159 if ((l = pci_physslot_name_lookup(pp, dp)) == NULL) 160 if ((l = did_label(dp, d)) != NULL) { 161 l = pci_slotname_rewrite(pp, l); 162 } else { 163 l = pci_missing_match(mod, pp, dp); 164 } 165 topo_mod_strfree(mod, plat); 166 return (l); 167 } 168 169 int 170 pci_label_cmn(topo_mod_t *mod, tnode_t *node, nvlist_t *in, nvlist_t **out) 171 { 172 uint64_t ptr; 173 const char *l; 174 did_t *dp; 175 char *nm; 176 int err; 177 178 /* 179 * If it's not a device or a PCI-express bus (which could potentially 180 * represent a slot, and therefore we might need to capture its slot 181 * name information), just inherit any label from our parent 182 */ 183 *out = NULL; 184 nm = topo_node_name(node); 185 if (strcmp(nm, PCI_DEVICE) != 0 && strcmp(nm, PCIEX_DEVICE) != 0 && 186 strcmp(nm, PCIEX_BUS) != 0) { 187 if (topo_node_label_set(node, NULL, &err) < 0) 188 if (err != ETOPO_PROP_NOENT) 189 return (topo_mod_seterrno(mod, err)); 190 return (0); 191 } 192 193 if (nvlist_lookup_uint64(in, TOPO_METH_LABEL_ARG_NVL, &ptr) != 0) { 194 topo_mod_dprintf(mod, 195 "label method argument not found.\n"); 196 return (-1); 197 } 198 dp = (did_t *)(uintptr_t)ptr; 199 200 /* 201 * Is there a slotname associated with the device? 202 */ 203 if ((l = pci_slotname_lookup(mod, node, dp)) != NULL) { 204 nvlist_t *rnvl; 205 206 if (topo_mod_nvalloc(mod, &rnvl, NV_UNIQUE_NAME) != 0 || 207 nvlist_add_string(rnvl, TOPO_METH_LABEL_RET_STR, l) != 0) 208 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 209 *out = rnvl; 210 return (0); 211 } else { 212 if (topo_node_label_set(node, NULL, &err) < 0) 213 if (err != ETOPO_PROP_NOENT) 214 return (topo_mod_seterrno(mod, err)); 215 return (0); 216 } 217 } 218