xref: /titanic_52/usr/src/cmd/fm/modules/sun4v/etm/etm_filter.c (revision 2c07a09983fd87547573e6ac9b5fbee5f44fa309)
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