xref: /onnv-gate/usr/src/cmd/fps/fptest/fps_ereport_mod.c (revision 11102:b91faef0c984)
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 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <kstat.h>
28 #include <libnvpair.h>
29 #include <libsysevent.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <sys/fm/protocol.h>
34 #include <sys/fm/util.h>
35 #include <sys/types.h>
36 #include <sys/processor.h>
37 #include <unistd.h>
38 #include <fp.h>
39 #include <fps_defines.h>
40 #include <fps_ereport.h>
41 #include <fpst-defines.h>
42 
43 #define	CLASS_HEAD "ereport.cpu"
44 #define	CLASS_TAIL "fpu.fpscrub"
45 
46 /* nvlist */
47 static nvlist_t *fps_nvlist_create();
48 
49 /* ereport piece generators */
50 static int fps_fmri_cpu_set(nvlist_t *fmri_cpu, uint32_t cpu_id);
51 static int fps_fmri_svc_set(nvlist_t *fmri_svc, const char *svc_fmri);
52 static int fps_post_ereport(nvlist_t *ereport);
53 static uint64_t fps_ena_generate(uint64_t timestamp, uint32_t cpuid,
54 		uchar_t format);
55 
56 /* cpu check and name convert */
57 static char *fps_get_cpu_brand(uint32_t cpu_id);
58 static char *fps_convert_cpu_brand(char *brand);
59 
60 /* ereport struct functions */
61 int fps_generate_ereport_struct(struct fps_test_ereport *report);
62 void setup_fps_test_struct(int mask, struct fps_test_ereport *rep, ...);
63 void initialize_fps_test_struct(struct fps_test_ereport *init_me);
64 
65 /*
66  * fps_nvlist_create() allocates the memory for an
67  * nvlist.
68  */
69 static nvlist_t *
fps_nvlist_create()70 fps_nvlist_create()
71 {
72 	int nr_malloc;
73 	nvlist_t *nvl;
74 	struct timeval timeout;
75 
76 	timeout.tv_sec = 0;
77 	timeout.tv_usec = 10000;
78 	nr_malloc = 0;
79 
80 	nvl = NULL;
81 	(void) nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
82 
83 	while (nvl == NULL && nr_malloc < 10) {
84 		(void) select(1, NULL, NULL, NULL, &timeout);
85 		(void) nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
86 		nr_malloc++;
87 	}
88 
89 	return (nvl);
90 }
91 
92 /*
93  * fps_ena_generate(uint64_t timestamp, processorid_t cpuid,
94  * uchar_t format)creates the ENA for the ereport.
95  */
96 static uint64_t
fps_ena_generate(uint64_t timestamp,uint32_t cpuid,uchar_t format)97 fps_ena_generate(uint64_t timestamp, uint32_t cpuid, uchar_t format)
98 {
99 	uint64_t ena = 0;
100 
101 	switch (format) {
102 	case FM_ENA_FMT1:
103 		if (timestamp) {
104 			ena = (uint64_t)((format & ENA_FORMAT_MASK) |
105 			    ((cpuid << ENA_FMT1_CPUID_SHFT) &
106 			    ENA_FMT1_CPUID_MASK) |
107 			    ((timestamp << ENA_FMT1_TIME_SHFT) &
108 			    ENA_FMT1_TIME_MASK));
109 		} else {
110 			ena = (uint64_t)((format & ENA_FORMAT_MASK) |
111 			    ((cpuid << ENA_FMT1_CPUID_SHFT) &
112 			    ENA_FMT1_CPUID_MASK) |
113 			    ((gethrtime() << ENA_FMT1_TIME_SHFT) &
114 			    ENA_FMT1_TIME_MASK));
115 		}
116 		break;
117 	case FM_ENA_FMT2:
118 		ena = (uint64_t)((format & ENA_FORMAT_MASK) |
119 		    ((timestamp << ENA_FMT2_TIME_SHFT) & ENA_FMT2_TIME_MASK));
120 		break;
121 	default:
122 		break;
123 	}
124 
125 	return (ena);
126 }
127 
128 /*
129  * fps_fmri_svc_set(nvlist_t *fmri_svc, const char *svc_fmri)
130  * adds the detector data to fmri_svc.
131  */
132 static int
fps_fmri_svc_set(nvlist_t * fmri_svc,const char * svc_fmri)133 fps_fmri_svc_set(nvlist_t *fmri_svc, const char *svc_fmri)
134 {
135 	if (fmri_svc == NULL)
136 		return (1);
137 
138 	if (svc_fmri == NULL)
139 		return (1);
140 
141 	if (nvlist_add_uint8(fmri_svc, FM_VERSION, FM_SVC_SCHEME_VERSION) != 0)
142 		return (1);
143 
144 	if (nvlist_add_string(fmri_svc, FM_FMRI_SCHEME,
145 	    FM_FMRI_SCHEME_SVC) != 0)
146 		return (1);
147 
148 	if (nvlist_add_string(fmri_svc, FM_FMRI_SVC_NAME,
149 	    svc_fmri) != 0)
150 		return (1);
151 
152 	return (0);
153 }
154 
155 /*
156  * fps_fmri_cpu_set(nvlist_t *fmri_cpu, uint32_t cpu_id)
157  * adds the resource data to fmri_cpu.
158  */
159 static int
fps_fmri_cpu_set(nvlist_t * fmri_cpu,uint32_t cpu_id)160 fps_fmri_cpu_set(nvlist_t *fmri_cpu, uint32_t cpu_id)
161 {
162 	if (fmri_cpu == NULL)
163 		return (1);
164 
165 	if (nvlist_add_uint8(fmri_cpu, FM_VERSION,
166 	    FM_CPU_SCHEME_VERSION) != 0)
167 		return (1);
168 
169 	if (nvlist_add_string(fmri_cpu, FM_FMRI_SCHEME,
170 	    FM_FMRI_SCHEME_CPU) != 0)
171 		return (1);
172 
173 	if (nvlist_add_uint32(fmri_cpu, FM_FMRI_CPU_ID, cpu_id) != 0)
174 		return (1);
175 	return (0);
176 }
177 
178 /*
179  * fps_post_ereport(nvlist_t *ereport) posts an
180  * ereport to the sysevent error channel.  The error
181  * channel is assumed to be established by fps-transport.so.
182  */
183 static int
fps_post_ereport(nvlist_t * ereport)184 fps_post_ereport(nvlist_t *ereport)
185 {
186 	evchan_t *scp;
187 
188 	if (sysevent_evc_bind(CHANNEL, &scp, BIND_FLAGS) != 0) {
189 		return (1);
190 	}
191 
192 	if (sysevent_evc_publish(scp, CLASS, SUBCLASS, VENDOR,
193 	    PUBLISHER, ereport, EVCH_NOSLEEP) != 0) {
194 		return (1);
195 	}
196 
197 	(void) sleep(1);
198 
199 	(void) fflush(NULL);
200 	(void) sysevent_evc_unbind(scp);
201 
202 	return (0);
203 }
204 /*
205  * fps_convert_cpu_brand(char *brand) changes
206  * the kstat data to match the ereport class
207  * names.
208  */
209 static char *
fps_convert_cpu_brand(char * brand)210 fps_convert_cpu_brand(char *brand)
211 {
212 	if (brand == NULL)
213 		return (NULL);
214 
215 	if (strcasecmp(brand, USIII_KSTAT) == 0)
216 		return (USIII);
217 	else if (strcasecmp(brand, USIIIi_KSTAT) == 0)
218 		return (USIIIi);
219 	else if (strcasecmp(brand, USIIIP_KSTAT) == 0)
220 		return (USIIIP);
221 	else if (strcasecmp(brand, USIV_KSTAT) == 0)
222 		return (USIV);
223 	else if (strcasecmp(brand, USIVP_KSTAT) == 0)
224 		return (USIVP);
225 	else
226 		return (NULL);
227 }
228 
229 /*
230  * get_cpu_brand(uint32_t cpu_id)gets the
231  * brand of the CPU and returns the CPU
232  * name to use in the ereport class name.
233  */
234 static char *
fps_get_cpu_brand(uint32_t cpu_id)235 fps_get_cpu_brand(uint32_t cpu_id)
236 {
237 	char *brand;
238 	kstat_ctl_t *kc;
239 	kstat_t *ksp;
240 	kstat_named_t *knp;
241 
242 	kc = kstat_open();
243 	if (kc == NULL) {
244 		return (NULL);
245 	}
246 
247 	if ((ksp = kstat_lookup(kc, "cpu_info", (int)cpu_id, NULL)) == NULL) {
248 		(void) kstat_close(kc);
249 		return (NULL);
250 	}
251 
252 	if ((kstat_read(kc, ksp, NULL)) == -1) {
253 		(void) kstat_close(kc);
254 		return (NULL);
255 	}
256 
257 	if ((knp = kstat_data_lookup(ksp, "brand")) == NULL) {
258 		(void) kstat_close(kc);
259 		return (NULL);
260 	}
261 
262 	brand = fps_convert_cpu_brand(KSTAT_NAMED_STR_PTR(knp));
263 	(void) kstat_close(kc);
264 
265 	if (brand == NULL)
266 		return (NULL);
267 
268 	return (brand);
269 }
270 
271 /*
272  * fps_generate_ereport_struct(struct fps_test_ereport *report)
273  * takes report and constructs an nvlist that will be used
274  * for the ereport.
275  */
276 int
fps_generate_ereport_struct(struct fps_test_ereport * report)277 fps_generate_ereport_struct(struct fps_test_ereport *report)
278 {
279 	char class_name[FM_MAX_CLASS];
280 	char *cpu_brand;
281 	char *string_data;
282 	int expect_size;
283 	int is_valid_cpu;
284 	int mask;
285 	int observe_size;
286 	int ret;
287 	nvlist_t *detector;
288 	nvlist_t *ereport;
289 	nvlist_t *resource;
290 	uint32_t cpu_id;
291 	uint32_t test;
292 	uint8_t fps_ver;
293 	uint64_t ena;
294 	uint64_t ereport_time;
295 	uint64_t *expect;
296 	uint64_t *observe;
297 
298 	if (report == NULL)
299 		return (FPU_EREPORT_FAIL);
300 
301 	ret = FPU_FOROFFLINE;
302 	cpu_id = report->cpu_id;
303 	test = report->test_id;
304 	mask = report->mask;
305 	is_valid_cpu = report->is_valid_cpu;
306 	expect_size = report->expected_size;
307 	expect = report->expected;
308 	observe_size = report->observed_size;
309 	observe = report->observed;
310 	string_data = report->info;
311 
312 	/* allocate nvlists */
313 	if ((ereport = fps_nvlist_create()) == NULL)
314 		_exit(FPU_EREPORT_FAIL);
315 
316 	if ((detector = fps_nvlist_create()) == NULL) {
317 		_exit(FPU_EREPORT_FAIL);
318 	}
319 
320 	/* setup class */
321 	if ((cpu_brand = fps_get_cpu_brand(cpu_id)) == NULL)
322 		_exit(FPU_EREPORT_FAIL);
323 
324 	if ((snprintf(class_name, FM_MAX_CLASS, "%s.%s.%s",
325 	    CLASS_HEAD, cpu_brand, CLASS_TAIL)) < 0)
326 		_exit(FPU_EREPORT_FAIL);
327 
328 	/* setup ena */
329 	ereport_time = gethrtime();
330 	ena = fps_ena_generate(ereport_time, cpu_id, FM_ENA_FMT1);
331 
332 	/* setup detector */
333 	if (fps_fmri_svc_set(detector, getenv("SMF_FMRI")) != 0) {
334 		_exit(FPU_EREPORT_FAIL);
335 	}
336 
337 	/* setup fps-version */
338 	fps_ver = FPS_VERSION;
339 
340 	/* setup resource */
341 	if (is_valid_cpu) {
342 		resource = fps_nvlist_create();
343 
344 		if (fps_fmri_cpu_set(resource, cpu_id)) {
345 			_exit(FPU_EREPORT_FAIL);
346 		}
347 	} else {
348 		resource = NULL;
349 	}
350 
351 	/* put it together */
352 	if (nvlist_add_string(ereport, NAME_FPS_CLASS, class_name) != 0)
353 		_exit(FPU_EREPORT_FAIL);
354 
355 	if (ena != 0) {
356 		if (nvlist_add_uint64(ereport, NAME_FPS_ENA, ena) != 0)
357 			_exit(FPU_EREPORT_FAIL);
358 	} else
359 		_exit(FPU_EREPORT_FAIL);
360 
361 	if (nvlist_add_nvlist(ereport, NAME_FPS_DETECTOR,
362 	    (nvlist_t *)detector) != 0)
363 		_exit(FPU_EREPORT_FAIL);
364 
365 	if (nvlist_add_uint8(ereport, NAME_FPS_VERSION, fps_ver) != 0)
366 		_exit(FPU_EREPORT_FAIL);
367 
368 	if (nvlist_add_uint32(ereport, NAME_FPS_TEST_ID, test) != 0)
369 		ret = FPU_EREPORT_INCOM;
370 
371 	if (nvlist_add_uint64_array(ereport, NAME_FPS_EXPECTED_VALUE,
372 	    expect, expect_size) != 0)
373 		ret = FPU_EREPORT_INCOM;
374 
375 	if (nvlist_add_uint64_array(ereport, NAME_FPS_OBSERVED_VALUE,
376 	    observe, observe_size) != 0)
377 		ret = FPU_EREPORT_INCOM;
378 
379 	if (mask & IS_EREPORT_INFO) {
380 		if (nvlist_add_string(ereport, NAME_FPS_STRING_DATA,
381 		    string_data) != 0)
382 			ret = FPU_EREPORT_INCOM;
383 	}
384 
385 	if (is_valid_cpu) {
386 		if (nvlist_add_nvlist(ereport, NAME_FPS_RESOURCE,
387 		    (nvlist_t *)resource) != 0)
388 			_exit(FPU_EREPORT_FAIL);
389 	}
390 
391 	/* publish */
392 	if (fps_post_ereport(ereport)) {
393 		ret = FPU_EREPORT_FAIL;
394 	}
395 
396 	/* free nvlists */
397 	nvlist_free(ereport);
398 
399 	if (resource != NULL)
400 		nvlist_free(resource);
401 
402 	if (detector != NULL)
403 		nvlist_free(detector);
404 
405 	return (ret);
406 }
407 
408 /*
409  * initialize_fps_test_struct(struct fps_test_ereport *init_me)
410  * creates the initial values for the init_me.
411  */
412 void
initialize_fps_test_struct(struct fps_test_ereport * init_me)413 initialize_fps_test_struct(struct fps_test_ereport *init_me)
414 {
415 	if (init_me == NULL)
416 		return;
417 
418 	init_me->cpu_id = 0;
419 	init_me->test_id = 0;
420 	init_me->observed_size = 0;
421 	init_me->expected_size = 0;
422 	init_me->is_valid_cpu = 1;
423 	init_me->info[0] = '\0';
424 	init_me->mask = NO_EREPORT_INFO;
425 }
426 
427 /*
428  * setup_fps_test_struct(int mask, struct fps_test_ereport *rep,
429  * ...) takes a variable amount of input and stores it in rep
430  * based on mask provided.
431  */
432 void
setup_fps_test_struct(int mask,struct fps_test_ereport * rep,...)433 setup_fps_test_struct(int mask, struct fps_test_ereport *rep, ...)
434 {
435 	char *data;
436 	int i;
437 	uint64_t *exp_arg;
438 	uint64_t *obs_arg;
439 	va_list argptr;
440 
441 	if (rep == NULL)
442 		return;
443 
444 	/* begin parsing args */
445 	va_start(argptr, rep);
446 
447 	/* test id */
448 	rep->test_id = va_arg(argptr, int);
449 
450 	/* observed */
451 	obs_arg = va_arg(argptr, uint64_t *);
452 
453 	/* expected */
454 	exp_arg = va_arg(argptr, uint64_t *);
455 
456 	/* observed size */
457 	rep->observed_size = va_arg(argptr, int);
458 
459 	/* expected size */
460 	rep->expected_size = va_arg(argptr, int);
461 
462 	/* copy arrays of observed and expected */
463 	if (rep->observed_size < 1 || rep->expected_size < 1)
464 		return;
465 
466 	if (obs_arg == NULL || exp_arg == NULL)
467 		return;
468 
469 	for (i = 0; i < rep->observed_size; i++)
470 		rep->observed[i] = obs_arg[i];
471 
472 	for (i = 0; i < rep->expected_size; i++)
473 		rep->expected[i] = exp_arg[i];
474 
475 	rep->mask = mask;
476 
477 	/* copy string data if there */
478 	if (mask & IS_EREPORT_INFO)	{
479 		data = va_arg(argptr, char *);
480 
481 		if (data == NULL) {
482 			va_end(argptr);
483 
484 			return;
485 		}
486 
487 		(void) strlcpy(rep->info, data, MAX_INFO_SIZE-1);
488 	}
489 
490 	va_end(argptr);
491 }
492