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 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <fm/topo_mod.h> 28 #include <sys/fm/protocol.h> 29 #include <string.h> 30 #include <alloca.h> 31 #include <libdevinfo.h> 32 #include <did_props.h> 33 34 /* 35 * Including the following file gives us definitions of the three 36 * global arrays used to adjust labels, Slot_Rewrites, Physlot_Names, 37 * and Missing_Names. With those defined we can use the common labeling 38 * routines for pci. 39 */ 40 #include "pci_sun4v.h" 41 #include "pci_sun4.h" 42 43 #define PI_PROP_CHASSIS_LOCATION_NAME "chassis-location-name" 44 45 typedef struct _pci_fru { 46 tnode_t *node; 47 char *location; 48 int locsiz; 49 } _pci_fru_t; 50 51 52 static int platform_pci_fru_location(topo_mod_t *, tnode_t *, uchar_t *, int); 53 static int platform_pci_fru_cb(topo_mod_t *, tnode_t *, void *); 54 55 56 int 57 platform_pci_label(topo_mod_t *mod, tnode_t *node, nvlist_t *in, 58 nvlist_t **out) 59 { 60 int result; 61 int err; 62 int locsiz = 0; 63 uchar_t *loc = NULL; 64 char *nac = NULL; 65 66 topo_mod_dprintf(mod, "entering platform_pci_label\n"); 67 68 *out = NULL; 69 result = di_bytes_get(mod, topo_node_getspecific(node), 70 PI_PROP_CHASSIS_LOCATION_NAME, &locsiz, &loc); 71 if (result == -1 || locsiz < 0) { 72 topo_mod_dprintf(mod, "platform_pci_label: %s not found (%s)\n", 73 PI_PROP_CHASSIS_LOCATION_NAME, strerror(errno)); 74 75 /* Invoke the generic label generator for this node */ 76 return (pci_label_cmn(mod, node, in, out)); 77 } 78 79 /* 80 * We have crossed a FRU boundary. Use the value in the 81 * chassis-location-name property as the node label. 82 */ 83 nac = alloca(locsiz+1); 84 (void) memset(nac, 0, locsiz+1); 85 (void) memcpy(nac, loc, locsiz); 86 result = topo_node_label_set(node, nac, &err); 87 if (result < 0) { 88 if (err != ETOPO_PROP_NOENT) { 89 return (topo_mod_seterrno(mod, err)); 90 } 91 } 92 93 return (0); 94 } 95 96 97 int 98 platform_pci_fru(topo_mod_t *mod, tnode_t *node, nvlist_t *in, 99 nvlist_t **out) 100 { 101 int err = 0; 102 uint64_t ptr; 103 did_t *dp, *pdp; 104 tnode_t *pnode; 105 char *nm, *plat, *pp, **cp; 106 char *label; 107 int found_t1plat = 0; 108 uchar_t *loc; 109 int locsiz; 110 111 topo_mod_dprintf(mod, "entering platform_pci_fru\n"); 112 113 if (topo_prop_get_string(node, FM_FMRI_AUTHORITY, 114 FM_FMRI_AUTH_PRODUCT, &plat, &err) < 0) { 115 (void) topo_mod_seterrno(mod, err); 116 return (-1); 117 } 118 /* Delete the "SUNW," */ 119 pp = strchr(plat, ','); 120 if (pp == NULL) 121 pp = plat; 122 else 123 ++pp; 124 125 /* Is this an UltraSPARC-T1 platform? */ 126 cp = usT1_plats; 127 while ((*cp != NULL) && (found_t1plat == 0)) { 128 if (strcmp(pp, *cp) == 0) 129 found_t1plat = 1; 130 cp++; 131 } 132 133 topo_mod_strfree(mod, plat); 134 135 /* 136 * On UltraSPARC-T1 systems, use the legacy hc scheme on 137 * the adapter slots to ensure ALOM on the SP can interpret 138 * the FRU correctly. For everything else, follow the normal 139 * code flow 140 */ 141 if (found_t1plat) { 142 *out = NULL; 143 nm = topo_node_name(node); 144 if (strcmp(nm, PCI_DEVICE) != 0 && 145 strcmp(nm, PCIEX_DEVICE) != 0 && 146 strcmp(nm, PCIEX_BUS) != 0) 147 return (0); 148 149 if (nvlist_lookup_uint64(in, "nv1", &ptr) != 0) { 150 topo_mod_dprintf(mod, "label method argument " 151 "not found.\n"); 152 return (-1); 153 } 154 dp = (did_t *)(uintptr_t)ptr; 155 pnode = did_gettnode(dp); 156 pdp = did_find(mod, topo_node_getspecific(pnode)); 157 158 /* 159 * Is there a slotname associated with the device? 160 */ 161 if ((label = pci_slot_label_lookup(mod, pnode, dp, pdp)) 162 != NULL) { 163 nvlist_t *rnvl; 164 char buf[PATH_MAX]; 165 166 (void) snprintf(buf, PATH_MAX, "hc:///component=%s", 167 label); 168 if (topo_mod_str2nvl(mod, buf, &rnvl) < 0) 169 return (-1); 170 *out = rnvl; 171 } 172 return (0); 173 } else if (di_bytes_get(mod, topo_node_getspecific(node), 174 PI_PROP_CHASSIS_LOCATION_NAME, &locsiz, &loc) == 0 && locsiz > 0) { 175 /* 176 * We have crossed a FRU boundary and need to find the parent 177 * node with this location and set our FMRI to that value. 178 */ 179 return (platform_pci_fru_location(mod, node, loc, locsiz)); 180 } else { 181 return (pci_fru_compute(mod, node, in, out)); 182 } 183 } 184 185 186 static int 187 platform_pci_fru_location(topo_mod_t *mod, tnode_t *node, uchar_t *loc, 188 int locsiz) 189 { 190 int err; 191 tnode_t *parent; 192 tnode_t *top; 193 topo_walk_t *wp; 194 _pci_fru_t walkdata; 195 196 topo_mod_dprintf(mod, "entering platform_pci_fru_location\n"); 197 198 /* Find the root node */ 199 top = node; 200 while ((parent = topo_node_parent(top)) != NULL) { 201 top = parent; 202 } 203 walkdata.node = node; 204 walkdata.locsiz = locsiz; 205 walkdata.location = alloca(locsiz+1); 206 (void) memset(walkdata.location, 0, locsiz+1); 207 (void) memcpy(walkdata.location, loc, locsiz); 208 209 /* Create a walker starting at the root node */ 210 wp = topo_mod_walk_init(mod, top, platform_pci_fru_cb, &walkdata, &err); 211 if (wp == NULL) { 212 return (topo_mod_seterrno(mod, err)); 213 } 214 215 /* 216 * Walk the tree breadth first to hopefully avoid visiting too many 217 * nodes while searching for the node with the appropriate FMRI. 218 */ 219 (void) topo_walk_step(wp, TOPO_WALK_SIBLING); 220 topo_walk_fini(wp); 221 222 return (0); 223 } 224 225 226 static int 227 platform_pci_fru_cb(topo_mod_t *mod, tnode_t *node, void *private) 228 { 229 int err; 230 _pci_fru_t *walkdata = (_pci_fru_t *)private; 231 nvlist_t *fmri; 232 char *location; 233 int result, rc; 234 235 if (node == walkdata->node) { 236 /* This is the starting node. Do not check the location */ 237 return (TOPO_WALK_NEXT); 238 } 239 240 if (topo_node_label(node, &location, &err) != 0) { 241 /* This node has no location property. Continue the walk */ 242 return (TOPO_WALK_NEXT); 243 } 244 245 result = TOPO_WALK_NEXT; 246 if (strncmp(location, walkdata->location, walkdata->locsiz) == 0) { 247 /* 248 * We have a match. Set the node's FRU FMRI to this nodes 249 * FRU FMRI 250 */ 251 rc = topo_node_fru(node, &fmri, NULL, &err); 252 if (rc == 0) { 253 rc = topo_node_fru_set(walkdata->node, fmri, 0, &err); 254 nvlist_free(fmri); 255 } 256 if (rc != 0) { 257 result = TOPO_WALK_TERMINATE; 258 (void) topo_mod_seterrno(mod, err); 259 } 260 } 261 topo_mod_strfree(mod, location); 262 return (result); 263 } 264