Adding upstream version 1.0.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
809e3412a9
commit
336fe81026
743 changed files with 51081 additions and 0 deletions
89
examples/discover-loop.c
Normal file
89
examples/discover-loop.c
Normal file
|
@ -0,0 +1,89 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/**
|
||||
* This file is part of libnvme.
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors: Keith Busch <keith.busch@wdc.com>
|
||||
*/
|
||||
|
||||
/**
|
||||
* discover-loop: Use fabrics commands to discover any loop targets and print
|
||||
* those records. You must have at least one configured nvme loop target on the
|
||||
* system (no existing connection required). The output will look more
|
||||
* interesting with more targets.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <libnvme.h>
|
||||
|
||||
#include <ccan/endian/endian.h>
|
||||
|
||||
static void print_discover_log(struct nvmf_discovery_log *log)
|
||||
{
|
||||
int i, numrec = le64_to_cpu(log->numrec);
|
||||
|
||||
printf(".\n");
|
||||
printf("|-- genctr:%llx\n", log->genctr);
|
||||
printf("|-- numrec:%x\n", numrec);
|
||||
printf("`-- recfmt:%x\n", log->recfmt);
|
||||
|
||||
for (i = 0; i < numrec; i++) {
|
||||
struct nvmf_disc_log_entry *e = &log->entries[i];
|
||||
|
||||
printf(" %c-- Entry:%d\n", (i < numrec - 1) ? '|' : '`', i);
|
||||
printf(" %c |-- trtype:%x\n", (i < numrec - 1) ? '|' : ' ', e->trtype);
|
||||
printf(" %c |-- adrfam:%x\n", (i < numrec - 1) ? '|' : ' ', e->adrfam);
|
||||
printf(" %c |-- subtype:%x\n", (i < numrec - 1) ? '|' : ' ', e->subtype);
|
||||
printf(" %c |-- treq:%x\n", (i < numrec - 1) ? '|' : ' ', e->treq);
|
||||
printf(" %c |-- portid:%x\n", (i < numrec - 1) ? '|' : ' ', e->portid);
|
||||
printf(" %c |-- cntlid:%x\n", (i < numrec - 1) ? '|' : ' ', e->cntlid);
|
||||
printf(" %c |-- asqsz:%x\n", (i < numrec - 1) ? '|' : ' ', e->asqsz);
|
||||
printf(" %c |-- trsvcid:%s\n", (i < numrec - 1) ? '|' : ' ', e->trsvcid);
|
||||
printf(" %c |-- subnqn:%s\n", (i < numrec - 1) ? '|' : ' ', e->subnqn);
|
||||
printf(" %c `-- traddr:%s\n", (i < numrec - 1) ? '|' : ' ', e->traddr);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
struct nvmf_discovery_log *log = NULL;
|
||||
nvme_root_t r;
|
||||
nvme_host_t h;
|
||||
nvme_ctrl_t c;
|
||||
int ret;
|
||||
struct nvme_fabrics_config cfg;
|
||||
|
||||
nvmf_default_config(&cfg);
|
||||
|
||||
r = nvme_scan(NULL);
|
||||
h = nvme_default_host(r);
|
||||
if (!h) {
|
||||
fprintf(stderr, "Failed to allocated memory\n");
|
||||
return ENOMEM;
|
||||
}
|
||||
c = nvme_create_ctrl(r, NVME_DISC_SUBSYS_NAME, "loop",
|
||||
NULL, NULL, NULL, NULL);
|
||||
if (!c) {
|
||||
fprintf(stderr, "Failed to allocate memory\n");
|
||||
return ENOMEM;
|
||||
}
|
||||
ret = nvmf_add_ctrl(h, c, &cfg);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "no controller found\n");
|
||||
return errno;
|
||||
}
|
||||
|
||||
ret = nvmf_get_discovery_log(c, &log, 4);
|
||||
nvme_disconnect_ctrl(c);
|
||||
nvme_free_ctrl(c);
|
||||
|
||||
if (ret)
|
||||
fprintf(stderr, "nvmf-discover-log:%x\n", ret);
|
||||
else
|
||||
print_discover_log(log);
|
||||
|
||||
nvme_free_tree(r);
|
||||
return 0;
|
||||
}
|
35
examples/discover-loop.py
Normal file
35
examples/discover-loop.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/python3
|
||||
'''
|
||||
Example script for nvme discovery
|
||||
|
||||
Copyright (c) 2021 Hannes Reinecke, SUSE Software Solutions
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
not use this file except in compliance with the License. You may obtain
|
||||
a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
'''
|
||||
|
||||
from libnvme import nvme
|
||||
r = nvme.root()
|
||||
h = nvme.host(r)
|
||||
c = nvme.ctrl(nvme.NVME_DISC_SUBSYS_NAME, 'loop')
|
||||
try:
|
||||
c.connect(h)
|
||||
except:
|
||||
sys.exit("Failed to connect!")
|
||||
|
||||
print("connected to %s subsys %s" % (c.name, c.subsystem.name))
|
||||
try:
|
||||
d = c.discover()
|
||||
print (d)
|
||||
except:
|
||||
print("Failed to discover!")
|
||||
pass
|
||||
c.disconnect()
|
121
examples/display-columnar.c
Normal file
121
examples/display-columnar.c
Normal file
|
@ -0,0 +1,121 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/**
|
||||
* This file is part of libnvme.
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors: Keith Busch <keith.busch@wdc.com>
|
||||
*/
|
||||
|
||||
/**
|
||||
* display-columnar: Scans the nvme topology, prints each record type in a
|
||||
* column format for easy visual scanning.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include <libnvme.h>
|
||||
|
||||
static const char dash[101] = {[0 ... 99] = '-'};
|
||||
int main()
|
||||
{
|
||||
nvme_root_t r;
|
||||
nvme_host_t h;
|
||||
nvme_subsystem_t s;
|
||||
nvme_ctrl_t c;
|
||||
nvme_path_t p;
|
||||
nvme_ns_t n;
|
||||
|
||||
r = nvme_scan(NULL);
|
||||
if (!r)
|
||||
return -1;
|
||||
|
||||
|
||||
printf("%-16s %-96s %-.16s\n", "Subsystem", "Subsystem-NQN", "Controllers");
|
||||
printf("%-.16s %-.96s %-.16s\n", dash, dash, dash);
|
||||
|
||||
nvme_for_each_host(r, h) {
|
||||
nvme_for_each_subsystem(h, s) {
|
||||
bool first = true;
|
||||
printf("%-16s %-96s ", nvme_subsystem_get_name(s),
|
||||
nvme_subsystem_get_nqn(s));
|
||||
|
||||
nvme_subsystem_for_each_ctrl(s, c) {
|
||||
printf("%s%s", first ? "": ", ",
|
||||
nvme_ctrl_get_name(c));
|
||||
first = false;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("%-8s %-20s %-40s %-8s %-6s %-14s %-12s %-16s\n", "Device",
|
||||
"SN", "MN", "FR", "TxPort", "Address", "Subsystem", "Namespaces");
|
||||
printf("%-.8s %-.20s %-.40s %-.8s %-.6s %-.14s %-.12s %-.16s\n", dash, dash,
|
||||
dash, dash, dash, dash, dash, dash);
|
||||
|
||||
nvme_for_each_host(r, h) {
|
||||
nvme_for_each_subsystem(h, s) {
|
||||
nvme_subsystem_for_each_ctrl(s, c) {
|
||||
bool first = true;
|
||||
|
||||
printf("%-8s %-20s %-40s %-8s %-6s %-14s %-12s ",
|
||||
nvme_ctrl_get_name(c),
|
||||
nvme_ctrl_get_serial(c),
|
||||
nvme_ctrl_get_model(c),
|
||||
nvme_ctrl_get_firmware(c),
|
||||
nvme_ctrl_get_transport(c),
|
||||
nvme_ctrl_get_address(c),
|
||||
nvme_subsystem_get_name(s));
|
||||
|
||||
nvme_ctrl_for_each_ns(c, n) {
|
||||
printf("%s%s", first ? "": ", ",
|
||||
nvme_ns_get_name(n));
|
||||
first = false;
|
||||
}
|
||||
|
||||
nvme_ctrl_for_each_path(c, p) {
|
||||
printf("%s%s", first ? "": ", ",
|
||||
nvme_ns_get_name(nvme_path_get_ns(p)));
|
||||
first = false;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("%-12s %-8s %-16s %-8s %-16s\n", "Device", "NSID", "Sectors", "Format", "Controllers");
|
||||
printf("%-.12s %-.8s %-.16s %-.8s %-.16s\n", dash, dash, dash, dash, dash);
|
||||
|
||||
nvme_for_each_host(r, h) {
|
||||
nvme_for_each_subsystem(h, s) {
|
||||
nvme_subsystem_for_each_ctrl(s, c) {
|
||||
nvme_ctrl_for_each_ns(c, n)
|
||||
printf("%-12s %-8d %-16" PRIu64 " %-8d %s\n",
|
||||
nvme_ns_get_name(n),
|
||||
nvme_ns_get_nsid(n),
|
||||
nvme_ns_get_lba_count(n),
|
||||
nvme_ns_get_lba_size(n),
|
||||
nvme_ctrl_get_name(c));
|
||||
}
|
||||
|
||||
nvme_subsystem_for_each_ns(s, n) {
|
||||
bool first = true;
|
||||
|
||||
printf("%-12s %-8d %-16" PRIu64 " %-8d ",
|
||||
nvme_ns_get_name(n),
|
||||
nvme_ns_get_nsid(n),
|
||||
nvme_ns_get_lba_count(n),
|
||||
nvme_ns_get_lba_size(n));
|
||||
nvme_subsystem_for_each_ctrl(s, c) {
|
||||
printf("%s%s", first ? "" : ", ",
|
||||
nvme_ctrl_get_name(c));
|
||||
first = false;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
71
examples/display-tree.c
Normal file
71
examples/display-tree.c
Normal file
|
@ -0,0 +1,71 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/**
|
||||
* This file is part of libnvme.
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors: Keith Busch <keith.busch@wdc.com>
|
||||
*/
|
||||
|
||||
/**
|
||||
* display-tree: Scans the nvme topology, prints as an ascii tree with some
|
||||
* selected attributes for each component.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <libnvme.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
nvme_root_t r;
|
||||
nvme_host_t h;
|
||||
nvme_subsystem_t s, _s;
|
||||
nvme_ctrl_t c, _c;
|
||||
nvme_path_t p, _p;
|
||||
nvme_ns_t n, _n;
|
||||
|
||||
r = nvme_scan(NULL);
|
||||
if (!r)
|
||||
return -1;
|
||||
|
||||
printf(".\n");
|
||||
nvme_for_each_host(r, h) {
|
||||
nvme_for_each_subsystem_safe(h, s, _s) {
|
||||
printf("%c-- %s - NQN=%s\n", _s ? '|' : '`',
|
||||
nvme_subsystem_get_name(s),
|
||||
nvme_subsystem_get_nqn(s));
|
||||
|
||||
nvme_subsystem_for_each_ns_safe(s, n, _n) {
|
||||
printf("%c |-- %s lba size:%d lba max:%lu\n",
|
||||
_s ? '|' : ' ',
|
||||
nvme_ns_get_name(n),
|
||||
nvme_ns_get_lba_size(n),
|
||||
nvme_ns_get_lba_count(n));
|
||||
}
|
||||
|
||||
nvme_subsystem_for_each_ctrl_safe(s, c, _c) {
|
||||
printf("%c %c-- %s %s %s %s\n",
|
||||
_s ? '|' : ' ', _c ? '|' : '`',
|
||||
nvme_ctrl_get_name(c),
|
||||
nvme_ctrl_get_transport(c),
|
||||
nvme_ctrl_get_address(c),
|
||||
nvme_ctrl_get_state(c));
|
||||
|
||||
nvme_ctrl_for_each_ns_safe(c, n, _n)
|
||||
printf("%c %c %c-- %s lba size:%d lba max:%lu\n",
|
||||
_s ? '|' : ' ', _c ? '|' : ' ',
|
||||
_n ? '|' : '`',
|
||||
nvme_ns_get_name(n),
|
||||
nvme_ns_get_lba_size(n),
|
||||
nvme_ns_get_lba_count(n));
|
||||
|
||||
nvme_ctrl_for_each_path_safe(c, p, _p)
|
||||
printf("%c %c %c-- %s %s\n",
|
||||
_s ? '|' : ' ', _c ? '|' : ' ',
|
||||
_p ? '|' : '`',
|
||||
nvme_path_get_name(p),
|
||||
nvme_path_get_ana_state(p));
|
||||
}
|
||||
}
|
||||
}
|
||||
nvme_free_tree(r);
|
||||
return 0;
|
||||
}
|
34
examples/meson.build
Normal file
34
examples/meson.build
Normal file
|
@ -0,0 +1,34 @@
|
|||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
#
|
||||
# This file is part of libnvme.
|
||||
# Copyright (c) 2021 Dell Inc.
|
||||
#
|
||||
# Authors: Martin Belanger <Martin.Belanger@dell.com>
|
||||
#
|
||||
executable(
|
||||
'telemetry-listen',
|
||||
['telemetry-listen.c'],
|
||||
link_with: libnvme,
|
||||
include_directories: [incdir, internal_incdir]
|
||||
)
|
||||
|
||||
executable(
|
||||
'display-columnar',
|
||||
['display-columnar.c'],
|
||||
link_with: libnvme,
|
||||
include_directories: [incdir, internal_incdir]
|
||||
)
|
||||
|
||||
executable(
|
||||
'display-tree',
|
||||
['display-tree.c'],
|
||||
link_with: libnvme,
|
||||
include_directories: [incdir, internal_incdir]
|
||||
)
|
||||
|
||||
executable(
|
||||
'discover-loop',
|
||||
['discover-loop.c'],
|
||||
link_with: libnvme,
|
||||
include_directories: [incdir, internal_incdir]
|
||||
)
|
167
examples/telemetry-listen.c
Normal file
167
examples/telemetry-listen.c
Normal file
|
@ -0,0 +1,167 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/**
|
||||
* This file is part of libnvme.
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors: Keith Busch <keith.busch@wdc.com>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Open all nvme controller's uevent and listen for changes. If NVME_AEN event
|
||||
* is observed with controller telemetry data, read the log and save it to a
|
||||
* file in /var/log/ with the device's unique name and epoch timestamp.
|
||||
*/
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <libnvme.h>
|
||||
|
||||
#include <ccan/endian/endian.h>
|
||||
|
||||
struct events {
|
||||
nvme_ctrl_t c;
|
||||
int uevent_fd;
|
||||
};
|
||||
|
||||
static int open_uevent(nvme_ctrl_t c)
|
||||
{
|
||||
char buf[0x1000];
|
||||
if (snprintf(buf, sizeof(buf), "%s/uevent", nvme_ctrl_get_sysfs_dir(c)) < 0)
|
||||
return -1;
|
||||
return open(buf, O_RDONLY);
|
||||
}
|
||||
|
||||
static void save_telemetry(nvme_ctrl_t c)
|
||||
{
|
||||
char buf[0x1000];
|
||||
size_t log_size;
|
||||
int ret, fd;
|
||||
struct nvme_telemetry_log *log;
|
||||
time_t s;
|
||||
|
||||
/* Clear the log (rae == false) at the end to see new telemetry events later */
|
||||
ret = nvme_get_ctrl_telemetry(nvme_ctrl_get_fd(c), false, &log, NVME_TELEMETRY_DA_3, &log_size);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
s = time(NULL);
|
||||
ret = snprintf(buf, sizeof(buf), "/var/log/%s-telemetry-%ld",
|
||||
nvme_ctrl_get_subsysnqn(c), s);
|
||||
if (ret < 0) {
|
||||
free(log);
|
||||
return;
|
||||
}
|
||||
log_size = (le16_to_cpu(log->dalb3) + 1) * NVME_LOG_TELEM_BLOCK_SIZE;
|
||||
|
||||
fd = open(buf, O_CREAT|O_WRONLY, S_IRUSR|S_IRGRP);
|
||||
if (fd < 0) {
|
||||
free(log);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = write(fd, log, log_size);
|
||||
if (ret < 0)
|
||||
printf("failed to write telemetry log\n");
|
||||
else
|
||||
printf("telemetry log save as %s, wrote:%d size:%ld\n", buf,
|
||||
ret, log_size);
|
||||
close(fd);
|
||||
free(log);
|
||||
}
|
||||
|
||||
static void check_telemetry(nvme_ctrl_t c, int ufd)
|
||||
{
|
||||
char buf[0x1000] = { 0 };
|
||||
char *p, *ptr;
|
||||
|
||||
if (read(ufd, buf, sizeof(buf)) < 0)
|
||||
return;
|
||||
|
||||
ptr = buf;
|
||||
while ((p = strsep(&ptr, "\n")) != NULL) {
|
||||
__u32 aen, type, info, lid;
|
||||
|
||||
if (sscanf(p, "NVME_AEN=0x%08x", &aen) != 1)
|
||||
continue;
|
||||
|
||||
type = aen & 0x07;
|
||||
info = (aen >> 8) & 0xff;
|
||||
lid = (aen >> 16) & 0xff;
|
||||
|
||||
printf("%s: aen type:%x info:%x lid:%d\n",
|
||||
nvme_ctrl_get_name(c), type, info, lid);
|
||||
if (type == NVME_AER_NOTICE &&
|
||||
info == NVME_AER_NOTICE_TELEMETRY)
|
||||
save_telemetry(c);
|
||||
}
|
||||
}
|
||||
|
||||
static void wait_events(fd_set *fds, struct events *e, int nr)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
for (i = 0; i < nr; i++)
|
||||
check_telemetry(e[i].c, e[i].uevent_fd);
|
||||
|
||||
while (1) {
|
||||
ret = select(nr, fds, NULL, NULL, NULL);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < nr; i++) {
|
||||
if (!FD_ISSET(e[i].uevent_fd, fds))
|
||||
continue;
|
||||
check_telemetry(e[i].c, e[i].uevent_fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
struct events *e;
|
||||
fd_set fds;
|
||||
int i = 0;
|
||||
|
||||
nvme_subsystem_t s;
|
||||
nvme_ctrl_t c;
|
||||
nvme_host_t h;
|
||||
nvme_root_t r;
|
||||
|
||||
r = nvme_scan(NULL);
|
||||
if (!r)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
nvme_for_each_host(r, h)
|
||||
nvme_for_each_subsystem(h, s)
|
||||
nvme_subsystem_for_each_ctrl(s, c)
|
||||
i++;
|
||||
|
||||
e = calloc(i, sizeof(e));
|
||||
FD_ZERO(&fds);
|
||||
i = 0;
|
||||
|
||||
nvme_for_each_host(r, h) {
|
||||
nvme_for_each_subsystem(h, s) {
|
||||
nvme_subsystem_for_each_ctrl(s, c) {
|
||||
int fd = open_uevent(c);
|
||||
|
||||
if (fd < 0)
|
||||
continue;
|
||||
FD_SET(fd, &fds);
|
||||
e[i].uevent_fd = fd;
|
||||
e[i].c = c;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wait_events(&fds, e, i);
|
||||
nvme_free_tree(r);
|
||||
free(e);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue