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 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * etm_filter.c 29 * Description: 30 * Find the ldom that own the resource specified in the detector field 31 * of the ereport. 32 */ 33 34 #include <pthread.h> 35 #include <stdio.h> 36 #include <strings.h> 37 #include <sys/types.h> 38 #include <sys/stat.h> 39 #include <sys/fm/ldom.h> 40 #include <sys/fm/protocol.h> 41 #include <fm/fmd_api.h> 42 #include <fm/libtopo.h> 43 #include <fm/topo_hc.h> 44 45 #include "etm_filter.h" 46 47 static etm_prc_t *etm_rcs; /* vector of root complexes */ 48 static uint16_t etm_rc_cnt; /* count of rc entries in rcs */ 49 static uint16_t etm_rc_max; /* max entries allowed in rcs */ 50 static pthread_mutex_t etm_rc_lock; /* lock of the rc vector */ 51 52 53 extern ldom_hdl_t *etm_lhp; /* libldom handle */ 54 55 /* ARGSUSED */ 56 static int 57 etm_pciexrc_walker(topo_hdl_t *thp, tnode_t *node, void *arg) 58 { 59 int i; /* temp counter */ 60 int n; /* temp size of new vector */ 61 int err; /* temp error var */ 62 char *str; /* topo node value */ 63 fmd_hdl_t *hdl = arg; /* etm mod hdl */ 64 etm_prc_t *rcl; /* root complex vector */ 65 etm_prc_t *p; /* temp pointer */ 66 topo_instance_t ins; /* rc id */ 67 uint64_t ba; /* bus address */ 68 69 /* pciexrc node */ 70 if (strcmp(topo_node_name(node), PCIEX_ROOT) != 0) 71 return (TOPO_WALK_NEXT); 72 73 if (topo_prop_get_string(node, TOPO_PGROUP_IO, TOPO_IO_DEV, &str, 74 &err) != 0) 75 return (TOPO_WALK_NEXT); 76 77 /* physical id and bus address of a root complex */ 78 ins = topo_node_instance(node); 79 (void) sscanf(str, "/pci@%llx", &ba); 80 topo_hdl_strfree(thp, str); 81 82 /* 83 * prc vector is full, so double its size 84 */ 85 if (etm_rc_cnt >= etm_rc_max) { 86 n = (etm_rc_max == 0) ? 1 : 2 * etm_rc_max; 87 rcl = fmd_hdl_zalloc(hdl, n * sizeof (etm_prc_t), FMD_SLEEP); 88 for (i = 0, p = rcl; i < n; i++, p++) { 89 p->prc_id = -1; 90 p->prc_status = -1; 91 } 92 if (etm_rcs != NULL) { 93 bcopy(etm_rcs, rcl, etm_rc_max * sizeof (etm_prc_t)); 94 fmd_hdl_free(hdl, etm_rcs, 95 etm_rc_max * sizeof (etm_prc_t)); 96 } 97 etm_rcs = rcl; 98 etm_rc_max = n; 99 } 100 101 if (etm_rc_cnt >= etm_rc_max) { 102 fmd_hdl_abort(hdl, "rcs is full. Expect counter value %d<%d\n", 103 etm_rc_cnt, etm_rc_max); 104 } 105 106 /* Add the rc at the end of the list */ 107 p = etm_rcs + etm_rc_cnt; 108 p->prc_id = ins; 109 p->prc_cfg_handle = ba; 110 etm_rc_cnt++; 111 112 return (TOPO_WALK_NEXT); 113 } 114 115 /* 116 * etm_pciexrc_init() 117 * Description: 118 * Walk through the topology to find the pciexrc nodes. Then save the 119 * physical instances and bus addreses in a vector. 120 */ 121 static void 122 etm_pciexrc_init(fmd_hdl_t *hdl) 123 { 124 topo_hdl_t *thp; /* topo handle */ 125 topo_walk_t *twp; /* topo walk handle */ 126 int err; /* topo error */ 127 128 if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL) 129 return; 130 twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC, etm_pciexrc_walker, 131 (void *) hdl, &err); 132 if (twp == NULL) { 133 fmd_hdl_topo_rele(hdl, thp); 134 return; 135 } 136 (void) topo_walk_step(twp, TOPO_WALK_CHILD); 137 topo_walk_fini(twp); 138 fmd_hdl_topo_rele(hdl, thp); 139 } 140 141 /* 142 * etm_update_prc() 143 * Description: 144 * Query ldmd for the ldom id 145 */ 146 void 147 etm_update_prc(fmd_hdl_t *hdl, etm_prc_t *prc) 148 { 149 char name[MAX_LDOM_NAME]; /* domain name */ 150 uint64_t virt_cfg_handle; /* bus address from ldmd */ 151 uint64_t did; /* domain id */ 152 153 if (prc == NULL) 154 return; 155 156 /* call libldom to find the ldom id */ 157 prc->prc_status = ldom_find_id(etm_lhp, prc->prc_cfg_handle, 158 LDOM_RSRC_PCI, &virt_cfg_handle, name, MAX_LDOM_NAME, &did); 159 if (prc->prc_status) { 160 return; 161 } 162 163 /* cache the ldom id */ 164 prc->prc_did = did; 165 if (prc->prc_name != NULL) { 166 fmd_hdl_free(hdl, prc->prc_name, prc->prc_name_sz); 167 } 168 prc->prc_name_sz = strlen(name) + 1; 169 prc->prc_name = fmd_hdl_zalloc(hdl, prc->prc_name_sz, FMD_SLEEP); 170 (void) strncpy(prc->prc_name, name, prc->prc_name_sz); 171 } 172 173 /* 174 * etm_find_ldom_id() 175 * Description: 176 * Find the ldom name and the domain id that owns the resource specified in 177 * the ereport detector 178 */ 179 int 180 etm_filter_find_ldom_id(fmd_hdl_t *hdl, nvlist_t *evp, char *name, 181 int name_size, uint64_t *did) 182 { 183 char *str; /* temp string */ 184 char *s; /* temp string */ 185 int i; /* loop counter */ 186 int ins; /* instance number */ 187 nvlist_t *det; /* ereport detector */ 188 nvlist_t **hcl; /* hc name-value pair list */ 189 uint_t sz; /* size of hcl */ 190 etm_prc_t *prc; /* root complex */ 191 192 /* check paramters */ 193 if (name == NULL || name_size <= 0) { 194 fmd_hdl_debug(hdl, "Invalid parameters"); 195 return (-1); 196 } 197 198 /* must be an ereport */ 199 if ((nvlist_lookup_string(evp, FM_CLASS, &str) != 0) || 200 (strncmp(str, FM_EREPORT_CLASS, strlen(FM_EREPORT_CLASS)) != 0)) { 201 fmd_hdl_debug(hdl, "not an ereport"); 202 return (-1); 203 } 204 205 /* the detector is of hc-scheme */ 206 if (nvlist_lookup_nvlist(evp, FM_EREPORT_DETECTOR, &det) != 0) { 207 fmd_hdl_debug(hdl, "ereport detector not found"); 208 return (-1); 209 } 210 if ((nvlist_lookup_string(det, FM_FMRI_SCHEME, &str) != 0) || 211 (strcmp(str, FM_FMRI_SCHEME_HC) != 0)) { 212 fmd_hdl_debug(hdl, "detector is not hc-schemed\n"); 213 return (-1); 214 } 215 216 /* 217 * Find the pciexrc and extract the instance number 218 */ 219 if (nvlist_lookup_nvlist_array(det, FM_FMRI_HC_LIST, &hcl, &sz) != 0) { 220 fmd_hdl_debug(hdl, "%s is not found\n", FM_FMRI_HC_LIST); 221 return (-1); 222 } 223 for (i = 0; i < sz; i++) { 224 if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &str) == 0 && 225 nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &s) == 0 && 226 strcmp(str, PCIEX_ROOT) == 0) { 227 (void) sscanf(s, "%d", &ins); 228 break; 229 } 230 } 231 if (i >= sz) { 232 fmd_hdl_debug(hdl, "%s not found\n", PCIEX_ROOT); 233 return (-1); 234 } 235 236 (void) pthread_mutex_lock(&etm_rc_lock); 237 238 /* search the entry by the physical instance number */ 239 for (i = 0, prc = etm_rcs; prc != NULL && i < etm_rc_cnt; 240 i++, prc++) { 241 if (prc->prc_id == ins) { 242 /* update the cached entry */ 243 if (prc->prc_status != 0) { 244 etm_update_prc(hdl, prc); 245 } 246 /* check for cached ldom name */ 247 if (prc->prc_status == 0 && prc->prc_name != NULL) { 248 *did = prc->prc_did; 249 (void) strncpy(name, prc->prc_name, name_size); 250 (void) pthread_mutex_unlock(&etm_rc_lock); 251 return (0); 252 } 253 break; 254 } 255 } 256 if (i >= etm_rc_cnt) { 257 fmd_hdl_debug(hdl, "prc[%d] not found\n", ins); 258 } 259 260 (void) pthread_mutex_unlock(&etm_rc_lock); 261 262 return (-1); 263 } /* etm_find_ldom_id */ 264 265 /* 266 * etm_find_ldom_name() 267 * Description: 268 * Find the ldom name of a given domain id (did) 269 */ 270 int 271 etm_filter_find_ldom_name(fmd_hdl_t *hdl, uint64_t did, char *name, 272 int name_size) 273 { 274 int rc = -1; /* return value */ 275 int i; /* loop counter */ 276 etm_prc_t *prc; /* root complex */ 277 278 (void) pthread_mutex_lock(&etm_rc_lock); 279 280 /* visit all the root complexes to find an entry that matches the did */ 281 for (i = 0, prc = etm_rcs; prc != NULL && i < etm_rc_cnt; 282 i++, prc++) { 283 /* update the cached entry */ 284 if (prc->prc_status != 0) { 285 etm_update_prc(hdl, prc); 286 } 287 /* find the cached ldom name */ 288 if (prc->prc_status == 0 && prc->prc_did == did) { 289 rc = 0; 290 (void) strncpy(name, prc->prc_name ? prc->prc_name : "", 291 name_size); 292 break; 293 } 294 } 295 296 (void) pthread_mutex_unlock(&etm_rc_lock); 297 298 return (rc); 299 } /* etm_find_ldom_name */ 300 301 /* 302 * etm_filter_handle_ldom_event() 303 * Description: 304 * Invalidate the ldom name in the physical root complex vector. 305 */ 306 void 307 etm_filter_handle_ldom_event(fmd_hdl_t *hdl, etm_async_event_type_t event, 308 char *name) { 309 int i; /* loop counter */ 310 etm_prc_t *prc; /* root complex */ 311 312 /* 313 * Clear the cached ldom name 314 */ 315 switch (event) { 316 case ETM_ASYNC_EVENT_LDOM_ADD: 317 case ETM_ASYNC_EVENT_LDOM_REMOVE: 318 case ETM_ASYNC_EVENT_LDOM_BIND: 319 case ETM_ASYNC_EVENT_LDOM_UNBIND: 320 (void) pthread_mutex_lock(&etm_rc_lock); 321 for (i = 0, prc = etm_rcs; prc != NULL && i < etm_rc_cnt; 322 i++, prc++) { 323 if (prc->prc_name != NULL && 324 strcmp(prc->prc_name, name) == 0) { 325 fmd_hdl_free(hdl, prc->prc_name, 326 prc->prc_name_sz); 327 prc->prc_name = NULL; 328 prc->prc_name_sz = 0; 329 prc->prc_status = -1; 330 } 331 } 332 (void) pthread_mutex_unlock(&etm_rc_lock); 333 break; 334 default: 335 break; 336 } 337 } 338 339 /* ARGSUSED */ 340 void 341 etm_filter_init(fmd_hdl_t *hdl) { 342 etm_rcs = NULL; 343 etm_rc_cnt = 0; 344 etm_rc_max = 0; 345 (void) pthread_mutex_init(&etm_rc_lock, NULL); 346 etm_pciexrc_init(hdl); 347 } 348 349 void 350 etm_filter_fini(fmd_hdl_t *hdl) { 351 int i; /* loop counter */ 352 etm_prc_t *prc; /* root complex pointer */ 353 354 for (i = 0, prc = etm_rcs; prc != NULL && i < etm_rc_cnt; 355 i++, prc++) { 356 if (prc->prc_name != NULL) { 357 fmd_hdl_free(hdl, prc->prc_name, prc->prc_name_sz); 358 prc->prc_name = NULL; 359 prc->prc_name_sz = 0; 360 prc->prc_status = -1; 361 } 362 } 363 if (etm_rcs != NULL && etm_rc_max > 0) { 364 fmd_hdl_free(hdl, etm_rcs, etm_rc_max * sizeof (etm_prc_t)); 365 } 366 (void) pthread_mutex_destroy(&etm_rc_lock); 367 } 368