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 }