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
etm_pciexrc_walker(topo_hdl_t * thp,tnode_t * node,void * arg)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
etm_pciexrc_init(fmd_hdl_t * hdl)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
etm_update_prc(fmd_hdl_t * hdl,etm_prc_t * prc)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
etm_filter_find_ldom_id(fmd_hdl_t * hdl,nvlist_t * evp,char * name,int name_size,uint64_t * did)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
etm_filter_find_ldom_name(fmd_hdl_t * hdl,uint64_t did,char * name,int name_size)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
etm_filter_handle_ldom_event(fmd_hdl_t * hdl,etm_async_event_type_t event,char * name)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
etm_filter_init(fmd_hdl_t * hdl)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
etm_filter_fini(fmd_hdl_t * hdl)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