Add linux events
[zfs.git] / module / zfs / fm.c
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  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24
25 /*
26  * Fault Management Architecture (FMA) Resource and Protocol Support
27  *
28  * The routines contained herein provide services to support kernel subsystems
29  * in publishing fault management telemetry (see PSARC 2002/412 and 2003/089).
30  *
31  * Name-Value Pair Lists
32  *
33  * The embodiment of an FMA protocol element (event, fmri or authority) is a
34  * name-value pair list (nvlist_t).  FMA-specific nvlist construtor and
35  * destructor functions, fm_nvlist_create() and fm_nvlist_destroy(), are used
36  * to create an nvpair list using custom allocators.  Callers may choose to
37  * allocate either from the kernel memory allocator, or from a preallocated
38  * buffer, useful in constrained contexts like high-level interrupt routines.
39  *
40  * Protocol Event and FMRI Construction
41  *
42  * Convenience routines are provided to construct nvlist events according to
43  * the FMA Event Protocol and Naming Schema specification for ereports and
44  * FMRIs for the dev, cpu, hc, mem, legacy hc and de schemes.
45  *
46  * ENA Manipulation
47  *
48  * Routines to generate ENA formats 0, 1 and 2 are available as well as
49  * routines to increment formats 1 and 2.  Individual fields within the
50  * ENA are extractable via fm_ena_time_get(), fm_ena_id_get(),
51  * fm_ena_format_get() and fm_ena_gen_get().
52  */
53
54 #include <sys/types.h>
55 #include <sys/time.h>
56 #include <sys/list.h>
57 #include <sys/nvpair.h>
58 #include <sys/cmn_err.h>
59 #include <sys/sysmacros.h>
60 #include <sys/compress.h>
61 #include <sys/sunddi.h>
62 #include <sys/systeminfo.h>
63 #include <sys/fm/util.h>
64 #include <sys/fm/protocol.h>
65 #include <sys/kstat.h>
66 #include <sys/zfs_context.h>
67 #ifdef _KERNEL
68 #include <sys/atomic.h>
69 #include <sys/condvar.h>
70 #include <sys/cpuvar.h>
71 #include <sys/systm.h>
72 #include <sys/dumphdr.h>
73 #include <sys/cpuvar.h>
74 #include <sys/console.h>
75 #include <sys/kobj.h>
76 #include <sys/time.h>
77 #include <sys/zfs_ioctl.h>
78
79 int zevent_len_max = 0;
80 int zevent_cols = 80;
81 int zevent_console = 0;
82
83 static int zevent_len_cur = 0;
84 static int zevent_waiters = 0;
85 static int zevent_flags = 0;
86
87 static kmutex_t zevent_lock;
88 static list_t zevent_list;
89 static kcondvar_t zevent_cv;
90 #endif /* _KERNEL */
91
92 extern void fastreboot_disable_highpil(void);
93
94 /*
95  * Common fault management kstats to record event generation failures
96  */
97
98 struct erpt_kstat {
99         kstat_named_t   erpt_dropped;           /* num erpts dropped on post */
100         kstat_named_t   erpt_set_failed;        /* num erpt set failures */
101         kstat_named_t   fmri_set_failed;        /* num fmri set failures */
102         kstat_named_t   payload_set_failed;     /* num payload set failures */
103 };
104
105 static struct erpt_kstat erpt_kstat_data = {
106         { "erpt-dropped", KSTAT_DATA_UINT64 },
107         { "erpt-set-failed", KSTAT_DATA_UINT64 },
108         { "fmri-set-failed", KSTAT_DATA_UINT64 },
109         { "payload-set-failed", KSTAT_DATA_UINT64 }
110 };
111
112 kstat_t *fm_ksp;
113
114 #ifdef _KERNEL
115
116 /*
117  * Formatting utility function for fm_nvprintr.  We attempt to wrap chunks of
118  * output so they aren't split across console lines, and return the end column.
119  */
120 /*PRINTFLIKE4*/
121 static int
122 fm_printf(int depth, int c, int cols, const char *format, ...)
123 {
124         va_list ap;
125         int width;
126         char c1;
127
128         va_start(ap, format);
129         width = vsnprintf(&c1, sizeof (c1), format, ap);
130         va_end(ap);
131
132         if (c + width >= cols) {
133                 console_printf("\n");
134                 c = 0;
135                 if (format[0] != ' ' && depth > 0) {
136                         console_printf(" ");
137                         c++;
138                 }
139         }
140
141         va_start(ap, format);
142         console_vprintf(format, ap);
143         va_end(ap);
144
145         return ((c + width) % cols);
146 }
147
148 /*
149  * Recursively print a nvlist in the specified column width and return the
150  * column we end up in.  This function is called recursively by fm_nvprint(),
151  * below.  We generically format the entire nvpair using hexadecimal
152  * integers and strings, and elide any integer arrays.  Arrays are basically
153  * used for cache dumps right now, so we suppress them so as not to overwhelm
154  * the amount of console output we produce at panic time.  This can be further
155  * enhanced as FMA technology grows based upon the needs of consumers.  All
156  * FMA telemetry is logged using the dump device transport, so the console
157  * output serves only as a fallback in case this procedure is unsuccessful.
158  */
159 static int
160 fm_nvprintr(nvlist_t *nvl, int d, int c, int cols)
161 {
162         nvpair_t *nvp;
163
164         for (nvp = nvlist_next_nvpair(nvl, NULL);
165             nvp != NULL; nvp = nvlist_next_nvpair(nvl, nvp)) {
166
167                 data_type_t type = nvpair_type(nvp);
168                 const char *name = nvpair_name(nvp);
169
170                 boolean_t b;
171                 uint8_t i8;
172                 uint16_t i16;
173                 uint32_t i32;
174                 uint64_t i64;
175                 char *str;
176                 nvlist_t *cnv;
177
178                 if (strcmp(name, FM_CLASS) == 0)
179                         continue; /* already printed by caller */
180
181                 c = fm_printf(d, c, cols, " %s=", name);
182
183                 switch (type) {
184                 case DATA_TYPE_BOOLEAN:
185                         c = fm_printf(d + 1, c, cols, " 1");
186                         break;
187
188                 case DATA_TYPE_BOOLEAN_VALUE:
189                         (void) nvpair_value_boolean_value(nvp, &b);
190                         c = fm_printf(d + 1, c, cols, b ? "1" : "0");
191                         break;
192
193                 case DATA_TYPE_BYTE:
194                         (void) nvpair_value_byte(nvp, &i8);
195                         c = fm_printf(d + 1, c, cols, "0x%x", i8);
196                         break;
197
198                 case DATA_TYPE_INT8:
199                         (void) nvpair_value_int8(nvp, (void *)&i8);
200                         c = fm_printf(d + 1, c, cols, "0x%x", i8);
201                         break;
202
203                 case DATA_TYPE_UINT8:
204                         (void) nvpair_value_uint8(nvp, &i8);
205                         c = fm_printf(d + 1, c, cols, "0x%x", i8);
206                         break;
207
208                 case DATA_TYPE_INT16:
209                         (void) nvpair_value_int16(nvp, (void *)&i16);
210                         c = fm_printf(d + 1, c, cols, "0x%x", i16);
211                         break;
212
213                 case DATA_TYPE_UINT16:
214                         (void) nvpair_value_uint16(nvp, &i16);
215                         c = fm_printf(d + 1, c, cols, "0x%x", i16);
216                         break;
217
218                 case DATA_TYPE_INT32:
219                         (void) nvpair_value_int32(nvp, (void *)&i32);
220                         c = fm_printf(d + 1, c, cols, "0x%x", i32);
221                         break;
222
223                 case DATA_TYPE_UINT32:
224                         (void) nvpair_value_uint32(nvp, &i32);
225                         c = fm_printf(d + 1, c, cols, "0x%x", i32);
226                         break;
227
228                 case DATA_TYPE_INT64:
229                         (void) nvpair_value_int64(nvp, (void *)&i64);
230                         c = fm_printf(d + 1, c, cols, "0x%llx",
231                             (u_longlong_t)i64);
232                         break;
233
234                 case DATA_TYPE_UINT64:
235                         (void) nvpair_value_uint64(nvp, &i64);
236                         c = fm_printf(d + 1, c, cols, "0x%llx",
237                             (u_longlong_t)i64);
238                         break;
239
240                 case DATA_TYPE_HRTIME:
241                         (void) nvpair_value_hrtime(nvp, (void *)&i64);
242                         c = fm_printf(d + 1, c, cols, "0x%llx",
243                             (u_longlong_t)i64);
244                         break;
245
246                 case DATA_TYPE_STRING:
247                         (void) nvpair_value_string(nvp, &str);
248                         c = fm_printf(d + 1, c, cols, "\"%s\"",
249                             str ? str : "<NULL>");
250                         break;
251
252                 case DATA_TYPE_NVLIST:
253                         c = fm_printf(d + 1, c, cols, "[");
254                         (void) nvpair_value_nvlist(nvp, &cnv);
255                         c = fm_nvprintr(cnv, d + 1, c, cols);
256                         c = fm_printf(d + 1, c, cols, " ]");
257                         break;
258
259                 case DATA_TYPE_NVLIST_ARRAY: {
260                         nvlist_t **val;
261                         uint_t i, nelem;
262
263                         c = fm_printf(d + 1, c, cols, "[");
264                         (void) nvpair_value_nvlist_array(nvp, &val, &nelem);
265                         for (i = 0; i < nelem; i++) {
266                                 c = fm_nvprintr(val[i], d + 1, c, cols);
267                         }
268                         c = fm_printf(d + 1, c, cols, " ]");
269                         }
270                         break;
271
272                 case DATA_TYPE_INT8_ARRAY: {
273                         int8_t *val;
274                         uint_t i, nelem;
275
276                         c = fm_printf(d + 1, c, cols, "[ ");
277                         (void) nvpair_value_int8_array(nvp, &val, &nelem);
278                         for (i = 0; i < nelem; i++)
279                                 c = fm_printf(d + 1, c, cols, "0x%llx ",
280                                               (u_longlong_t)val[i]);
281
282                         c = fm_printf(d + 1, c, cols, "]");
283                         break;
284                         }
285
286                 case DATA_TYPE_UINT8_ARRAY: {
287                         uint8_t *val;
288                         uint_t i, nelem;
289
290                         c = fm_printf(d + 1, c, cols, "[ ");
291                         (void) nvpair_value_uint8_array(nvp, &val, &nelem);
292                         for (i = 0; i < nelem; i++)
293                                 c = fm_printf(d + 1, c, cols, "0x%llx ",
294                                               (u_longlong_t)val[i]);
295
296                         c = fm_printf(d + 1, c, cols, "]");
297                         break;
298                         }
299
300                 case DATA_TYPE_INT16_ARRAY: {
301                         int16_t *val;
302                         uint_t i, nelem;
303
304                         c = fm_printf(d + 1, c, cols, "[ ");
305                         (void) nvpair_value_int16_array(nvp, &val, &nelem);
306                         for (i = 0; i < nelem; i++)
307                                 c = fm_printf(d + 1, c, cols, "0x%llx ",
308                                               (u_longlong_t)val[i]);
309
310                         c = fm_printf(d + 1, c, cols, "]");
311                         break;
312                         }
313
314                 case DATA_TYPE_UINT16_ARRAY: {
315                         uint16_t *val;
316                         uint_t i, nelem;
317
318                         c = fm_printf(d + 1, c, cols, "[ ");
319                         (void) nvpair_value_uint16_array(nvp, &val, &nelem);
320                         for (i = 0; i < nelem; i++)
321                                 c = fm_printf(d + 1, c, cols, "0x%llx ",
322                                               (u_longlong_t)val[i]);
323
324                         c = fm_printf(d + 1, c, cols, "]");
325                         break;
326                         }
327
328                 case DATA_TYPE_INT32_ARRAY: {
329                         int32_t *val;
330                         uint_t i, nelem;
331
332                         c = fm_printf(d + 1, c, cols, "[ ");
333                         (void) nvpair_value_int32_array(nvp, &val, &nelem);
334                         for (i = 0; i < nelem; i++)
335                                 c = fm_printf(d + 1, c, cols, "0x%llx ",
336                                               (u_longlong_t)val[i]);
337
338                         c = fm_printf(d + 1, c, cols, "]");
339                         break;
340                         }
341
342                 case DATA_TYPE_UINT32_ARRAY: {
343                         uint32_t *val;
344                         uint_t i, nelem;
345
346                         c = fm_printf(d + 1, c, cols, "[ ");
347                         (void) nvpair_value_uint32_array(nvp, &val, &nelem);
348                         for (i = 0; i < nelem; i++)
349                                 c = fm_printf(d + 1, c, cols, "0x%llx ",
350                                               (u_longlong_t)val[i]);
351
352                         c = fm_printf(d + 1, c, cols, "]");
353                         break;
354                         }
355
356                 case DATA_TYPE_INT64_ARRAY: {
357                         int64_t *val;
358                         uint_t i, nelem;
359
360                         c = fm_printf(d + 1, c, cols, "[ ");
361                         (void) nvpair_value_int64_array(nvp, &val, &nelem);
362                         for (i = 0; i < nelem; i++)
363                                 c = fm_printf(d + 1, c, cols, "0x%llx ",
364                                               (u_longlong_t)val[i]);
365
366                         c = fm_printf(d + 1, c, cols, "]");
367                         break;
368                         }
369
370                 case DATA_TYPE_UINT64_ARRAY: {
371                         uint64_t *val;
372                         uint_t i, nelem;
373
374                         c = fm_printf(d + 1, c, cols, "[ ");
375                         (void) nvpair_value_uint64_array(nvp, &val, &nelem);
376                         for (i = 0; i < nelem; i++)
377                                 c = fm_printf(d + 1, c, cols, "0x%llx ",
378                                               (u_longlong_t)val[i]);
379
380                         c = fm_printf(d + 1, c, cols, "]");
381                         break;
382                         }
383
384                 case DATA_TYPE_STRING_ARRAY:
385                 case DATA_TYPE_BOOLEAN_ARRAY:
386                 case DATA_TYPE_BYTE_ARRAY:
387                         c = fm_printf(d + 1, c, cols, "[...]");
388                         break;
389
390                 case DATA_TYPE_UNKNOWN:
391                         c = fm_printf(d + 1, c, cols, "<unknown>");
392                         break;
393                 }
394         }
395
396         return (c);
397 }
398
399 void
400 fm_nvprint(nvlist_t *nvl)
401 {
402         char *class;
403         int c = 0;
404
405         console_printf("\n");
406
407         if (nvlist_lookup_string(nvl, FM_CLASS, &class) == 0)
408                 c = fm_printf(0, c, zevent_cols, "%s", class);
409
410         if (fm_nvprintr(nvl, 0, c, zevent_cols) != 0)
411                 console_printf("\n");
412
413         console_printf("\n");
414 }
415
416 static zevent_t *
417 zfs_zevent_alloc(void)
418 {
419         zevent_t *ev;
420
421         ev = kmem_zalloc(sizeof(zevent_t), KM_SLEEP);
422         if (ev == NULL)
423                 return NULL;
424
425         list_create(&ev->ev_ze_list, sizeof(zfs_zevent_t),
426                     offsetof(zfs_zevent_t, ze_node));
427         list_link_init(&ev->ev_node);
428
429         return ev;
430 }
431
432 static void
433 zfs_zevent_free(zevent_t *ev)
434 {
435         /* Run provided cleanup callback */
436         ev->ev_cb(ev->ev_nvl, ev->ev_detector);
437
438         list_destroy(&ev->ev_ze_list);
439         kmem_free(ev, sizeof(zevent_t));
440 }
441
442 static void
443 zfs_zevent_drain(zevent_t *ev)
444 {
445         zfs_zevent_t *ze;
446
447         ASSERT(MUTEX_HELD(&zevent_lock));
448         list_remove(&zevent_list, ev);
449
450         /* Remove references to this event in all private file data */
451         while ((ze = list_head(&ev->ev_ze_list)) != NULL) {
452                 list_remove(&ev->ev_ze_list, ze);
453                 ze->ze_zevent = NULL;
454                 ze->ze_dropped++;
455         }
456
457         zfs_zevent_free(ev);
458 }
459
460 void
461 zfs_zevent_drain_all(int *count)
462 {
463         zevent_t *ev;
464
465         mutex_enter(&zevent_lock);
466         while ((ev = list_head(&zevent_list)) != NULL)
467                 zfs_zevent_drain(ev);
468
469         *count = zevent_len_cur;
470         zevent_len_cur = 0;
471         mutex_exit(&zevent_lock);
472 }
473
474 /*
475  * New zevents are inserted at the head.  If the maximum queue
476  * length is exceeded a zevent will be drained from the tail.
477  * As part of this any user space processes which currently have
478  * a reference to this zevent_t in their private data will have
479  * this reference set to NULL.
480  */
481 static void
482 zfs_zevent_insert(zevent_t *ev)
483 {
484         mutex_enter(&zevent_lock);
485         list_insert_head(&zevent_list, ev);
486         if (zevent_len_cur >= zevent_len_max)
487                 zfs_zevent_drain(list_tail(&zevent_list));
488         else
489                 zevent_len_cur++;
490
491         mutex_exit(&zevent_lock);
492 }
493
494 /*
495  * Post a zevent
496  */
497 void
498 zfs_zevent_post(nvlist_t *nvl, nvlist_t *detector, zevent_cb_t *cb)
499 {
500         int64_t tv_array[2];
501         timestruc_t tv;
502         size_t nvl_size = 0;
503         zevent_t *ev;
504
505         gethrestime(&tv);
506         tv_array[0] = tv.tv_sec;
507         tv_array[1] = tv.tv_nsec;
508         if (nvlist_add_int64_array(nvl, FM_EREPORT_TIME, tv_array, 2)) {
509                 atomic_add_64(&erpt_kstat_data.erpt_set_failed.value.ui64, 1);
510                 return;
511         }
512
513         (void) nvlist_size(nvl, &nvl_size, NV_ENCODE_NATIVE);
514         if (nvl_size > ERPT_DATA_SZ || nvl_size == 0) {
515                 atomic_add_64(&erpt_kstat_data.erpt_dropped.value.ui64, 1);
516                 return;
517         }
518
519         if (zevent_console)
520                 fm_nvprint(nvl);
521
522         ev = zfs_zevent_alloc();
523         if (ev == NULL) {
524                 atomic_add_64(&erpt_kstat_data.erpt_dropped.value.ui64, 1);
525                 return;
526         }
527
528         ev->ev_nvl = nvl;
529         ev->ev_detector = detector;
530         ev->ev_cb = cb;
531         zfs_zevent_insert(ev);
532         cv_broadcast(&zevent_cv);
533 }
534
535 static int
536 zfs_zevent_minor_to_state(minor_t minor, zfs_zevent_t **ze)
537 {
538         *ze = zfsdev_get_state(minor, ZST_ZEVENT);
539         if (*ze == NULL)
540                 return (EBADF);
541
542         return (0);
543 }
544
545 int
546 zfs_zevent_fd_hold(int fd, minor_t *minorp, zfs_zevent_t **ze)
547 {
548         file_t *fp;
549         int error;
550
551         fp = getf(fd);
552         if (fp == NULL)
553                 return (EBADF);
554
555         *minorp = zfsdev_getminor(fp->f_file);
556         error = zfs_zevent_minor_to_state(*minorp, ze);
557
558         if (error)
559                 zfs_zevent_fd_rele(fd);
560
561         return (error);
562 }
563
564 void
565 zfs_zevent_fd_rele(int fd)
566 {
567         releasef(fd);
568 }
569
570 /*
571  * Get the next zevent in the stream and place a copy in 'event'.
572  */
573 int
574 zfs_zevent_next(zfs_zevent_t *ze, nvlist_t **event, uint64_t *dropped)
575 {
576         zevent_t *ev;
577         int error;
578
579         mutex_enter(&zevent_lock);
580         if (ze->ze_zevent == NULL) {
581                 /* New stream start at the beginning/tail */
582                 ev = list_tail(&zevent_list);
583                 if (ev == NULL) {
584                         error = ENOENT;
585                         goto out;
586                 }
587         } else {
588                 /* Existing stream continue with the next element and remove
589                  * ourselves from the wait queue for the previous element */
590                 ev = list_prev(&zevent_list, ze->ze_zevent);
591                 if (ev == NULL) {
592                         error = ENOENT;
593                         goto out;
594                 }
595
596                 list_remove(&ze->ze_zevent->ev_ze_list, ze);
597         }
598
599         ze->ze_zevent = ev;
600         list_insert_head(&ev->ev_ze_list, ze);
601         nvlist_dup(ev->ev_nvl, event, KM_SLEEP);
602         *dropped = ze->ze_dropped;
603         ze->ze_dropped = 0;
604 out:
605         mutex_exit(&zevent_lock);
606
607         return error;
608 }
609
610 int
611 zfs_zevent_wait(zfs_zevent_t *ze)
612 {
613         int error = 0;
614
615         mutex_enter(&zevent_lock);
616
617         if (zevent_flags & ZEVENT_SHUTDOWN) {
618                 error = ESHUTDOWN;
619                 goto out;
620         }
621
622         zevent_waiters++;
623         cv_wait_interruptible(&zevent_cv, &zevent_lock);
624         if (issig(JUSTLOOKING))
625                 error = EINTR;
626
627         zevent_waiters--;
628 out:
629         mutex_exit(&zevent_lock);
630
631         return error;
632 }
633
634 void
635 zfs_zevent_init(zfs_zevent_t **zep)
636 {
637         zfs_zevent_t *ze;
638
639         ze = *zep = kmem_zalloc(sizeof (zfs_zevent_t), KM_SLEEP);
640         list_link_init(&ze->ze_node);
641 }
642
643 void
644 zfs_zevent_destroy(zfs_zevent_t *ze)
645 {
646         mutex_enter(&zevent_lock);
647         if (ze->ze_zevent)
648                 list_remove(&ze->ze_zevent->ev_ze_list, ze);
649         mutex_exit(&zevent_lock);
650
651         kmem_free(ze, sizeof (zfs_zevent_t));
652 }
653 #endif /* _KERNEL */
654
655 /*
656  * Wrapppers for FM nvlist allocators
657  */
658 /* ARGSUSED */
659 static void *
660 i_fm_alloc(nv_alloc_t *nva, size_t size)
661 {
662         return (kmem_zalloc(size, KM_SLEEP));
663 }
664
665 /* ARGSUSED */
666 static void
667 i_fm_free(nv_alloc_t *nva, void *buf, size_t size)
668 {
669         kmem_free(buf, size);
670 }
671
672 const nv_alloc_ops_t fm_mem_alloc_ops = {
673         NULL,
674         NULL,
675         i_fm_alloc,
676         i_fm_free,
677         NULL
678 };
679
680 /*
681  * Create and initialize a new nv_alloc_t for a fixed buffer, buf.  A pointer
682  * to the newly allocated nv_alloc_t structure is returned upon success or NULL
683  * is returned to indicate that the nv_alloc structure could not be created.
684  */
685 nv_alloc_t *
686 fm_nva_xcreate(char *buf, size_t bufsz)
687 {
688         nv_alloc_t *nvhdl = kmem_zalloc(sizeof (nv_alloc_t), KM_SLEEP);
689
690         if (bufsz == 0 || nv_alloc_init(nvhdl, nv_fixed_ops, buf, bufsz) != 0) {
691                 kmem_free(nvhdl, sizeof (nv_alloc_t));
692                 return (NULL);
693         }
694
695         return (nvhdl);
696 }
697
698 /*
699  * Destroy a previously allocated nv_alloc structure.  The fixed buffer
700  * associated with nva must be freed by the caller.
701  */
702 void
703 fm_nva_xdestroy(nv_alloc_t *nva)
704 {
705         nv_alloc_fini(nva);
706         kmem_free(nva, sizeof (nv_alloc_t));
707 }
708
709 /*
710  * Create a new nv list.  A pointer to a new nv list structure is returned
711  * upon success or NULL is returned to indicate that the structure could
712  * not be created.  The newly created nv list is created and managed by the
713  * operations installed in nva.   If nva is NULL, the default FMA nva
714  * operations are installed and used.
715  *
716  * When called from the kernel and nva == NULL, this function must be called
717  * from passive kernel context with no locks held that can prevent a
718  * sleeping memory allocation from occurring.  Otherwise, this function may
719  * be called from other kernel contexts as long a valid nva created via
720  * fm_nva_create() is supplied.
721  */
722 nvlist_t *
723 fm_nvlist_create(nv_alloc_t *nva)
724 {
725         int hdl_alloced = 0;
726         nvlist_t *nvl;
727         nv_alloc_t *nvhdl;
728
729         if (nva == NULL) {
730                 nvhdl = kmem_zalloc(sizeof (nv_alloc_t), KM_SLEEP);
731
732                 if (nv_alloc_init(nvhdl, &fm_mem_alloc_ops, NULL, 0) != 0) {
733                         kmem_free(nvhdl, sizeof (nv_alloc_t));
734                         return (NULL);
735                 }
736                 hdl_alloced = 1;
737         } else {
738                 nvhdl = nva;
739         }
740
741         if (nvlist_xalloc(&nvl, NV_UNIQUE_NAME, nvhdl) != 0) {
742                 if (hdl_alloced) {
743                         nv_alloc_fini(nvhdl);
744                         kmem_free(nvhdl, sizeof (nv_alloc_t));
745                 }
746                 return (NULL);
747         }
748
749         return (nvl);
750 }
751
752 /*
753  * Destroy a previously allocated nvlist structure.  flag indicates whether
754  * or not the associated nva structure should be freed (FM_NVA_FREE) or
755  * retained (FM_NVA_RETAIN).  Retaining the nv alloc structure allows
756  * it to be re-used for future nvlist creation operations.
757  */
758 void
759 fm_nvlist_destroy(nvlist_t *nvl, int flag)
760 {
761         nv_alloc_t *nva = nvlist_lookup_nv_alloc(nvl);
762
763         nvlist_free(nvl);
764
765         if (nva != NULL) {
766                 if (flag == FM_NVA_FREE)
767                         fm_nva_xdestroy(nva);
768         }
769 }
770
771 int
772 i_fm_payload_set(nvlist_t *payload, const char *name, va_list ap)
773 {
774         int nelem, ret = 0;
775         data_type_t type;
776
777         while (ret == 0 && name != NULL) {
778                 type = va_arg(ap, data_type_t);
779                 switch (type) {
780                 case DATA_TYPE_BYTE:
781                         ret = nvlist_add_byte(payload, name,
782                             va_arg(ap, uint_t));
783                         break;
784                 case DATA_TYPE_BYTE_ARRAY:
785                         nelem = va_arg(ap, int);
786                         ret = nvlist_add_byte_array(payload, name,
787                             va_arg(ap, uchar_t *), nelem);
788                         break;
789                 case DATA_TYPE_BOOLEAN_VALUE:
790                         ret = nvlist_add_boolean_value(payload, name,
791                             va_arg(ap, boolean_t));
792                         break;
793                 case DATA_TYPE_BOOLEAN_ARRAY:
794                         nelem = va_arg(ap, int);
795                         ret = nvlist_add_boolean_array(payload, name,
796                             va_arg(ap, boolean_t *), nelem);
797                         break;
798                 case DATA_TYPE_INT8:
799                         ret = nvlist_add_int8(payload, name,
800                             va_arg(ap, int));
801                         break;
802                 case DATA_TYPE_INT8_ARRAY:
803                         nelem = va_arg(ap, int);
804                         ret = nvlist_add_int8_array(payload, name,
805                             va_arg(ap, int8_t *), nelem);
806                         break;
807                 case DATA_TYPE_UINT8:
808                         ret = nvlist_add_uint8(payload, name,
809                             va_arg(ap, uint_t));
810                         break;
811                 case DATA_TYPE_UINT8_ARRAY:
812                         nelem = va_arg(ap, int);
813                         ret = nvlist_add_uint8_array(payload, name,
814                             va_arg(ap, uint8_t *), nelem);
815                         break;
816                 case DATA_TYPE_INT16:
817                         ret = nvlist_add_int16(payload, name,
818                             va_arg(ap, int));
819                         break;
820                 case DATA_TYPE_INT16_ARRAY:
821                         nelem = va_arg(ap, int);
822                         ret = nvlist_add_int16_array(payload, name,
823                             va_arg(ap, int16_t *), nelem);
824                         break;
825                 case DATA_TYPE_UINT16:
826                         ret = nvlist_add_uint16(payload, name,
827                             va_arg(ap, uint_t));
828                         break;
829                 case DATA_TYPE_UINT16_ARRAY:
830                         nelem = va_arg(ap, int);
831                         ret = nvlist_add_uint16_array(payload, name,
832                             va_arg(ap, uint16_t *), nelem);
833                         break;
834                 case DATA_TYPE_INT32:
835                         ret = nvlist_add_int32(payload, name,
836                             va_arg(ap, int32_t));
837                         break;
838                 case DATA_TYPE_INT32_ARRAY:
839                         nelem = va_arg(ap, int);
840                         ret = nvlist_add_int32_array(payload, name,
841                             va_arg(ap, int32_t *), nelem);
842                         break;
843                 case DATA_TYPE_UINT32:
844                         ret = nvlist_add_uint32(payload, name,
845                             va_arg(ap, uint32_t));
846                         break;
847                 case DATA_TYPE_UINT32_ARRAY:
848                         nelem = va_arg(ap, int);
849                         ret = nvlist_add_uint32_array(payload, name,
850                             va_arg(ap, uint32_t *), nelem);
851                         break;
852                 case DATA_TYPE_INT64:
853                         ret = nvlist_add_int64(payload, name,
854                             va_arg(ap, int64_t));
855                         break;
856                 case DATA_TYPE_INT64_ARRAY:
857                         nelem = va_arg(ap, int);
858                         ret = nvlist_add_int64_array(payload, name,
859                             va_arg(ap, int64_t *), nelem);
860                         break;
861                 case DATA_TYPE_UINT64:
862                         ret = nvlist_add_uint64(payload, name,
863                             va_arg(ap, uint64_t));
864                         break;
865                 case DATA_TYPE_UINT64_ARRAY:
866                         nelem = va_arg(ap, int);
867                         ret = nvlist_add_uint64_array(payload, name,
868                             va_arg(ap, uint64_t *), nelem);
869                         break;
870                 case DATA_TYPE_STRING:
871                         ret = nvlist_add_string(payload, name,
872                             va_arg(ap, char *));
873                         break;
874                 case DATA_TYPE_STRING_ARRAY:
875                         nelem = va_arg(ap, int);
876                         ret = nvlist_add_string_array(payload, name,
877                             va_arg(ap, char **), nelem);
878                         break;
879                 case DATA_TYPE_NVLIST:
880                         ret = nvlist_add_nvlist(payload, name,
881                             va_arg(ap, nvlist_t *));
882                         break;
883                 case DATA_TYPE_NVLIST_ARRAY:
884                         nelem = va_arg(ap, int);
885                         ret = nvlist_add_nvlist_array(payload, name,
886                             va_arg(ap, nvlist_t **), nelem);
887                         break;
888                 default:
889                         ret = EINVAL;
890                 }
891
892                 name = va_arg(ap, char *);
893         }
894         return (ret);
895 }
896
897 void
898 fm_payload_set(nvlist_t *payload, ...)
899 {
900         int ret;
901         const char *name;
902         va_list ap;
903
904         va_start(ap, payload);
905         name = va_arg(ap, char *);
906         ret = i_fm_payload_set(payload, name, ap);
907         va_end(ap);
908
909         if (ret)
910                 atomic_add_64(
911                     &erpt_kstat_data.payload_set_failed.value.ui64, 1);
912 }
913
914 /*
915  * Set-up and validate the members of an ereport event according to:
916  *
917  *      Member name             Type            Value
918  *      ====================================================
919  *      class                   string          ereport
920  *      version                 uint8_t         0
921  *      ena                     uint64_t        <ena>
922  *      detector                nvlist_t        <detector>
923  *      ereport-payload         nvlist_t        <var args>
924  *
925  * We don't actually add a 'version' member to the payload.  Really,
926  * the version quoted to us by our caller is that of the category 1
927  * "ereport" event class (and we require FM_EREPORT_VERS0) but
928  * the payload version of the actual leaf class event under construction
929  * may be something else.  Callers should supply a version in the varargs,
930  * or (better) we could take two version arguments - one for the
931  * ereport category 1 classification (expect FM_EREPORT_VERS0) and one
932  * for the leaf class.
933  */
934 void
935 fm_ereport_set(nvlist_t *ereport, int version, const char *erpt_class,
936     uint64_t ena, const nvlist_t *detector, ...)
937 {
938         char ereport_class[FM_MAX_CLASS];
939         const char *name;
940         va_list ap;
941         int ret;
942
943         if (version != FM_EREPORT_VERS0) {
944                 atomic_add_64(&erpt_kstat_data.erpt_set_failed.value.ui64, 1);
945                 return;
946         }
947
948         (void) snprintf(ereport_class, FM_MAX_CLASS, "%s.%s",
949             FM_EREPORT_CLASS, erpt_class);
950         if (nvlist_add_string(ereport, FM_CLASS, ereport_class) != 0) {
951                 atomic_add_64(&erpt_kstat_data.erpt_set_failed.value.ui64, 1);
952                 return;
953         }
954
955         if (nvlist_add_uint64(ereport, FM_EREPORT_ENA, ena)) {
956                 atomic_add_64(&erpt_kstat_data.erpt_set_failed.value.ui64, 1);
957         }
958
959         if (nvlist_add_nvlist(ereport, FM_EREPORT_DETECTOR,
960             (nvlist_t *)detector) != 0) {
961                 atomic_add_64(&erpt_kstat_data.erpt_set_failed.value.ui64, 1);
962         }
963
964         va_start(ap, detector);
965         name = va_arg(ap, const char *);
966         ret = i_fm_payload_set(ereport, name, ap);
967         va_end(ap);
968
969         if (ret)
970                 atomic_add_64(&erpt_kstat_data.erpt_set_failed.value.ui64, 1);
971 }
972
973 /*
974  * Set-up and validate the members of an hc fmri according to;
975  *
976  *      Member name             Type            Value
977  *      ===================================================
978  *      version                 uint8_t         0
979  *      auth                    nvlist_t        <auth>
980  *      hc-name                 string          <name>
981  *      hc-id                   string          <id>
982  *
983  * Note that auth and hc-id are optional members.
984  */
985
986 #define HC_MAXPAIRS     20
987 #define HC_MAXNAMELEN   50
988
989 static int
990 fm_fmri_hc_set_common(nvlist_t *fmri, int version, const nvlist_t *auth)
991 {
992         if (version != FM_HC_SCHEME_VERSION) {
993                 atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
994                 return (0);
995         }
996
997         if (nvlist_add_uint8(fmri, FM_VERSION, version) != 0 ||
998             nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC) != 0) {
999                 atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
1000                 return (0);
1001         }
1002
1003         if (auth != NULL && nvlist_add_nvlist(fmri, FM_FMRI_AUTHORITY,
1004             (nvlist_t *)auth) != 0) {
1005                 atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
1006                 return (0);
1007         }
1008
1009         return (1);
1010 }
1011
1012 void
1013 fm_fmri_hc_set(nvlist_t *fmri, int version, const nvlist_t *auth,
1014     nvlist_t *snvl, int npairs, ...)
1015 {
1016         nv_alloc_t *nva = nvlist_lookup_nv_alloc(fmri);
1017         nvlist_t *pairs[HC_MAXPAIRS];
1018         va_list ap;
1019         int i;
1020
1021         if (!fm_fmri_hc_set_common(fmri, version, auth))
1022                 return;
1023
1024         npairs = MIN(npairs, HC_MAXPAIRS);
1025
1026         va_start(ap, npairs);
1027         for (i = 0; i < npairs; i++) {
1028                 const char *name = va_arg(ap, const char *);
1029                 uint32_t id = va_arg(ap, uint32_t);
1030                 char idstr[11];
1031
1032                 (void) snprintf(idstr, sizeof (idstr), "%u", id);
1033
1034                 pairs[i] = fm_nvlist_create(nva);
1035                 if (nvlist_add_string(pairs[i], FM_FMRI_HC_NAME, name) != 0 ||
1036                     nvlist_add_string(pairs[i], FM_FMRI_HC_ID, idstr) != 0) {
1037                         atomic_add_64(
1038                             &erpt_kstat_data.fmri_set_failed.value.ui64, 1);
1039                 }
1040         }
1041         va_end(ap);
1042
1043         if (nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST, pairs, npairs) != 0)
1044                 atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
1045
1046         for (i = 0; i < npairs; i++)
1047                 fm_nvlist_destroy(pairs[i], FM_NVA_RETAIN);
1048
1049         if (snvl != NULL) {
1050                 if (nvlist_add_nvlist(fmri, FM_FMRI_HC_SPECIFIC, snvl) != 0) {
1051                         atomic_add_64(
1052                             &erpt_kstat_data.fmri_set_failed.value.ui64, 1);
1053                 }
1054         }
1055 }
1056
1057 void
1058 fm_fmri_hc_create(nvlist_t *fmri, int version, const nvlist_t *auth,
1059     nvlist_t *snvl, nvlist_t *bboard, int npairs, ...)
1060 {
1061         nv_alloc_t *nva = nvlist_lookup_nv_alloc(fmri);
1062         nvlist_t *pairs[HC_MAXPAIRS];
1063         nvlist_t **hcl;
1064         uint_t n;
1065         int i, j;
1066         va_list ap;
1067         char *hcname, *hcid;
1068
1069         if (!fm_fmri_hc_set_common(fmri, version, auth))
1070                 return;
1071
1072         /*
1073          * copy the bboard nvpairs to the pairs array
1074          */
1075         if (nvlist_lookup_nvlist_array(bboard, FM_FMRI_HC_LIST, &hcl, &n)
1076             != 0) {
1077                 atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
1078                 return;
1079         }
1080
1081         for (i = 0; i < n; i++) {
1082                 if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME,
1083                     &hcname) != 0) {
1084                         atomic_add_64(
1085                             &erpt_kstat_data.fmri_set_failed.value.ui64, 1);
1086                         return;
1087                 }
1088                 if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &hcid) != 0) {
1089                         atomic_add_64(
1090                             &erpt_kstat_data.fmri_set_failed.value.ui64, 1);
1091                         return;
1092                 }
1093
1094                 pairs[i] = fm_nvlist_create(nva);
1095                 if (nvlist_add_string(pairs[i], FM_FMRI_HC_NAME, hcname) != 0 ||
1096                     nvlist_add_string(pairs[i], FM_FMRI_HC_ID, hcid) != 0) {
1097                         for (j = 0; j <= i; j++) {
1098                                 if (pairs[j] != NULL)
1099                                         fm_nvlist_destroy(pairs[j],
1100                                             FM_NVA_RETAIN);
1101                         }
1102                         atomic_add_64(
1103                             &erpt_kstat_data.fmri_set_failed.value.ui64, 1);
1104                         return;
1105                 }
1106         }
1107
1108         /*
1109          * create the pairs from passed in pairs
1110          */
1111         npairs = MIN(npairs, HC_MAXPAIRS);
1112
1113         va_start(ap, npairs);
1114         for (i = n; i < npairs + n; i++) {
1115                 const char *name = va_arg(ap, const char *);
1116                 uint32_t id = va_arg(ap, uint32_t);
1117                 char idstr[11];
1118                 (void) snprintf(idstr, sizeof (idstr), "%u", id);
1119                 pairs[i] = fm_nvlist_create(nva);
1120                 if (nvlist_add_string(pairs[i], FM_FMRI_HC_NAME, name) != 0 ||
1121                     nvlist_add_string(pairs[i], FM_FMRI_HC_ID, idstr) != 0) {
1122                         for (j = 0; j <= i; j++) {
1123                                 if (pairs[j] != NULL)
1124                                         fm_nvlist_destroy(pairs[j],
1125                                             FM_NVA_RETAIN);
1126                         }
1127                         atomic_add_64(
1128                             &erpt_kstat_data.fmri_set_failed.value.ui64, 1);
1129                         return;
1130                 }
1131         }
1132         va_end(ap);
1133
1134         /*
1135          * Create the fmri hc list
1136          */
1137         if (nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST, pairs,
1138             npairs + n) != 0) {
1139                 atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
1140                 return;
1141         }
1142
1143         for (i = 0; i < npairs + n; i++) {
1144                         fm_nvlist_destroy(pairs[i], FM_NVA_RETAIN);
1145         }
1146
1147         if (snvl != NULL) {
1148                 if (nvlist_add_nvlist(fmri, FM_FMRI_HC_SPECIFIC, snvl) != 0) {
1149                         atomic_add_64(
1150                             &erpt_kstat_data.fmri_set_failed.value.ui64, 1);
1151                         return;
1152                 }
1153         }
1154 }
1155
1156 /*
1157  * Set-up and validate the members of an dev fmri according to:
1158  *
1159  *      Member name             Type            Value
1160  *      ====================================================
1161  *      version                 uint8_t         0
1162  *      auth                    nvlist_t        <auth>
1163  *      devpath                 string          <devpath>
1164  *      [devid]                 string          <devid>
1165  *      [target-port-l0id]      string          <target-port-lun0-id>
1166  *
1167  * Note that auth and devid are optional members.
1168  */
1169 void
1170 fm_fmri_dev_set(nvlist_t *fmri_dev, int version, const nvlist_t *auth,
1171     const char *devpath, const char *devid, const char *tpl0)
1172 {
1173         int err = 0;
1174
1175         if (version != DEV_SCHEME_VERSION0) {
1176                 atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
1177                 return;
1178         }
1179
1180         err |= nvlist_add_uint8(fmri_dev, FM_VERSION, version);
1181         err |= nvlist_add_string(fmri_dev, FM_FMRI_SCHEME, FM_FMRI_SCHEME_DEV);
1182
1183         if (auth != NULL) {
1184                 err |= nvlist_add_nvlist(fmri_dev, FM_FMRI_AUTHORITY,
1185                     (nvlist_t *)auth);
1186         }
1187
1188         err |= nvlist_add_string(fmri_dev, FM_FMRI_DEV_PATH, devpath);
1189
1190         if (devid != NULL)
1191                 err |= nvlist_add_string(fmri_dev, FM_FMRI_DEV_ID, devid);
1192
1193         if (tpl0 != NULL)
1194                 err |= nvlist_add_string(fmri_dev, FM_FMRI_DEV_TGTPTLUN0, tpl0);
1195
1196         if (err)
1197                 atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
1198
1199 }
1200
1201 /*
1202  * Set-up and validate the members of an cpu fmri according to:
1203  *
1204  *      Member name             Type            Value
1205  *      ====================================================
1206  *      version                 uint8_t         0
1207  *      auth                    nvlist_t        <auth>
1208  *      cpuid                   uint32_t        <cpu_id>
1209  *      cpumask                 uint8_t         <cpu_mask>
1210  *      serial                  uint64_t        <serial_id>
1211  *
1212  * Note that auth, cpumask, serial are optional members.
1213  *
1214  */
1215 void
1216 fm_fmri_cpu_set(nvlist_t *fmri_cpu, int version, const nvlist_t *auth,
1217     uint32_t cpu_id, uint8_t *cpu_maskp, const char *serial_idp)
1218 {
1219         uint64_t *failedp = &erpt_kstat_data.fmri_set_failed.value.ui64;
1220
1221         if (version < CPU_SCHEME_VERSION1) {
1222                 atomic_add_64(failedp, 1);
1223                 return;
1224         }
1225
1226         if (nvlist_add_uint8(fmri_cpu, FM_VERSION, version) != 0) {
1227                 atomic_add_64(failedp, 1);
1228                 return;
1229         }
1230
1231         if (nvlist_add_string(fmri_cpu, FM_FMRI_SCHEME,
1232             FM_FMRI_SCHEME_CPU) != 0) {
1233                 atomic_add_64(failedp, 1);
1234                 return;
1235         }
1236
1237         if (auth != NULL && nvlist_add_nvlist(fmri_cpu, FM_FMRI_AUTHORITY,
1238             (nvlist_t *)auth) != 0)
1239                 atomic_add_64(failedp, 1);
1240
1241         if (nvlist_add_uint32(fmri_cpu, FM_FMRI_CPU_ID, cpu_id) != 0)
1242                 atomic_add_64(failedp, 1);
1243
1244         if (cpu_maskp != NULL && nvlist_add_uint8(fmri_cpu, FM_FMRI_CPU_MASK,
1245             *cpu_maskp) != 0)
1246                 atomic_add_64(failedp, 1);
1247
1248         if (serial_idp == NULL || nvlist_add_string(fmri_cpu,
1249             FM_FMRI_CPU_SERIAL_ID, (char *)serial_idp) != 0)
1250                         atomic_add_64(failedp, 1);
1251 }
1252
1253 /*
1254  * Set-up and validate the members of a mem according to:
1255  *
1256  *      Member name             Type            Value
1257  *      ====================================================
1258  *      version                 uint8_t         0
1259  *      auth                    nvlist_t        <auth>          [optional]
1260  *      unum                    string          <unum>
1261  *      serial                  string          <serial>        [optional*]
1262  *      offset                  uint64_t        <offset>        [optional]
1263  *
1264  *      * serial is required if offset is present
1265  */
1266 void
1267 fm_fmri_mem_set(nvlist_t *fmri, int version, const nvlist_t *auth,
1268     const char *unum, const char *serial, uint64_t offset)
1269 {
1270         if (version != MEM_SCHEME_VERSION0) {
1271                 atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
1272                 return;
1273         }
1274
1275         if (!serial && (offset != (uint64_t)-1)) {
1276                 atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
1277                 return;
1278         }
1279
1280         if (nvlist_add_uint8(fmri, FM_VERSION, version) != 0) {
1281                 atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
1282                 return;
1283         }
1284
1285         if (nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_MEM) != 0) {
1286                 atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
1287                 return;
1288         }
1289
1290         if (auth != NULL) {
1291                 if (nvlist_add_nvlist(fmri, FM_FMRI_AUTHORITY,
1292                     (nvlist_t *)auth) != 0) {
1293                         atomic_add_64(
1294                             &erpt_kstat_data.fmri_set_failed.value.ui64, 1);
1295                 }
1296         }
1297
1298         if (nvlist_add_string(fmri, FM_FMRI_MEM_UNUM, unum) != 0) {
1299                 atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
1300         }
1301
1302         if (serial != NULL) {
1303                 if (nvlist_add_string_array(fmri, FM_FMRI_MEM_SERIAL_ID,
1304                     (char **)&serial, 1) != 0) {
1305                         atomic_add_64(
1306                             &erpt_kstat_data.fmri_set_failed.value.ui64, 1);
1307                 }
1308                 if (offset != (uint64_t)-1) {
1309                         if (nvlist_add_uint64(fmri, FM_FMRI_MEM_OFFSET,
1310                             offset) != 0) {
1311                                 atomic_add_64(&erpt_kstat_data.
1312                                     fmri_set_failed.value.ui64, 1);
1313                         }
1314                 }
1315         }
1316 }
1317
1318 void
1319 fm_fmri_zfs_set(nvlist_t *fmri, int version, uint64_t pool_guid,
1320     uint64_t vdev_guid)
1321 {
1322         if (version != ZFS_SCHEME_VERSION0) {
1323                 atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
1324                 return;
1325         }
1326
1327         if (nvlist_add_uint8(fmri, FM_VERSION, version) != 0) {
1328                 atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
1329                 return;
1330         }
1331
1332         if (nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_ZFS) != 0) {
1333                 atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
1334                 return;
1335         }
1336
1337         if (nvlist_add_uint64(fmri, FM_FMRI_ZFS_POOL, pool_guid) != 0) {
1338                 atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
1339         }
1340
1341         if (vdev_guid != 0) {
1342                 if (nvlist_add_uint64(fmri, FM_FMRI_ZFS_VDEV, vdev_guid) != 0) {
1343                         atomic_add_64(
1344                             &erpt_kstat_data.fmri_set_failed.value.ui64, 1);
1345                 }
1346         }
1347 }
1348
1349 uint64_t
1350 fm_ena_increment(uint64_t ena)
1351 {
1352         uint64_t new_ena;
1353
1354         switch (ENA_FORMAT(ena)) {
1355         case FM_ENA_FMT1:
1356                 new_ena = ena + (1 << ENA_FMT1_GEN_SHFT);
1357                 break;
1358         case FM_ENA_FMT2:
1359                 new_ena = ena + (1 << ENA_FMT2_GEN_SHFT);
1360                 break;
1361         default:
1362                 new_ena = 0;
1363         }
1364
1365         return (new_ena);
1366 }
1367
1368 uint64_t
1369 fm_ena_generate_cpu(uint64_t timestamp, processorid_t cpuid, uchar_t format)
1370 {
1371         uint64_t ena = 0;
1372
1373         switch (format) {
1374         case FM_ENA_FMT1:
1375                 if (timestamp) {
1376                         ena = (uint64_t)((format & ENA_FORMAT_MASK) |
1377                             ((cpuid << ENA_FMT1_CPUID_SHFT) &
1378                             ENA_FMT1_CPUID_MASK) |
1379                             ((timestamp << ENA_FMT1_TIME_SHFT) &
1380                             ENA_FMT1_TIME_MASK));
1381                 } else {
1382                         ena = (uint64_t)((format & ENA_FORMAT_MASK) |
1383                             ((cpuid << ENA_FMT1_CPUID_SHFT) &
1384                             ENA_FMT1_CPUID_MASK) |
1385                             ((gethrtime() << ENA_FMT1_TIME_SHFT) &
1386                             ENA_FMT1_TIME_MASK));
1387                 }
1388                 break;
1389         case FM_ENA_FMT2:
1390                 ena = (uint64_t)((format & ENA_FORMAT_MASK) |
1391                     ((timestamp << ENA_FMT2_TIME_SHFT) & ENA_FMT2_TIME_MASK));
1392                 break;
1393         default:
1394                 break;
1395         }
1396
1397         return (ena);
1398 }
1399
1400 uint64_t
1401 fm_ena_generate(uint64_t timestamp, uchar_t format)
1402 {
1403         return (fm_ena_generate_cpu(timestamp, getcpuid(), format));
1404 }
1405
1406 uint64_t
1407 fm_ena_generation_get(uint64_t ena)
1408 {
1409         uint64_t gen;
1410
1411         switch (ENA_FORMAT(ena)) {
1412         case FM_ENA_FMT1:
1413                 gen = (ena & ENA_FMT1_GEN_MASK) >> ENA_FMT1_GEN_SHFT;
1414                 break;
1415         case FM_ENA_FMT2:
1416                 gen = (ena & ENA_FMT2_GEN_MASK) >> ENA_FMT2_GEN_SHFT;
1417                 break;
1418         default:
1419                 gen = 0;
1420                 break;
1421         }
1422
1423         return (gen);
1424 }
1425
1426 uchar_t
1427 fm_ena_format_get(uint64_t ena)
1428 {
1429
1430         return (ENA_FORMAT(ena));
1431 }
1432
1433 uint64_t
1434 fm_ena_id_get(uint64_t ena)
1435 {
1436         uint64_t id;
1437
1438         switch (ENA_FORMAT(ena)) {
1439         case FM_ENA_FMT1:
1440                 id = (ena & ENA_FMT1_ID_MASK) >> ENA_FMT1_ID_SHFT;
1441                 break;
1442         case FM_ENA_FMT2:
1443                 id = (ena & ENA_FMT2_ID_MASK) >> ENA_FMT2_ID_SHFT;
1444                 break;
1445         default:
1446                 id = 0;
1447         }
1448
1449         return (id);
1450 }
1451
1452 uint64_t
1453 fm_ena_time_get(uint64_t ena)
1454 {
1455         uint64_t time;
1456
1457         switch (ENA_FORMAT(ena)) {
1458         case FM_ENA_FMT1:
1459                 time = (ena & ENA_FMT1_TIME_MASK) >> ENA_FMT1_TIME_SHFT;
1460                 break;
1461         case FM_ENA_FMT2:
1462                 time = (ena & ENA_FMT2_TIME_MASK) >> ENA_FMT2_TIME_SHFT;
1463                 break;
1464         default:
1465                 time = 0;
1466         }
1467
1468         return (time);
1469 }
1470
1471 #ifdef _KERNEL
1472 void
1473 fm_init(void)
1474 {
1475         zevent_len_cur = 0;
1476         zevent_flags = 0;
1477
1478         if (zevent_len_max == 0)
1479                 zevent_len_max = ERPT_MAX_ERRS * MAX(max_ncpus, 4);
1480
1481         /* Initialize zevent allocation and generation kstats */
1482         fm_ksp = kstat_create("zfs", 0, "fm", "misc", KSTAT_TYPE_NAMED,
1483             sizeof (struct erpt_kstat) / sizeof (kstat_named_t),
1484             KSTAT_FLAG_VIRTUAL);
1485
1486         if (fm_ksp != NULL) {
1487                 fm_ksp->ks_data = &erpt_kstat_data;
1488                 kstat_install(fm_ksp);
1489         } else {
1490                 cmn_err(CE_NOTE, "failed to create fm/misc kstat\n");
1491         }
1492
1493         mutex_init(&zevent_lock, NULL, MUTEX_DEFAULT, NULL);
1494         list_create(&zevent_list, sizeof(zevent_t), offsetof(zevent_t, ev_node));
1495         cv_init(&zevent_cv, NULL, CV_DEFAULT, NULL);
1496 }
1497
1498 void
1499 fm_fini(void)
1500 {
1501         int count;
1502
1503         zfs_zevent_drain_all(&count);
1504         cv_broadcast(&zevent_cv);
1505
1506         mutex_enter(&zevent_lock);
1507         zevent_flags |= ZEVENT_SHUTDOWN;
1508         while (zevent_waiters > 0) {
1509                 mutex_exit(&zevent_lock);
1510                 schedule();
1511                 mutex_enter(&zevent_lock);
1512         }
1513         mutex_exit(&zevent_lock);
1514
1515         cv_destroy(&zevent_cv);
1516         list_destroy(&zevent_list);
1517         mutex_destroy(&zevent_lock);
1518
1519         if (fm_ksp != NULL) {
1520                 kstat_delete(fm_ksp);
1521                 fm_ksp = NULL;
1522         }
1523 }
1524
1525 module_param(zevent_len_max, int, 0644);
1526 MODULE_PARM_DESC(zevent_len_max, "Maximum event queue length");
1527
1528 module_param(zevent_cols, int, 0644);
1529 MODULE_PARM_DESC(zevent_cols, "Maximum event column width");
1530
1531 module_param(zevent_console, int, 0644);
1532 MODULE_PARM_DESC(zevent_console, "Log events to the console");
1533
1534 #endif /* _KERNEL */