1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
14 */
15
16 #include <fm/fmd_api.h>
17 #include <sys/note.h>
18 #include <fm/libtopo.h>
19 #include <sys/fm/protocol.h>
20 #include <strings.h>
21
22 typedef struct slow_io_stat {
23 fmd_stat_t bad_fmri;
24 fmd_stat_t bad_scheme;
25 } slow_io_stat_t;
26
27 slow_io_stat_t slow_io_stats = {
28 { "bad_FMRI", FMD_TYPE_UINT64,
29 "event FMRI is missing or invalid" },
30 { "bad_scheme", FMD_TYPE_UINT64,
31 "event does not contain a valid detector"},
32 };
33
34 static const fmd_prop_t fmd_props [] = {
35 { "io_N", FMD_TYPE_INT32, "10" },
36 { "io_T", FMD_TYPE_TIME, "10min"},
37 { NULL, 0, NULL }
38 };
39
40 void
41 slow_io_close(fmd_hdl_t *hdl, fmd_case_t *c)
42 {
43 char *devid = fmd_case_getspecific(hdl, c);
44 if (devid != NULL) {
45 fmd_hdl_debug(hdl, "Destroying serd: %s", devid);
46 fmd_serd_destroy(hdl, devid);
47 }
48 }
49
50 void
51 slow_io_recv(fmd_hdl_t *hdl, fmd_event_t *event, nvlist_t *nvl,
52 const char *class)
53 {
54 nvlist_t *detector = NULL;
55 char *devid = NULL;
56 nvlist_t *fault;
57 fmd_hdl_topo_node_info_t *node;
58 _NOTE(ARGUNUSED(class));
59
60 if (nvlist_lookup_nvlist(nvl, "detector", &detector) != 0) {
61 slow_io_stats.bad_scheme.fmds_value.ui64++;
62 return;
63 }
64
65 if (nvlist_lookup_string(detector, "devid", &devid) != 0) {
66 slow_io_stats.bad_fmri.fmds_value.ui64++;
67 return;
68 }
69
70 if (fmd_serd_exists(hdl, devid) == 0) {
71 fmd_serd_create(hdl, devid, fmd_prop_get_int32(hdl, "io_N"),
72 fmd_prop_get_int64(hdl, "io_T"));
73 (void) fmd_serd_record(hdl, devid, event);
74 return;
75 }
76
77 if (fmd_serd_record(hdl, devid, event) == FMD_B_TRUE) {
78 fmd_case_t *c = fmd_case_open(hdl, NULL);
79 fmd_case_add_serd(hdl, c, devid);
80 node = fmd_hdl_topo_node_get_by_devid(hdl, devid);
81
82 /*
83 * If for some reason libtopo does not enumureate the device
84 * we still want to create a fault, we will see a "bad"
85 * FMA message however that lacks the FRU information.
86 */
87
88 if (node == NULL) {
89 fault = fmd_nvl_create_fault(hdl,
90 "fault.io.disk.slow-io", 100,
91 detector, NULL, NULL);
92 } else {
93 fault = fmd_nvl_create_fault(hdl,
94 "fault.io.disk.slow-io", 100,
95 detector, node->fru, node->resource);
96 nvlist_free(node->fru);
97 nvlist_free(node->resource);
98 fmd_hdl_free(hdl, node,
99 sizeof (fmd_hdl_topo_node_info_t));
100 }
101
102 fmd_case_add_suspect(hdl, c, fault);
103 fmd_case_setspecific(hdl, c, devid);
104 fmd_case_solve(hdl, c);
105 }
106 }
107
108 static const fmd_hdl_ops_t fmd_ops = {
109 slow_io_recv,
110 NULL,
111 slow_io_close,
112 NULL,
113 NULL,
114 };
115
116 static const fmd_hdl_info_t fmd_info = {
117 "slow-io-de", "0.2", &fmd_ops, fmd_props
118 };
119
120 void
121 _fmd_init(fmd_hdl_t *hdl)
122 {
123 if (fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info) != 0) {
124 fmd_hdl_debug(hdl, "Internal error\n");
125 return;
126 }
127
128 (void) fmd_stat_create(hdl, FMD_STAT_NOALLOC, sizeof (slow_io_stats) /
129 sizeof (fmd_stat_t), (fmd_stat_t *)&slow_io_stats);
130 }
131
132 void
133 _fmd_fini(fmd_hdl_t *hdl)
134 {
135 _NOTE(ARGUNUSED(hdl));
136 }