From patchwork Sat Mar 23 04:20:25 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dexuan Cui X-Patchwork-Id: 10866755 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3FBE1922 for ; Sat, 23 Mar 2019 04:20:39 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 09C2A2A94F for ; Sat, 23 Mar 2019 04:20:39 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id F0D212A95D; Sat, 23 Mar 2019 04:20:38 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.7 required=2.0 tests=BAYES_00,DKIM_ADSP_CUSTOM_MED, DKIM_INVALID,DKIM_SIGNED,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from ml01.01.org (ml01.01.org [198.145.21.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 662F12A94F for ; Sat, 23 Mar 2019 04:20:38 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 4EFB0211E9FA5; Fri, 22 Mar 2019 21:20:38 -0700 (PDT) X-Original-To: linux-nvdimm@lists.01.org Delivered-To: linux-nvdimm@lists.01.org Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=2607:f8b0:4864:20::741; helo=mail-qk1-x741.google.com; envelope-from=dexuan.cui@gmail.com; receiver=linux-nvdimm@lists.01.org Received: from mail-qk1-x741.google.com (mail-qk1-x741.google.com [IPv6:2607:f8b0:4864:20::741]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id D9AE2211E95BE for ; Fri, 22 Mar 2019 21:20:36 -0700 (PDT) Received: by mail-qk1-x741.google.com with SMTP id o129so2458297qke.8 for ; Fri, 22 Mar 2019 21:20:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=ED828ESF4TV6+QScdxw1SGHw4GXhqLFcJzI5YRL4H6E=; b=hSLraxbBBM4Vb8UMYlKCzQPlFHduWtRuk/mPzUDUVishYXNRCvpLLw6U3YQhkr1+JZ OK9FIqIu7O2VLCHE2f/68R3y3vSllkuX7TqjNf+aEjfSE7WrzoneO9jRozuaS/SajfPb tZXQO0C+ct7TfP4Vw9dAsk7/uALJXNwiR3uXgT+jACTzcorYpeLY7FBcTesuXN7okYqM khV/unNri7VGt1cnXatOLCiv26vzycLKjZ/DRruuRHgm9fSxUJcLs0BhSdhP5jZbiqaw G+WjtnHXJp6SjZN4t5PmLPlsuhDMlA0rHOtO/nmFTPZgeP1e3K1pn2isrT2hKvGe+bJc bCsA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ED828ESF4TV6+QScdxw1SGHw4GXhqLFcJzI5YRL4H6E=; b=be4O+VRAulDqXFbNBeN6bpoauGqikE7xAdtgmWmV3zXHg9bKNgNyHhSsciTLTqhblg L6l7iFdQ6CAlB3LCviLQrh3OkNGpOZYopHb/V1YTgagFqGQoA0igL6bHViIAeezBm7GJ BruTPMUJ9WYbnUl5UjiAryzWzQm5XmvveQX1evu5PsIuwLb2GLBMde34DHlUjZICvkfJ kyFbUHCFP5x+N7TydWyW+e0b9aupxN3uHbdaSzgLKdrjAb3BMMMsxjFTeERjH071lJ4K KuvJRErqxSMfOlpT+kApXwPOzDIa6pRqqn2UWYLVufG8PRpDI9aCMzAccqgCU5L5vss5 LDSg== X-Gm-Message-State: APjAAAVKgTUYfxDLsDahhwwO4uobnjXHIw0X+VI56kbE7L2ftIcdDx8m CtJ3IhigAUCCH3BQFotpeJc= X-Google-Smtp-Source: APXvYqxU6WrpOJRiem5/w8VCZEu2OCuMpP1zbqiCKmz43FJ9jrtEnrXPjkYR2Cxy9MKD7800SUfOCA== X-Received: by 2002:a37:7383:: with SMTP id o125mr10933805qkc.56.1553314835867; Fri, 22 Mar 2019 21:20:35 -0700 (PDT) Received: from linuxonhyperv2.linuxonhyperv.com (ip-107-180-71-197.ip.secureserver.net. [107.180.71.197]) by smtp.gmail.com with ESMTPSA id k12sm6919699qti.38.2019.03.22.21.20.34 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 22 Mar 2019 21:20:35 -0700 (PDT) From: Dexuan Cui X-Google-Original-From: Dexuan Cui To: vishal.l.verma@intel.com, dan.j.williams@intel.com, dave.jiang@intel.com, linux-nvdimm@lists.01.org, mikelley@microsoft.com Subject: [ndctl PATCH v3 1/5] libndctl: Implement the "smart_get_health" dimm-op for Hyper-V Date: Sat, 23 Mar 2019 04:20:25 +0000 Message-Id: <20190323042028.4310-2-decui@microsoft.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20190323042028.4310-1-decui@microsoft.com> References: <20190323042028.4310-1-decui@microsoft.com> MIME-Version: 1.0 X-BeenThere: linux-nvdimm@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Linux-nvdimm developer list." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: qi.fuli@fujitsu.com Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP Show the health info of the NVDIMM by "Get Health Information (Function Index 1)" See http://www.uefi.org/RFIC_LIST ("Virtual NVDIMM 0x1901"). Now "ndctl list --dimms --health" can show a line "health_state":"ok" for Hyper-V NVDIMM, e.g. { "dev":"nmem0", "id":"04d5-01-1701-00000000", "handle":0, "phys_id":0, "health":{ "health_state":"ok" } } If the NVDIMM has an error, the string "ok" will be replaced with "fatal", "critical", or "non-critical". If ndctl fails to retrieve the health info due to some reason, a string of "unknown" will be shown. Signed-off-by: Dexuan Cui --- ndctl/lib/Makefile.am | 1 + ndctl/lib/hyperv.c | 126 ++++++++++++++++++++++++++++++++++++++++++ ndctl/lib/hyperv.h | 30 ++++++++++ ndctl/lib/libndctl.c | 2 + ndctl/lib/private.h | 3 + ndctl/ndctl.h | 1 + 6 files changed, 163 insertions(+) create mode 100644 ndctl/lib/hyperv.c create mode 100644 ndctl/lib/hyperv.h diff --git a/ndctl/lib/Makefile.am b/ndctl/lib/Makefile.am index 7797039..fb75fda 100644 --- a/ndctl/lib/Makefile.am +++ b/ndctl/lib/Makefile.am @@ -20,6 +20,7 @@ libndctl_la_SOURCES =\ intel.c \ hpe1.c \ msft.c \ + hyperv.c \ ars.c \ firmware.c \ libndctl.c diff --git a/ndctl/lib/hyperv.c b/ndctl/lib/hyperv.c new file mode 100644 index 0000000..6ed2125 --- /dev/null +++ b/ndctl/lib/hyperv.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2019, Microsoft Corporation. All rights reserved. */ + +#include +#include +#include +#include +#include +#include "private.h" +#include "hyperv.h" + +static struct ndctl_cmd *alloc_hyperv_cmd(struct ndctl_dimm *dimm, + unsigned int command) +{ + struct ndctl_bus *bus = ndctl_dimm_get_bus(dimm); + struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus); + struct nd_pkg_hyperv *hyperv; + struct ndctl_cmd *cmd; + size_t size; + + if (!ndctl_dimm_is_cmd_supported(dimm, ND_CMD_CALL)) { + dbg(ctx, "unsupported cmd\n"); + return NULL; + } + + if (test_dimm_dsm(dimm, command) == DIMM_DSM_UNSUPPORTED) { + dbg(ctx, "unsupported function\n"); + return NULL; + } + + size = sizeof(*cmd) + sizeof(struct nd_pkg_hyperv); + cmd = calloc(1, size); + if (!cmd) + return NULL; + + ndctl_cmd_ref(cmd); + + cmd->dimm = dimm; + cmd->type = ND_CMD_CALL; + cmd->size = size; + cmd->status = 1; + + hyperv = cmd->hyperv; + hyperv->gen.nd_family = NVDIMM_FAMILY_HYPERV; + hyperv->gen.nd_command = command; + hyperv->gen.nd_size_out = sizeof(hyperv->u.health_info); + + cmd->firmware_status = &hyperv->u.health_info.status; + return cmd; +} + +static struct ndctl_cmd *hyperv_dimm_cmd_new_smart(struct ndctl_dimm *dimm) +{ + return alloc_hyperv_cmd(dimm, ND_HYPERV_CMD_GET_HEALTH_INFO); +} + +static int hyperv_cmd_valid(struct ndctl_cmd *cmd, unsigned int command) +{ + if (cmd->type != ND_CMD_CALL || + cmd->size != sizeof(*cmd) + sizeof(struct nd_pkg_hyperv) || + cmd->hyperv->gen.nd_family != NVDIMM_FAMILY_HYPERV || + cmd->hyperv->gen.nd_command != command || + cmd->status != 0 || + cmd->hyperv->u.status != 0) + return cmd->status < 0 ? cmd->status : -EINVAL; + + return 0; +} + +static int hyperv_valid_health_info(struct ndctl_cmd *cmd) +{ + return hyperv_cmd_valid(cmd, ND_HYPERV_CMD_GET_HEALTH_INFO); +} + +static unsigned int hyperv_cmd_get_flags(struct ndctl_cmd *cmd) +{ + unsigned int flags = 0; + int rc; + + rc = hyperv_valid_health_info(cmd); + if (rc < 0) { + errno = -rc; + return 0; + } + flags |= ND_SMART_HEALTH_VALID; + + return flags; +} + +static unsigned int hyperv_cmd_get_health(struct ndctl_cmd *cmd) +{ + unsigned int health = 0; + __u32 num; + int rc; + + rc = hyperv_valid_health_info(cmd); + if (rc < 0) { + errno = -rc; + return UINT_MAX; + } + + num = cmd->hyperv->u.health_info.health & 0x3F; + + if (num & (BIT(0) | BIT(1))) + health |= ND_SMART_CRITICAL_HEALTH; + + if (num & BIT(2)) + health |= ND_SMART_FATAL_HEALTH; + + if (num & (BIT(3) | BIT(4) | BIT(5))) + health |= ND_SMART_NON_CRITICAL_HEALTH; + + return health; +} + +static int hyperv_cmd_xlat_firmware_status(struct ndctl_cmd *cmd) +{ + return cmd->hyperv->u.status == 0 ? 0 : -EINVAL; +} + +struct ndctl_dimm_ops * const hyperv_dimm_ops = &(struct ndctl_dimm_ops) { + .new_smart = hyperv_dimm_cmd_new_smart, + .smart_get_flags = hyperv_cmd_get_flags, + .smart_get_health = hyperv_cmd_get_health, + .xlat_firmware_status = hyperv_cmd_xlat_firmware_status, +}; diff --git a/ndctl/lib/hyperv.h b/ndctl/lib/hyperv.h new file mode 100644 index 0000000..45bbc12 --- /dev/null +++ b/ndctl/lib/hyperv.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2019, Microsoft Corporation. All rights reserved. */ + +#ifndef __NDCTL_HYPERV_H__ +#define __NDCTL_HYPERV_H__ + +/* See http://www.uefi.org/RFIC_LIST ("Virtual NVDIMM 0x1901") */ + +enum { + ND_HYPERV_CMD_QUERY_SUPPORTED_FUNCTIONS = 0, + ND_HYPERV_CMD_GET_HEALTH_INFO = 1, +}; + +/* Get Health Information (Function Index 1) */ +struct nd_hyperv_health_info { + __u32 status; + __u32 health; +} __attribute__((packed)); + +union nd_hyperv_cmd { + __u32 status; + struct nd_hyperv_health_info health_info; +} __attribute__((packed)); + +struct nd_pkg_hyperv { + struct nd_cmd_pkg gen; + union nd_hyperv_cmd u; +} __attribute__((packed)); + +#endif /* __NDCTL_HYPERV_H__ */ diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c index 98893bc..24b8ad3 100644 --- a/ndctl/lib/libndctl.c +++ b/ndctl/lib/libndctl.c @@ -1543,6 +1543,8 @@ static void *add_dimm(void *parent, int id, const char *dimm_base) dimm->ops = hpe1_dimm_ops; if (dimm->cmd_family == NVDIMM_FAMILY_MSFT) dimm->ops = msft_dimm_ops; + if (dimm->cmd_family == NVDIMM_FAMILY_HYPERV) + dimm->ops = hyperv_dimm_ops; sprintf(path, "%s/nfit/dsm_mask", dimm_base); if (sysfs_read_attr(ctx, path, buf) == 0) diff --git a/ndctl/lib/private.h b/ndctl/lib/private.h index a387b0b..a9d35c5 100644 --- a/ndctl/lib/private.h +++ b/ndctl/lib/private.h @@ -31,6 +31,7 @@ #include "intel.h" #include "hpe1.h" #include "msft.h" +#include "hyperv.h" struct nvdimm_data { struct ndctl_cmd *cmd_read; @@ -270,6 +271,7 @@ struct ndctl_cmd { struct nd_cmd_pkg pkg[0]; struct ndn_pkg_hpe1 hpe1[0]; struct ndn_pkg_msft msft[0]; + struct nd_pkg_hyperv hyperv[0]; struct nd_pkg_intel intel[0]; struct nd_cmd_get_config_size get_size[0]; struct nd_cmd_get_config_data_hdr get_data[0]; @@ -344,6 +346,7 @@ struct ndctl_dimm_ops { struct ndctl_dimm_ops * const intel_dimm_ops; struct ndctl_dimm_ops * const hpe1_dimm_ops; struct ndctl_dimm_ops * const msft_dimm_ops; +struct ndctl_dimm_ops * const hyperv_dimm_ops; static inline struct ndctl_bus *cmd_to_bus(struct ndctl_cmd *cmd) { diff --git a/ndctl/ndctl.h b/ndctl/ndctl.h index c6aaa4c..008f81c 100644 --- a/ndctl/ndctl.h +++ b/ndctl/ndctl.h @@ -262,6 +262,7 @@ struct nd_cmd_pkg { #define NVDIMM_FAMILY_HPE1 1 #define NVDIMM_FAMILY_HPE2 2 #define NVDIMM_FAMILY_MSFT 3 +#define NVDIMM_FAMILY_HYPERV 4 #define ND_IOCTL_CALL _IOWR(ND_IOCTL, ND_CMD_CALL,\ struct nd_cmd_pkg)