blob: 41bbc6f93b809d582a5b00325690680e60aff25f [file] [log] [blame]
/*
* Copyright (c) 2016, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
* more details.
*/
#include <stdlib.h>
#include <limits.h>
#include <util/log.h>
#include <ndctl/libndctl.h>
#include "private.h"
/*
* Define the wrappers around the ndctl_smart_ops:
*/
NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_cmd_new_smart(
struct ndctl_dimm *dimm)
{
struct ndctl_smart_ops *ops = ndctl_dimm_get_smart_ops(dimm);
if (ops && ops->new_smart)
return ops->new_smart(dimm);
else
return NULL;
}
NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_cmd_new_smart_threshold(
struct ndctl_dimm *dimm)
{
struct ndctl_smart_ops *ops = ndctl_dimm_get_smart_ops(dimm);
if (ops && ops->new_smart_threshold)
return ops->new_smart_threshold(dimm);
else
return NULL;
}
#define smart_cmd_op(name, op, rettype, defretvalue) \
NDCTL_EXPORT rettype name(struct ndctl_cmd *cmd) \
{ \
if (cmd->dimm) { \
struct ndctl_smart_ops *ops = ndctl_dimm_get_smart_ops(cmd->dimm); \
if (ops && ops->op) \
return ops->op(cmd); \
} \
return defretvalue; \
}
smart_cmd_op(ndctl_cmd_smart_get_flags, smart_get_flags, unsigned int, 0)
smart_cmd_op(ndctl_cmd_smart_get_health, smart_get_health, unsigned int, 0)
smart_cmd_op(ndctl_cmd_smart_get_temperature, smart_get_temperature, unsigned int, 0)
smart_cmd_op(ndctl_cmd_smart_get_spares, smart_get_spares, unsigned int, 0)
smart_cmd_op(ndctl_cmd_smart_get_alarm_flags, smart_get_alarm_flags, unsigned int, 0)
smart_cmd_op(ndctl_cmd_smart_get_life_used, smart_get_life_used, unsigned int, 0)
smart_cmd_op(ndctl_cmd_smart_get_shutdown_state, smart_get_shutdown_state, unsigned int, 0)
smart_cmd_op(ndctl_cmd_smart_get_vendor_size, smart_get_vendor_size, unsigned int, 0)
smart_cmd_op(ndctl_cmd_smart_get_vendor_data, smart_get_vendor_data, unsigned char *, NULL)
smart_cmd_op(ndctl_cmd_smart_threshold_get_alarm_control, smart_threshold_get_alarm_control, unsigned int, 0)
smart_cmd_op(ndctl_cmd_smart_threshold_get_temperature, smart_threshold_get_temperature, unsigned int, 0)
smart_cmd_op(ndctl_cmd_smart_threshold_get_spares, smart_threshold_get_spares, unsigned int, 0)
/*
* The following intel_dimm_*() and intel_smart_*() functions implement
* the ndctl_smart_ops for the Intel DSM family (NVDIMM_FAMILY_INTEL):
*/
static struct ndctl_cmd *intel_dimm_cmd_new_smart(struct ndctl_dimm *dimm)
{
struct ndctl_bus *bus = ndctl_dimm_get_bus(dimm);
struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus);
struct ndctl_cmd *cmd;
size_t size;
BUILD_ASSERT(sizeof(struct nd_smart_payload) == 128);
if (!ndctl_dimm_is_cmd_supported(dimm, ND_CMD_SMART)) {
dbg(ctx, "unsupported cmd\n");
return NULL;
}
size = sizeof(*cmd) + sizeof(struct nd_cmd_smart);
cmd = calloc(1, size);
if (!cmd)
return NULL;
cmd->dimm = dimm;
ndctl_cmd_ref(cmd);
cmd->type = ND_CMD_SMART;
cmd->size = size;
cmd->status = 1;
cmd->firmware_status = &cmd->smart->status;
return cmd;
}
static int intel_smart_valid(struct ndctl_cmd *cmd)
{
if (cmd->type != ND_CMD_SMART || cmd->status != 0)
return cmd->status < 0 ? cmd->status : -EINVAL;
return 0;
}
#define intel_smart_get_field(cmd, field) \
static unsigned int intel_cmd_smart_get_##field(struct ndctl_cmd *cmd) \
{ \
struct nd_smart_payload *smart_data; \
if (intel_smart_valid(cmd) < 0) \
return UINT_MAX; \
smart_data = (struct nd_smart_payload *) cmd->smart->data; \
return smart_data->field; \
}
intel_smart_get_field(cmd, flags)
intel_smart_get_field(cmd, health)
intel_smart_get_field(cmd, temperature)
intel_smart_get_field(cmd, spares)
intel_smart_get_field(cmd, alarm_flags)
intel_smart_get_field(cmd, life_used)
intel_smart_get_field(cmd, shutdown_state)
intel_smart_get_field(cmd, vendor_size)
static unsigned char *intel_cmd_smart_get_vendor_data(struct ndctl_cmd *cmd)
{
struct nd_smart_payload *smart_data;
if (intel_smart_valid(cmd) < 0)
return NULL;
smart_data = (struct nd_smart_payload *) cmd->smart->data;
return (unsigned char *) smart_data->vendor_data;
}
static int intel_smart_threshold_valid(struct ndctl_cmd *cmd)
{
if (cmd->type != ND_CMD_SMART_THRESHOLD || cmd->status != 0)
return cmd->status < 0 ? cmd->status : -EINVAL;
return 0;
}
#define intel_smart_threshold_get_field(cmd, field) \
static unsigned int intel_cmd_smart_threshold_get_##field( \
struct ndctl_cmd *cmd) \
{ \
struct nd_smart_threshold_payload *smart_t_data; \
if (intel_smart_threshold_valid(cmd) < 0) \
return UINT_MAX; \
smart_t_data = (struct nd_smart_threshold_payload *) \
cmd->smart_t->data; \
return smart_t_data->field; \
}
intel_smart_threshold_get_field(cmd, alarm_control)
intel_smart_threshold_get_field(cmd, temperature)
intel_smart_threshold_get_field(cmd, spares)
static struct ndctl_cmd *intel_dimm_cmd_new_smart_threshold(
struct ndctl_dimm *dimm)
{
struct ndctl_bus *bus = ndctl_dimm_get_bus(dimm);
struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus);
struct ndctl_cmd *cmd;
size_t size;
BUILD_ASSERT(sizeof(struct nd_smart_threshold_payload) == 8);
if (!ndctl_dimm_is_cmd_supported(dimm, ND_CMD_SMART_THRESHOLD)) {
dbg(ctx, "unsupported cmd\n");
return NULL;
}
size = sizeof(*cmd) + sizeof(struct nd_cmd_smart_threshold);
cmd = calloc(1, size);
if (!cmd)
return NULL;
cmd->dimm = dimm;
ndctl_cmd_ref(cmd);
cmd->type = ND_CMD_SMART_THRESHOLD;
cmd->size = size;
cmd->status = 1;
cmd->firmware_status = &cmd->smart_t->status;
return cmd;
}
struct ndctl_smart_ops * const intel_smart_ops = &(struct ndctl_smart_ops) {
.new_smart = intel_dimm_cmd_new_smart,
.smart_get_flags = intel_cmd_smart_get_flags,
.smart_get_health = intel_cmd_smart_get_health,
.smart_get_temperature = intel_cmd_smart_get_temperature,
.smart_get_spares = intel_cmd_smart_get_spares,
.smart_get_alarm_flags = intel_cmd_smart_get_alarm_flags,
.smart_get_life_used = intel_cmd_smart_get_life_used,
.smart_get_shutdown_state = intel_cmd_smart_get_shutdown_state,
.smart_get_vendor_size = intel_cmd_smart_get_vendor_size,
.smart_get_vendor_data = intel_cmd_smart_get_vendor_data,
.new_smart_threshold = intel_dimm_cmd_new_smart_threshold,
.smart_threshold_get_alarm_control = intel_cmd_smart_threshold_get_alarm_control,
.smart_threshold_get_temperature = intel_cmd_smart_threshold_get_temperature,
.smart_threshold_get_spares = intel_cmd_smart_threshold_get_spares,
};