6859503de8
- Add NetApp vendor plugin (bsc#1080672) + 0001-nvme-cli-add-NetApp-plugin.patch + 0002-nvme-cli-add-netapp-smdevices-man-page.patch (forwarded request 576273 from morbidrsa) OBS-URL: https://build.opensuse.org/request/show/576274 OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/nvme-cli?expand=0&rev=23
346 lines
9.6 KiB
Diff
346 lines
9.6 KiB
Diff
From: "Schremmer, Steven" <Steve.Schremmer@netapp.com>
|
|
Date: Mon, 12 Feb 2018 19:27:32 +0000
|
|
Subject: [PATCH nvme-cli 1/2] nvme-cli: add NetApp plugin
|
|
Git-commit: 396677894203bedbe9d037b20d9197361899fa03
|
|
References: bsc#1080672
|
|
|
|
Add smdevices command for NetApp E-Series devices.
|
|
|
|
Signed-off-by: Steve Schremmer <steve.schremmer@netapp.com>
|
|
---
|
|
Makefile | 3
|
|
netapp-nvme.c | 293 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
netapp-nvme.h | 17 +++
|
|
3 files changed, 312 insertions(+), 1 deletion(-)
|
|
create mode 100644 netapp-nvme.c
|
|
create mode 100644 netapp-nvme.h
|
|
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -33,7 +33,8 @@ NVME_DPKG_VERSION=1~`lsb_release -sc`
|
|
|
|
OBJS := argconfig.o suffix.o parser.o nvme-print.o nvme-ioctl.o \
|
|
nvme-lightnvm.o fabrics.o json.o plugin.o intel-nvme.o \
|
|
- lnvm-nvme.o memblaze-nvme.o wdc-nvme.o nvme-models.o huawei-nvme.o
|
|
+ lnvm-nvme.o memblaze-nvme.o wdc-nvme.o nvme-models.o huawei-nvme.o \
|
|
+ netapp-nvme.o
|
|
|
|
nvme: nvme.c nvme.h $(OBJS) NVME-VERSION-FILE
|
|
$(CC) $(CPPFLAGS) $(CFLAGS) nvme.c -o $(NVME) $(OBJS) $(LDFLAGS)
|
|
--- /dev/null
|
|
+++ b/netapp-nvme.c
|
|
@@ -0,0 +1,293 @@
|
|
+/*
|
|
+* Copyright (c) 2018 NetApp, Inc.
|
|
+*
|
|
+* This program is free software; you can redistribute it and/or
|
|
+* modify it under the terms of the GNU General Public License
|
|
+* as published by the Free Software Foundation; either version 2
|
|
+* of the License, or (at your option) any later version.
|
|
+*
|
|
+* 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 <stdio.h>
|
|
+#include <dirent.h>
|
|
+#include <sys/stat.h>
|
|
+#include <stdlib.h>
|
|
+#include <fcntl.h>
|
|
+#include <unistd.h>
|
|
+#include <errno.h>
|
|
+#include <string.h>
|
|
+
|
|
+#include "nvme.h"
|
|
+#include "nvme-ioctl.h"
|
|
+#include "json.h"
|
|
+
|
|
+#include "suffix.h"
|
|
+
|
|
+#define CREATE_CMD
|
|
+#include "netapp-nvme.h"
|
|
+
|
|
+enum {
|
|
+ NNORMAL,
|
|
+ NJSON,
|
|
+ NCOLUMN,
|
|
+};
|
|
+
|
|
+static const char *dev_path = "/dev/";
|
|
+
|
|
+struct smdevice_info {
|
|
+ int nsid;
|
|
+ struct nvme_id_ctrl ctrl;
|
|
+ struct nvme_id_ns ns;
|
|
+ char dev[265];
|
|
+};
|
|
+
|
|
+#define ARRAY_LABEL_LEN 60
|
|
+#define VOLUME_LABEL_LEN 60
|
|
+
|
|
+/*
|
|
+ * Format of the string isn't tightly controlled yet. For now, squash UCS-2 into
|
|
+ * ASCII. dst buffer must be at least count + 1 bytes long
|
|
+ */
|
|
+static void netapp_convert_string(char *dst, char *src, unsigned int count)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ if (!dst || !src || !count)
|
|
+ return;
|
|
+
|
|
+ memset(dst, 0, count + 1);
|
|
+ for (i = 0; i < count; i++)
|
|
+ dst[i] = src[i * 2 + 1];
|
|
+}
|
|
+
|
|
+static void netapp_nguid_to_str(char *str, __u8 *nguid)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ memset(str, 0, 33);
|
|
+ for (i = 0; i < 16; i++)
|
|
+ str += sprintf(str, "%02x", nguid[i]);
|
|
+}
|
|
+
|
|
+static void netapp_smdevice_json(struct json_array *devices, char *devname,
|
|
+ char *arrayname, char *volname, int nsid, char *nguid,
|
|
+ char *ctrl, char *astate, char *size, long long lba,
|
|
+ long long nsze)
|
|
+{
|
|
+ struct json_object *device_attrs;
|
|
+
|
|
+ device_attrs = json_create_object();
|
|
+ json_object_add_value_string(device_attrs, "Device", devname);
|
|
+ json_object_add_value_string(device_attrs, "Array_Name", arrayname);
|
|
+ json_object_add_value_string(device_attrs, "Volume_Name", volname);
|
|
+ json_object_add_value_int(device_attrs, "NSID", nsid);
|
|
+ json_object_add_value_string(device_attrs, "Volume_ID", nguid);
|
|
+ json_object_add_value_string(device_attrs, "Controller", ctrl);
|
|
+ json_object_add_value_string(device_attrs, "Access_State", astate);
|
|
+ json_object_add_value_string(device_attrs, "Size", size);
|
|
+ json_object_add_value_int(device_attrs, "LBA_Data_Size", lba);
|
|
+ json_object_add_value_int(device_attrs, "Namespace_Size", nsze);
|
|
+
|
|
+ json_array_add_value_object(devices, device_attrs);
|
|
+}
|
|
+
|
|
+static void netapp_smdevices_print(struct smdevice_info *devices, int count, int format)
|
|
+{
|
|
+ struct json_object *root = NULL;
|
|
+ struct json_array *json_devices = NULL;
|
|
+ int i, slta;
|
|
+ char array_label[ARRAY_LABEL_LEN / 2 + 1];
|
|
+ char volume_label[VOLUME_LABEL_LEN / 2 + 1];
|
|
+ char nguid_str[33];
|
|
+ char basestr[] = "%s, Array Name %s, Volume Name %s, NSID %d, "
|
|
+ "Volume ID %s, Controller %c, Access State %s, %s\n";
|
|
+ char columnstr[] = "%-16s %-30s %-30s %4d %32s %c %-12s %9s\n";
|
|
+ char *formatstr = basestr; // default to "normal" output format
|
|
+
|
|
+ if (format == NCOLUMN) {
|
|
+ /* for column output, change output string and print column headers */
|
|
+ formatstr = columnstr;
|
|
+ printf("%-16s %-30s %-30s %-4s %-32s %-4s %-12s %-9s\n",
|
|
+ "Device", "Array Name", "Volume Name", "NSID",
|
|
+ "Volume ID", "Ctrl", "Access State", " Size");
|
|
+ printf("%-16s %-30s %-30s %-4s %-32s %-4s %-12s %-9s\n",
|
|
+ "----------------", "------------------------------",
|
|
+ "------------------------------", "----",
|
|
+ "--------------------------------", "----",
|
|
+ "------------", "---------");
|
|
+ }
|
|
+ else if (format == NJSON) {
|
|
+ /* prepare for json output */
|
|
+ root = json_create_object();
|
|
+ json_devices = json_create_array();
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < count; i++) {
|
|
+ long long int lba = 1 << devices[i].ns.lbaf[(devices[i].ns.flbas & 0x0F)].ds;
|
|
+ double nsze = le64_to_cpu(devices[i].ns.nsze) * lba;
|
|
+ const char *s_suffix = suffix_si_get(&nsze);
|
|
+ char size[128];
|
|
+
|
|
+ sprintf(size, "%.2f%sB", nsze, s_suffix);
|
|
+ netapp_convert_string(array_label, (char *)&devices[i].ctrl.vs[20],
|
|
+ ARRAY_LABEL_LEN / 2);
|
|
+ slta = devices[i].ctrl.vs[0] & 0x1;
|
|
+ netapp_convert_string(volume_label, (char *)devices[i].ns.vs,
|
|
+ VOLUME_LABEL_LEN / 2);
|
|
+ netapp_nguid_to_str(nguid_str, devices[i].ns.nguid);
|
|
+ if (format == NJSON)
|
|
+ netapp_smdevice_json(json_devices, devices[i].dev,
|
|
+ array_label, volume_label, devices[i].nsid,
|
|
+ nguid_str, slta ? "A" : "B", "unknown", size,
|
|
+ lba, le64_to_cpu(devices[i].ns.nsze));
|
|
+ else
|
|
+ printf(formatstr, devices[i].dev, array_label,
|
|
+ volume_label, devices[i].nsid, nguid_str,
|
|
+ slta ? 'A' : 'B', "unknown", size);
|
|
+ }
|
|
+
|
|
+ if (format == NJSON) {
|
|
+ /* complete the json output */
|
|
+ json_object_add_value_array(root, "SMdevices", json_devices);
|
|
+ json_print_object(root, NULL);
|
|
+ }
|
|
+}
|
|
+
|
|
+static int netapp_smdevices_get_info(int fd, struct smdevice_info *item,
|
|
+ const char *dev)
|
|
+{
|
|
+ int err;
|
|
+
|
|
+ err = nvme_identify_ctrl(fd, &item->ctrl);
|
|
+ if (err) {
|
|
+ fprintf(stderr, "Identify Controler failed to %s (%s)\n", dev,
|
|
+ strerror(err));
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (strncmp("NetApp E-Series", item->ctrl.mn, 15) != 0)
|
|
+ return 0; // not the right model of controller
|
|
+
|
|
+ item->nsid = nvme_get_nsid(fd);
|
|
+ err = nvme_identify_ns(fd, item->nsid, 0, &item->ns);
|
|
+ if (err) {
|
|
+ fprintf(stderr, "Unable to identify namespace for %s (%s)\n",
|
|
+ dev, strerror(err));
|
|
+ return 0;
|
|
+ }
|
|
+ strncpy(item->dev, dev, sizeof(item->dev));
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static int netapp_nvme_filter(const struct dirent *d)
|
|
+{
|
|
+ char path[264];
|
|
+ struct stat bd;
|
|
+ int ctrl, ns, partition;
|
|
+
|
|
+ if (d->d_name[0] == '.')
|
|
+ return 0;
|
|
+
|
|
+ if (strstr(d->d_name, "nvme")) {
|
|
+ snprintf(path, sizeof(path), "%s%s", dev_path, d->d_name);
|
|
+ if (stat(path, &bd))
|
|
+ return 0;
|
|
+ if (!S_ISBLK(bd.st_mode))
|
|
+ return 0;
|
|
+ if (sscanf(d->d_name, "nvme%dn%d", &ctrl, &ns) != 2)
|
|
+ return 0;
|
|
+ if (sscanf(d->d_name, "nvme%dn%dp%d", &ctrl, &ns, &partition) == 3)
|
|
+ return 0;
|
|
+ return 1;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int netapp_output_format(char *format)
|
|
+{
|
|
+ if (!format)
|
|
+ return -EINVAL;
|
|
+ if (!strcmp(format, "normal"))
|
|
+ return NNORMAL;
|
|
+ if (!strcmp(format, "json"))
|
|
+ return NJSON;
|
|
+ if (!strcmp(format, "column"))
|
|
+ return NCOLUMN;
|
|
+ return -EINVAL;
|
|
+}
|
|
+
|
|
+/* handler for 'nvme netapp smdevices' */
|
|
+static int netapp_smdevices(int argc, char **argv, struct command *command,
|
|
+ struct plugin *plugin)
|
|
+{
|
|
+ const char *desc = "Display information about E-Series volumes.";
|
|
+ struct config {
|
|
+ char *output_format;
|
|
+ };
|
|
+ struct config cfg = {
|
|
+ .output_format = "normal",
|
|
+ };
|
|
+ struct dirent **devices;
|
|
+ int num, i, fd, ret, fmt;
|
|
+ struct smdevice_info *smdevices;
|
|
+ char path[264];
|
|
+ int num_smdevices = 0;
|
|
+
|
|
+ const struct argconfig_commandline_options opts[] = {
|
|
+ {"output-format", 'o', "FMT", CFG_STRING, &cfg.output_format,
|
|
+ required_argument, "Output Format: normal|json|column"},
|
|
+ {NULL}
|
|
+ };
|
|
+
|
|
+ ret = argconfig_parse(argc, argv, desc, opts, &cfg, sizeof(cfg));
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ fmt = netapp_output_format(cfg.output_format);
|
|
+ if (fmt != NNORMAL && fmt != NCOLUMN && fmt != NJSON) {
|
|
+ fprintf(stderr, "Unrecognized output format: %s\n", cfg.output_format);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ num = scandir(dev_path, &devices, netapp_nvme_filter, alphasort);
|
|
+ if (num <= 0) {
|
|
+ fprintf(stderr, "No NVMe devices detected.\n");
|
|
+ return num;
|
|
+ }
|
|
+
|
|
+ smdevices = calloc(num, sizeof(*smdevices));
|
|
+ if (!smdevices) {
|
|
+ fprintf(stderr, "Unable to allocate memory for devices.\n");
|
|
+ return ENOMEM;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < num; i++) {
|
|
+ snprintf(path, sizeof(path), "%s%s", dev_path,
|
|
+ devices[i]->d_name);
|
|
+ fd = open(path, O_RDONLY);
|
|
+ if (fd < 0) {
|
|
+ fprintf(stderr, "Unable to open %s: %s\n", path,
|
|
+ strerror(errno));
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ num_smdevices += netapp_smdevices_get_info(fd,
|
|
+ &smdevices[num_smdevices], path);
|
|
+ close(fd);
|
|
+ }
|
|
+
|
|
+ if (num_smdevices)
|
|
+ netapp_smdevices_print(smdevices, num_smdevices, fmt);
|
|
+
|
|
+ for (i = 0; i < num; i++)
|
|
+ free(devices[i]);
|
|
+ free(devices);
|
|
+ free(smdevices);
|
|
+ return 0;
|
|
+}
|
|
--- /dev/null
|
|
+++ b/netapp-nvme.h
|
|
@@ -0,0 +1,17 @@
|
|
+#undef CMD_INC_FILE
|
|
+#define CMD_INC_FILE netapp-nvme
|
|
+
|
|
+#if !defined(NETAPP_NVME) || defined(CMD_HEADER_MULTI_READ)
|
|
+#define NETAPP_NVME
|
|
+
|
|
+#include "cmd.h"
|
|
+
|
|
+PLUGIN(NAME("netapp", "NetApp vendor specific extensions"),
|
|
+ COMMAND_LIST(
|
|
+ ENTRY("smdevices", "NetApp SMdevices", netapp_smdevices)
|
|
+ )
|
|
+);
|
|
+
|
|
+#endif
|
|
+
|
|
+#include "define_cmd.h"
|