Adding upstream version 1.14.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
515eb29eee
commit
9ae445a706
1041 changed files with 6076 additions and 1170 deletions
|
@ -40,6 +40,20 @@ executable(
|
|||
include_directories: [incdir, internal_incdir]
|
||||
)
|
||||
|
||||
executable(
|
||||
'mi-mctp-csi-test',
|
||||
['mi-mctp-csi-test.c'],
|
||||
dependencies: [libnvme_mi_dep, threads_dep],
|
||||
include_directories: [incdir, internal_incdir]
|
||||
)
|
||||
|
||||
executable(
|
||||
'mi-mctp-ae',
|
||||
['mi-mctp-ae.c'],
|
||||
dependencies: libnvme_mi_dep,
|
||||
include_directories: [incdir, internal_incdir]
|
||||
)
|
||||
|
||||
if libdbus_dep.found()
|
||||
executable(
|
||||
'mi-conf',
|
||||
|
|
181
examples/mi-mctp-ae.c
Normal file
181
examples/mi-mctp-ae.c
Normal file
|
@ -0,0 +1,181 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/**
|
||||
* This file is part of libnvme.
|
||||
*/
|
||||
|
||||
/**
|
||||
* mi-mctp-ae: open a MI connection over MCTP, supporting asynchronous event messages
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h> // for usleep
|
||||
|
||||
#include <libnvme-mi.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include <ccan/array_size/array_size.h>
|
||||
#include <ccan/endian/endian.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
struct app_userdata {
|
||||
uint32_t count;
|
||||
};
|
||||
|
||||
static void print_byte_array(void *data, size_t len)
|
||||
{
|
||||
uint8_t *byte_data = (uint8_t *)data;
|
||||
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
printf("%02X ", byte_data[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void print_event_info(struct nvme_mi_event *event)
|
||||
{
|
||||
printf("aeoi: %02X\n", event->aeoi);
|
||||
printf("aeocidi: %04X\n", event->aeocidi);
|
||||
printf("aessi: %02X\n", event->aessi);
|
||||
|
||||
if (event->spec_info_len && event->spec_info) {
|
||||
printf("specific_info: ");
|
||||
print_byte_array(event->spec_info, event->spec_info_len);
|
||||
}
|
||||
|
||||
if (event->vend_spec_info_len && event->vend_spec_info) {
|
||||
printf("vendor_specific_info: ");
|
||||
print_byte_array(event->vend_spec_info, event->vend_spec_info_len);
|
||||
}
|
||||
}
|
||||
|
||||
enum nvme_mi_aem_handler_next_action aem_handler(nvme_mi_ep_t ep, size_t num_events, void *userdata)
|
||||
{
|
||||
struct app_userdata *data = (struct app_userdata *) userdata;
|
||||
|
||||
data->count++;
|
||||
|
||||
printf("Received notification #%d with %zu events:\n", data->count, num_events);
|
||||
for (int i = 0; i < num_events; i++) {
|
||||
struct nvme_mi_event *event = nvme_mi_aem_get_next_event(ep);
|
||||
|
||||
if (event == NULL)
|
||||
printf("Unexpected NULL event\n");
|
||||
else {
|
||||
printf("Event:\n");
|
||||
print_event_info(event);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
return NVME_MI_AEM_HNA_ACK;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
nvme_root_t root;
|
||||
nvme_mi_ep_t ep;
|
||||
uint8_t eid = 0;
|
||||
int rc = 0, net = 0;
|
||||
struct nvme_mi_aem_config aem_config = {0};
|
||||
struct nvme_mi_aem_enabled_map enabled_map = {0};
|
||||
struct app_userdata data = {0};
|
||||
|
||||
const uint8_t AEM_FD_INDEX = 0;
|
||||
const uint8_t STD_IN_FD_INDEX = 1;
|
||||
|
||||
if (argc == 4) {
|
||||
net = atoi(argv[1]);
|
||||
eid = atoi(argv[2]) & 0xff;
|
||||
argv += 2;
|
||||
argc -= 2;
|
||||
|
||||
int event_count = argc - 1;
|
||||
|
||||
for (int i = 0; i < event_count; i++) {
|
||||
int event = atoi(argv[1+i]);
|
||||
|
||||
aem_config.enabled_map.enabled[event] = true;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"usage: %s <net> <eid> [AE #s separated by spaces]\n",
|
||||
argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
root = nvme_mi_create_root(stderr, DEFAULT_LOGLEVEL);
|
||||
if (!root)
|
||||
err(EXIT_FAILURE, "can't create NVMe root");
|
||||
|
||||
ep = nvme_mi_open_mctp(root, net, eid);
|
||||
if (!ep)
|
||||
err(EXIT_FAILURE, "can't open MCTP endpoint %d:%d", net, eid);
|
||||
|
||||
aem_config.aem_handler = aem_handler;
|
||||
aem_config.aemd = 1;
|
||||
aem_config.aerd = 100;
|
||||
|
||||
rc = nvme_mi_aem_get_enabled(ep, &enabled_map);
|
||||
if (rc)
|
||||
err(EXIT_FAILURE, "Can't query enabled aems:%d", rc);
|
||||
printf("The following events were previously enabled:\n");
|
||||
for (int i = 0; i < 256; i++) {
|
||||
if (enabled_map.enabled[i])
|
||||
printf("Event: %d\n", i);
|
||||
}
|
||||
|
||||
rc = nvme_mi_aem_enable(ep, &aem_config, &data);
|
||||
if (rc && errno == EOPNOTSUPP)
|
||||
errx(EXIT_FAILURE, "MCTP Peer-Bind is required for AEM");
|
||||
else if (rc)
|
||||
err(EXIT_FAILURE, "Can't enable aem:%d", rc);
|
||||
|
||||
rc = nvme_mi_aem_get_enabled(ep, &enabled_map);
|
||||
if (rc)
|
||||
err(EXIT_FAILURE, "Can't query enabled aems:%d", rc);
|
||||
|
||||
struct pollfd fds[2];
|
||||
|
||||
fds[AEM_FD_INDEX].fd = nvme_mi_aem_get_fd(ep);
|
||||
if (fds[AEM_FD_INDEX].fd < 0)
|
||||
errx(EXIT_FAILURE, "Can't get aem fd");
|
||||
|
||||
fds[STD_IN_FD_INDEX].fd = STDIN_FILENO;
|
||||
|
||||
fds[AEM_FD_INDEX].events = POLLIN;
|
||||
fds[STD_IN_FD_INDEX].events = POLLIN;
|
||||
|
||||
printf("Press any key to exit\n");
|
||||
while (1) {
|
||||
rc = poll(fds, 2, -1);
|
||||
|
||||
if (rc == -1) {
|
||||
warn("poll");
|
||||
break;
|
||||
}
|
||||
//Time to do the work
|
||||
if (fds[AEM_FD_INDEX].revents & POLLIN) {
|
||||
rc = nvme_mi_aem_process(ep, &data);
|
||||
if (rc)
|
||||
err(EXIT_FAILURE,
|
||||
"nvme_mi_aem_process failed with:%d", rc);
|
||||
}
|
||||
if (fds[STD_IN_FD_INDEX].revents & POLLIN)
|
||||
break;//we are done
|
||||
}
|
||||
|
||||
//Cleanup
|
||||
nvme_mi_aem_disable(ep);
|
||||
nvme_mi_close(ep);
|
||||
nvme_mi_free_root(root);
|
||||
|
||||
return rc ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
252
examples/mi-mctp-csi-test.c
Normal file
252
examples/mi-mctp-csi-test.c
Normal file
|
@ -0,0 +1,252 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/**
|
||||
* This file is part of libnvme.
|
||||
*/
|
||||
|
||||
/**
|
||||
* mi-mctp-csi-test: open a MI connection over MCTP, and send two commands
|
||||
* in parallel with different CSI buffers
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <libnvme-mi.h>
|
||||
|
||||
#include <ccan/array_size/array_size.h>
|
||||
#include <ccan/endian/endian.h>
|
||||
#include <bits/pthreadtypes.h>
|
||||
|
||||
void fhexdump(FILE *fp, const unsigned char *buf, int len)
|
||||
{
|
||||
const int row_len = 16;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < len; i += row_len) {
|
||||
char hbuf[row_len * strlen("00 ") + 1];
|
||||
char cbuf[row_len + strlen("|") + 1];
|
||||
|
||||
for (j = 0; (j < row_len) && ((i+j) < len); j++) {
|
||||
unsigned char c = buf[i + j];
|
||||
|
||||
sprintf(hbuf + j * 3, "%02x ", c);
|
||||
|
||||
if (!isprint(c))
|
||||
c = '.';
|
||||
|
||||
sprintf(cbuf + j, "%c", c);
|
||||
}
|
||||
|
||||
strcat(cbuf, "|");
|
||||
|
||||
fprintf(fp, "%08x %*s |%s\n", i,
|
||||
0 - (int)sizeof(hbuf) + 1, hbuf, cbuf);
|
||||
}
|
||||
}
|
||||
|
||||
void hexdump(const unsigned char *buf, int len)
|
||||
{
|
||||
fhexdump(stdout, buf, len);
|
||||
}
|
||||
|
||||
int do_get_log_page(nvme_mi_ep_t ep, int argc, char **argv)
|
||||
{
|
||||
struct nvme_get_log_args args = { 0 };
|
||||
struct nvme_mi_ctrl *ctrl;
|
||||
uint8_t buf[4096];
|
||||
uint16_t ctrl_id;
|
||||
int rc, tmp;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "no controller ID specified\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
tmp = atoi(argv[1]);
|
||||
if (tmp < 0 || tmp > 0xffff) {
|
||||
fprintf(stderr, "invalid controller ID\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctrl_id = tmp & 0xffff;
|
||||
|
||||
args.args_size = sizeof(args);
|
||||
args.log = buf;
|
||||
args.len = sizeof(buf);
|
||||
|
||||
if (argc > 2) {
|
||||
tmp = atoi(argv[2]);
|
||||
args.lid = tmp & 0xff;
|
||||
} else {
|
||||
args.lid = 0x1;
|
||||
}
|
||||
|
||||
ctrl = nvme_mi_init_ctrl(ep, ctrl_id);
|
||||
if (!ctrl) {
|
||||
warn("can't create controller");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = nvme_mi_admin_get_log(ctrl, &args);
|
||||
if (rc) {
|
||||
warn("can't perform Get Log page command");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Get log page (log id = 0x%02x) data:\n", args.lid);
|
||||
hexdump(buf, args.len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct thread_struct {
|
||||
nvme_mi_ep_t ep;
|
||||
int argc;
|
||||
char **argv;
|
||||
int rc;
|
||||
};
|
||||
|
||||
void *csi_thread_helper(void *context)
|
||||
{
|
||||
struct thread_struct *s = (struct thread_struct *) context;
|
||||
|
||||
s->rc = do_get_log_page(s->ep, s->argc, s->argv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
enum action {
|
||||
ACTION_CSI_TEST,
|
||||
};
|
||||
|
||||
int do_csi_test(nvme_root_t root, int net, __u8 eid,
|
||||
int argc, char **argv)
|
||||
{
|
||||
int rc = 0;
|
||||
nvme_mi_ep_t ep1, ep2;
|
||||
|
||||
ep1 = nvme_mi_open_mctp(root, net, eid);
|
||||
if (!ep1)
|
||||
errx(EXIT_FAILURE, "can't open MCTP endpoint %d:%d", net, eid);
|
||||
ep2 = nvme_mi_open_mctp(root, net, eid);
|
||||
if (!ep2)
|
||||
errx(EXIT_FAILURE, "can't open MCTP endpoint %d:%d", net, eid);
|
||||
|
||||
pthread_t thread;
|
||||
|
||||
nvme_mi_set_csi(ep1, 0);//Not necessary, but to be explicit
|
||||
nvme_mi_set_csi(ep2, 1);
|
||||
struct thread_struct s;
|
||||
|
||||
s.ep = ep2;
|
||||
s.argc = argc;
|
||||
s.argv = argv;
|
||||
|
||||
// Create a new thread to run my_function
|
||||
if (pthread_create(&thread, NULL, csi_thread_helper, &s)) {
|
||||
fprintf(stderr, "Error creating thread\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = do_get_log_page(ep1, argc, argv);
|
||||
|
||||
// Main thread continues to do other work
|
||||
printf("Main thread finished with rc=%d\n", rc);
|
||||
|
||||
// Wait for the created thread to finish
|
||||
if (pthread_join(thread, NULL)) {
|
||||
fprintf(stderr, "Error joining thread\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
printf("Second thread finished with rc=%d\n", s.rc);
|
||||
|
||||
nvme_mi_close(ep1);
|
||||
nvme_mi_close(ep2);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
if (s.rc)
|
||||
return s.rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_action_endpoint(enum action action,
|
||||
nvme_root_t root,
|
||||
int net,
|
||||
uint8_t eid,
|
||||
int argc,
|
||||
char **argv)
|
||||
{
|
||||
int rc;
|
||||
|
||||
switch (action) {
|
||||
case ACTION_CSI_TEST:
|
||||
rc = do_csi_test(root, net, eid, argc, argv);
|
||||
break;
|
||||
default:
|
||||
/* This shouldn't be possible, as we should be covering all
|
||||
* of the enum action options above. Hoever, keep the compilers
|
||||
* happy and fail gracefully.
|
||||
*/
|
||||
fprintf(stderr, "invalid action %d?\n", action);
|
||||
rc = -1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
enum action action;
|
||||
nvme_root_t root;
|
||||
bool usage = true;
|
||||
uint8_t eid = 0;
|
||||
int rc = 0, net = 0;
|
||||
|
||||
if (argc >= 5) {
|
||||
usage = false;
|
||||
net = atoi(argv[1]);
|
||||
eid = atoi(argv[2]) & 0xff;
|
||||
argv += 2;
|
||||
argc -= 2;
|
||||
}
|
||||
|
||||
if (usage) {
|
||||
fprintf(stderr,
|
||||
"usage: %s <net> <eid> [action] [action args]\n",
|
||||
argv[0]);
|
||||
fprintf(stderr, "where action is:\n"
|
||||
" csi-test <controller-id> [<log-id>]\n"
|
||||
"\n"
|
||||
);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
char *action_str = argv[1];
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
if (!strcmp(action_str, "csi-test")) {
|
||||
action = ACTION_CSI_TEST;
|
||||
} else {
|
||||
fprintf(stderr, "invalid action '%s'\n", action_str);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
root = nvme_mi_create_root(stderr, DEFAULT_LOGLEVEL);
|
||||
if (!root)
|
||||
err(EXIT_FAILURE, "can't create NVMe root");
|
||||
|
||||
rc = do_action_endpoint(action, root, net, eid, argc, argv);
|
||||
nvme_mi_free_root(root);
|
||||
|
||||
return rc ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue