1219089Spjd/*-
2219089Spjd * Copyright (c) 2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3219089Spjd * All rights reserved.
4219089Spjd *
5219089Spjd * Redistribution and use in source and binary forms, with or without
6219089Spjd * modification, are permitted provided that the following conditions
7219089Spjd * are met:
8219089Spjd * 1. Redistributions of source code must retain the above copyright
9219089Spjd *    notice, this list of conditions and the following disclaimer.
10219089Spjd * 2. Redistributions in binary form must reproduce the above copyright
11219089Spjd *    notice, this list of conditions and the following disclaimer in the
12219089Spjd *    documentation and/or other materials provided with the distribution.
13219089Spjd *
14219089Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15219089Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16219089Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17219089Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18219089Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19219089Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20219089Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21219089Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22219089Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23219089Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24219089Spjd * SUCH DAMAGE.
25219089Spjd */
26219089Spjd
27219089Spjd#include <sys/cdefs.h>
28219089Spjd__FBSDID("$FreeBSD$");
29219089Spjd
30219089Spjd#include <sys/param.h>
31219089Spjd#include <sys/kernel.h>
32219089Spjd#include <sys/systm.h>
33219089Spjd#include <sys/malloc.h>
34219089Spjd#include <sys/kmem.h>
35219089Spjd#include <sys/sbuf.h>
36219089Spjd#include <sys/bus.h>
37219089Spjd#include <sys/nvpair.h>
38219089Spjd#include <sys/sunddi.h>
39219089Spjd#include <sys/sysevent.h>
40219089Spjd#include <sys/fm/protocol.h>
41219089Spjd
42219089Spjdstruct sysevent {
43219089Spjd	nvlist_t	*se_nvl;
44219089Spjd	char		 se_class[128];
45219089Spjd	char		 se_subclass[128];
46219089Spjd	char		 se_pub[128];
47219089Spjd};
48219089Spjd
49219089Spjdsysevent_t *
50219089Spjdsysevent_alloc(char *class, char *subclass, char *pub, int flag)
51219089Spjd{
52219089Spjd	struct sysevent *ev;
53219089Spjd
54219089Spjd	ASSERT(class != NULL);
55219089Spjd	ASSERT(subclass != NULL);
56219089Spjd	ASSERT(pub != NULL);
57219089Spjd	ASSERT(flag == SE_SLEEP);
58219089Spjd
59219089Spjd	ev = kmem_alloc(sizeof(*ev), KM_SLEEP);
60219089Spjd	ev->se_nvl = NULL;
61219089Spjd	strlcpy(ev->se_class, class, sizeof(ev->se_class));
62219089Spjd	strlcpy(ev->se_subclass, subclass, sizeof(ev->se_subclass));
63219089Spjd	strlcpy(ev->se_pub, pub, sizeof(ev->se_pub));
64219089Spjd
65219089Spjd	return ((sysevent_t *)ev);
66219089Spjd}
67219089Spjd
68219089Spjdvoid
69219089Spjdsysevent_free(sysevent_t *evp)
70219089Spjd{
71219089Spjd	struct sysevent *ev = (struct sysevent *)evp;
72219089Spjd
73219089Spjd	ASSERT(evp != NULL);
74219089Spjd
75219089Spjd	if (ev->se_nvl != NULL)
76219089Spjd		sysevent_free_attr(ev->se_nvl);
77219089Spjd	kmem_free(ev, sizeof(*ev));
78219089Spjd}
79219089Spjd
80219089Spjdint
81219089Spjdsysevent_add_attr(sysevent_attr_list_t **ev_attr_list, char *name,
82219089Spjd    sysevent_value_t *se_value, int flag)
83219089Spjd{
84219089Spjd	nvlist_t *nvl;
85219089Spjd	int error;
86219089Spjd
87219089Spjd	ASSERT(ev_attr_list != NULL);
88219089Spjd	ASSERT(name != NULL);
89219089Spjd	ASSERT(se_value != NULL);
90219089Spjd	ASSERT(flag == SE_SLEEP);
91219089Spjd
92219089Spjd	if (strlen(name) >= MAX_ATTR_NAME)
93219089Spjd		return (SE_EINVAL);
94219089Spjd
95219089Spjd	nvl = *ev_attr_list;
96219089Spjd	if (nvl == NULL) {
97219089Spjd		if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, KM_SLEEP) != 0)
98219089Spjd			return (SE_ENOMEM);
99219089Spjd	}
100219089Spjd
101219089Spjd	error = 0;
102219089Spjd
103219089Spjd	switch (se_value->value_type) {
104219089Spjd	case SE_DATA_TYPE_UINT64:
105219089Spjd		error = nvlist_add_uint64(nvl, name, se_value->value.sv_uint64);
106219089Spjd		break;
107219089Spjd	case SE_DATA_TYPE_STRING:
108219089Spjd		if (strlen(se_value->value.sv_string) >= MAX_STRING_SZ)
109219089Spjd			error = SE_EINVAL;
110219089Spjd		if (error == 0) {
111219089Spjd			error = nvlist_add_string(nvl, name,
112219089Spjd			    se_value->value.sv_string);
113219089Spjd		}
114219089Spjd		break;
115219089Spjd	default:
116222343Spjd#if 0
117219089Spjd		printf("%s: type %d is not implemented\n", __func__,
118219089Spjd		    se_value->value_type);
119222343Spjd#endif
120219089Spjd		break;
121219089Spjd	}
122219089Spjd
123219089Spjd	if (error != 0) {
124219089Spjd		nvlist_free(nvl);
125219089Spjd		return (error);
126219089Spjd	}
127219089Spjd
128219089Spjd	*ev_attr_list = nvl;
129219089Spjd
130219089Spjd	return (0);
131219089Spjd}
132219089Spjd
133219089Spjdvoid
134219089Spjdsysevent_free_attr(sysevent_attr_list_t *ev_attr_list)
135219089Spjd{
136219089Spjd
137219089Spjd	nvlist_free(ev_attr_list);
138219089Spjd}
139219089Spjd
140219089Spjdint
141219089Spjdsysevent_attach_attributes(sysevent_t *evp, sysevent_attr_list_t *ev_attr_list)
142219089Spjd{
143219089Spjd	struct sysevent *ev = (struct sysevent *)evp;
144219089Spjd
145219089Spjd	ASSERT(ev->se_nvl == NULL);
146219089Spjd
147219089Spjd	ev->se_nvl = ev_attr_list;
148219089Spjd
149219089Spjd	return (0);
150219089Spjd}
151219089Spjd
152219089Spjdvoid
153219089Spjdsysevent_detach_attributes(sysevent_t *evp)
154219089Spjd{
155219089Spjd	struct sysevent *ev = (struct sysevent *)evp;
156219089Spjd
157219089Spjd	ASSERT(ev->se_nvl != NULL);
158219089Spjd
159219089Spjd	ev->se_nvl = NULL;
160219089Spjd}
161219089Spjd
162219089Spjdint
163219089Spjdlog_sysevent(sysevent_t *evp, int flag, sysevent_id_t *eid)
164219089Spjd{
165219089Spjd	struct sysevent *ev = (struct sysevent *)evp;
166219089Spjd	struct sbuf *sb;
167219089Spjd	const char *type;
168219089Spjd	char typestr[128];
169219089Spjd	nvpair_t *elem = NULL;
170219089Spjd
171219089Spjd	ASSERT(evp != NULL);
172219089Spjd	ASSERT(ev->se_nvl != NULL);
173219089Spjd	ASSERT(flag == SE_SLEEP);
174219089Spjd	ASSERT(eid != NULL);
175219089Spjd
176219089Spjd	sb = sbuf_new_auto();
177219089Spjd	if (sb == NULL)
178219089Spjd		return (SE_ENOMEM);
179219089Spjd	type = NULL;
180219089Spjd
181219089Spjd	while ((elem = nvlist_next_nvpair(ev->se_nvl, elem)) != NULL) {
182219089Spjd		switch (nvpair_type(elem)) {
183219089Spjd		case DATA_TYPE_BOOLEAN:
184219089Spjd		    {
185219089Spjd			boolean_t value;
186219089Spjd
187219089Spjd			(void) nvpair_value_boolean_value(elem, &value);
188219089Spjd			sbuf_printf(sb, " %s=%s", nvpair_name(elem),
189219089Spjd			    value ? "true" : "false");
190219089Spjd			break;
191219089Spjd		    }
192219089Spjd		case DATA_TYPE_UINT8:
193219089Spjd		    {
194219089Spjd			uint8_t value;
195219089Spjd
196219089Spjd			(void) nvpair_value_uint8(elem, &value);
197219089Spjd			sbuf_printf(sb, " %s=%hhu", nvpair_name(elem), value);
198219089Spjd			break;
199219089Spjd		    }
200219089Spjd		case DATA_TYPE_INT32:
201219089Spjd		    {
202219089Spjd			int32_t value;
203219089Spjd
204219089Spjd			(void) nvpair_value_int32(elem, &value);
205219089Spjd			sbuf_printf(sb, " %s=%jd", nvpair_name(elem),
206219089Spjd			    (intmax_t)value);
207219089Spjd			break;
208219089Spjd		    }
209219089Spjd		case DATA_TYPE_UINT32:
210219089Spjd		    {
211219089Spjd			uint32_t value;
212219089Spjd
213219089Spjd			(void) nvpair_value_uint32(elem, &value);
214219089Spjd			sbuf_printf(sb, " %s=%ju", nvpair_name(elem),
215219089Spjd			    (uintmax_t)value);
216219089Spjd			break;
217219089Spjd		    }
218219089Spjd		case DATA_TYPE_INT64:
219219089Spjd		    {
220219089Spjd			int64_t value;
221219089Spjd
222219089Spjd			(void) nvpair_value_int64(elem, &value);
223219089Spjd			sbuf_printf(sb, " %s=%jd", nvpair_name(elem),
224219089Spjd			    (intmax_t)value);
225219089Spjd			break;
226219089Spjd		    }
227219089Spjd		case DATA_TYPE_UINT64:
228219089Spjd		    {
229219089Spjd			uint64_t value;
230219089Spjd
231219089Spjd			(void) nvpair_value_uint64(elem, &value);
232219089Spjd			sbuf_printf(sb, " %s=%ju", nvpair_name(elem),
233219089Spjd			    (uintmax_t)value);
234219089Spjd			break;
235219089Spjd		    }
236219089Spjd		case DATA_TYPE_STRING:
237219089Spjd		    {
238219089Spjd			char *value;
239219089Spjd
240219089Spjd			(void) nvpair_value_string(elem, &value);
241219089Spjd			sbuf_printf(sb, " %s=%s", nvpair_name(elem), value);
242219089Spjd			if (strcmp(FM_CLASS, nvpair_name(elem)) == 0)
243219089Spjd				type = value;
244219089Spjd			break;
245219089Spjd		    }
246219089Spjd		case DATA_TYPE_UINT8_ARRAY:
247219089Spjd		    {
248219089Spjd		    	uint8_t *value;
249219089Spjd			uint_t ii, nelem;
250219089Spjd
251219089Spjd			(void) nvpair_value_uint8_array(elem, &value, &nelem);
252219089Spjd			sbuf_printf(sb, " %s=", nvpair_name(elem));
253219089Spjd			for (ii = 0; ii < nelem; ii++)
254219089Spjd				sbuf_printf(sb, "%02hhx", value[ii]);
255219089Spjd			break;
256219089Spjd		    }
257219089Spjd		case DATA_TYPE_UINT16_ARRAY:
258219089Spjd		    {
259219089Spjd		    	uint16_t *value;
260219089Spjd			uint_t ii, nelem;
261219089Spjd
262219089Spjd			(void) nvpair_value_uint16_array(elem, &value, &nelem);
263219089Spjd			sbuf_printf(sb, " %s=", nvpair_name(elem));
264219089Spjd			for (ii = 0; ii < nelem; ii++)
265219089Spjd				sbuf_printf(sb, "%04hx", value[ii]);
266219089Spjd			break;
267219089Spjd		    }
268219089Spjd		case DATA_TYPE_UINT32_ARRAY:
269219089Spjd		    {
270219089Spjd		    	uint32_t *value;
271219089Spjd			uint_t ii, nelem;
272219089Spjd
273219089Spjd			(void) nvpair_value_uint32_array(elem, &value, &nelem);
274219089Spjd			sbuf_printf(sb, " %s=", nvpair_name(elem));
275219089Spjd			for (ii = 0; ii < nelem; ii++)
276219089Spjd				sbuf_printf(sb, "%08jx", (uintmax_t)value[ii]);
277219089Spjd			break;
278219089Spjd		    }
279219089Spjd		case DATA_TYPE_UINT64_ARRAY:
280219089Spjd		    {
281219089Spjd		    	uint64_t *value;
282219089Spjd			uint_t ii, nelem;
283219089Spjd
284219089Spjd			(void) nvpair_value_uint64_array(elem, &value, &nelem);
285219089Spjd			sbuf_printf(sb, " %s=", nvpair_name(elem));
286219089Spjd			for (ii = 0; ii < nelem; ii++)
287219089Spjd				sbuf_printf(sb, "%016jx", (uintmax_t)value[ii]);
288219089Spjd			break;
289219089Spjd		    }
290219089Spjd		default:
291222343Spjd#if 0
292219089Spjd			printf("%s: type %d is not implemented\n", __func__,
293219089Spjd			    nvpair_type(elem));
294222343Spjd#endif
295219089Spjd			break;
296219089Spjd		}
297219089Spjd	}
298219089Spjd
299219089Spjd	if (sbuf_finish(sb) != 0) {
300219089Spjd		sbuf_delete(sb);
301219089Spjd		return (SE_ENOMEM);
302219089Spjd	}
303219089Spjd
304219089Spjd	if (type == NULL)
305219089Spjd		type = ev->se_subclass;
306219089Spjd	if (strncmp(type, "ESC_ZFS_", 8) == 0) {
307219089Spjd		snprintf(typestr, sizeof(typestr), "misc.fs.zfs.%s", type + 8);
308219089Spjd		type = typestr;
309219089Spjd	}
310219089Spjd	devctl_notify("ZFS", "ZFS", type, sbuf_data(sb));
311219089Spjd	sbuf_delete(sb);
312219089Spjd
313219089Spjd	return (0);
314219089Spjd}
315219089Spjd
316219089Spjdint
317219089Spjd_ddi_log_sysevent(char *vendor, char *class, char *subclass,
318219089Spjd    nvlist_t *attr_list, sysevent_id_t *eidp, int flag)
319219089Spjd{
320219089Spjd	sysevent_t *ev;
321219089Spjd	int ret;
322219089Spjd
323219089Spjd	ASSERT(vendor != NULL);
324219089Spjd	ASSERT(class != NULL);
325219089Spjd	ASSERT(subclass != NULL);
326219089Spjd	ASSERT(attr_list != NULL);
327219089Spjd	ASSERT(eidp != NULL);
328219089Spjd	ASSERT(flag == DDI_SLEEP);
329219089Spjd
330219089Spjd	ev = sysevent_alloc(class, subclass, vendor, SE_SLEEP);
331219089Spjd	ASSERT(ev != NULL);
332219089Spjd	(void)sysevent_attach_attributes(ev, attr_list);
333219089Spjd        ret = log_sysevent(ev, SE_SLEEP, eidp);
334219089Spjd	sysevent_detach_attributes(ev);
335219089Spjd	sysevent_free(ev);
336219089Spjd
337219089Spjd	return (ret);
338219089Spjd}
339