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