blob: a0fb714189572be31438bcf674de98d1a8e412a4 [file] [log] [blame]
/*
* Copyright(c) 2015-2017 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include <limits.h>
#include <util/json.h>
#include <uuid/uuid.h>
#include <json-c/json.h>
#include <ndctl/libndctl.h>
#include <ccan/array_size/array_size.h>
#ifdef HAVE_NDCTL_H
#include <linux/ndctl.h>
#else
#include <ndctl.h>
#endif
static double parse_smart_temperature(unsigned int temp)
{
bool negative = !!(temp & (1 << 15));
double t;
temp &= ~(1 << 15);
t = temp;
t /= 16;
if (negative)
t *= -1;
return t;
}
static void smart_threshold_to_json(struct ndctl_dimm *dimm,
struct json_object *jhealth)
{
unsigned int alarm_control;
struct json_object *jobj;
struct ndctl_cmd *cmd;
int rc;
cmd = ndctl_dimm_cmd_new_smart_threshold(dimm);
if (!cmd)
return;
rc = ndctl_cmd_submit(cmd);
if (rc || ndctl_cmd_get_firmware_status(cmd))
goto out;
alarm_control = ndctl_cmd_smart_threshold_get_alarm_control(cmd);
if (alarm_control & ND_SMART_TEMP_TRIP) {
unsigned int temp;
double t;
temp = ndctl_cmd_smart_threshold_get_temperature(cmd);
t = parse_smart_temperature(temp);
jobj = json_object_new_double(t);
if (jobj)
json_object_object_add(jhealth,
"temperature_threshold", jobj);
}
if (alarm_control & ND_SMART_SPARE_TRIP) {
unsigned int spares;
spares = ndctl_cmd_smart_threshold_get_spares(cmd);
jobj = json_object_new_int(spares);
if (jobj)
json_object_object_add(jhealth,
"spares_threshold", jobj);
}
out:
ndctl_cmd_unref(cmd);
}
struct json_object *util_dimm_health_to_json(struct ndctl_dimm *dimm)
{
struct json_object *jhealth = json_object_new_object();
struct json_object *jobj;
struct ndctl_cmd *cmd;
unsigned int flags;
int rc;
if (!jhealth)
return NULL;
cmd = ndctl_dimm_cmd_new_smart(dimm);
if (!cmd)
goto err;
rc = ndctl_cmd_submit(cmd);
if (rc || ndctl_cmd_get_firmware_status(cmd)) {
if (!ndctl_dimm_is_cmd_supported(dimm, ND_CMD_SMART))
goto err;
jobj = json_object_new_string("unknown");
if (jobj)
json_object_object_add(jhealth, "health_state", jobj);
goto out;
}
flags = ndctl_cmd_smart_get_flags(cmd);
if (flags & ND_SMART_HEALTH_VALID) {
unsigned int health = ndctl_cmd_smart_get_health(cmd);
if (health & ND_SMART_FATAL_HEALTH)
jobj = json_object_new_string("fatal");
else if (health & ND_SMART_CRITICAL_HEALTH)
jobj = json_object_new_string("critical");
else if (health & ND_SMART_NON_CRITICAL_HEALTH)
jobj = json_object_new_string("non-critical");
else
jobj = json_object_new_string("ok");
if (jobj)
json_object_object_add(jhealth, "health_state", jobj);
}
if (flags & ND_SMART_TEMP_VALID) {
unsigned int temp = ndctl_cmd_smart_get_temperature(cmd);
double t = parse_smart_temperature(temp);
jobj = json_object_new_double(t);
if (jobj)
json_object_object_add(jhealth, "temperature_celsius", jobj);
}
if (flags & ND_SMART_SPARES_VALID) {
unsigned int spares = ndctl_cmd_smart_get_spares(cmd);
jobj = json_object_new_int(spares);
if (jobj)
json_object_object_add(jhealth, "spares_percentage", jobj);
}
if (flags & ND_SMART_ALARM_VALID) {
unsigned int alarm_flags = ndctl_cmd_smart_get_alarm_flags(cmd);
bool temp_flag = !!(alarm_flags & ND_SMART_TEMP_TRIP);
bool spares_flag = !!(alarm_flags & ND_SMART_SPARE_TRIP);
jobj = json_object_new_boolean(temp_flag);
if (jobj)
json_object_object_add(jhealth, "alarm_temperature", jobj);
jobj = json_object_new_boolean(spares_flag);
if (jobj)
json_object_object_add(jhealth, "alarm_spares", jobj);
}
smart_threshold_to_json(dimm, jhealth);
if (flags & ND_SMART_USED_VALID) {
unsigned int life_used = ndctl_cmd_smart_get_life_used(cmd);
jobj = json_object_new_int(life_used);
if (jobj)
json_object_object_add(jhealth, "life_used_percentage", jobj);
}
if (flags & ND_SMART_SHUTDOWN_VALID) {
unsigned int shutdown = ndctl_cmd_smart_get_shutdown_state(cmd);
jobj = json_object_new_string(shutdown ? "dirty" : "clean");
if (jobj)
json_object_object_add(jhealth, "shutdown_state", jobj);
}
ndctl_cmd_unref(cmd);
return jhealth;
err:
json_object_put(jhealth);
jhealth = NULL;
out:
if (cmd)
ndctl_cmd_unref(cmd);
return jhealth;
}