Skip to content

Commit

Permalink
mi: Introduce asynchronous event message handling
Browse files Browse the repository at this point in the history
Added new functionality to mi.c and mi-mctp.c to handle AEMs.  Included
new example mi-mctp-ae.c for usage.

Signed-off-by: Chuck Horkin <[email protected]>
  • Loading branch information
chorkin committed Mar 4, 2025
1 parent 8ad28af commit 3835077
Show file tree
Hide file tree
Showing 7 changed files with 1,544 additions and 36 deletions.
7 changes: 7 additions & 0 deletions examples/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ executable(
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',
Expand Down
172 changes: 172 additions & 0 deletions examples/mi-mctp-ae.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
// 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>

// Function to print the byte array
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);

printf("specific_info: ");
if (event->spec_info_len && event->spec_info)
print_byte_array(event->spec_info, event->spec_info_len);
else
printf("EMPTY\n");

printf("vendor_specific_info: ");
if (event->vend_spec_info_len && event->vend_spec_info)
print_byte_array(event->vend_spec_info, event->vend_spec_info_len);
else
printf("EMPTY\n");
}

enum nvme_mi_aem_handler_next_action aem_handler(nvme_mi_ep_t ep, size_t num_events, void *userdata)
{
uint32_t *count = (uint32_t *) userdata;
*count = *count+1;

printf("Received notification #%d with %zu events:\n", *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;
bool usage = true;
uint8_t eid = 0;
int rc = 0, net = 0;
struct nvme_mi_aem_callbacks aem_cb_info = {0};
uint32_t notification_counter = 0;

const uint8_t AEM_FD_INDEX = 0;
const uint8_t STD_IN_FD_INDEX = 1;

if (argc > 3) {
usage = false;
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_cb_info.enabled[event] = true;
}
}

if (usage) {
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)
errx(EXIT_FAILURE, "can't open MCTP endpoint %d:%d", net, eid);

aem_cb_info.aem_handler = aem_handler;

rc = nvme_mi_enable_aem(ep, true, true, true, 1, 4, &aem_cb_info, &notification_counter);
if (rc)
errx(EXIT_FAILURE, "Can't enable aem:%d (%d)", rc, errno);

struct pollfd fds[2];

fds[AEM_FD_INDEX].fd = nvme_mi_get_aem_fd(ep);
if (fds[AEM_FD_INDEX].fd < 0)
errx(EXIT_FAILURE, "Can't get aem fd\n");

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) {
int poll_timeout = 500; // Timeout in milliseconds

rc = poll(fds, 2, poll_timeout);

if (rc == -1) {
perror("poll");
break;
} else if (rc == 0) {
//printf("No data within %d milliseconds.\n", timeout);
} else {
//Time to do the work
if (fds[AEM_FD_INDEX].revents & POLLIN) {
rc = nvme_mi_aem_process(ep, &notification_counter);
if (rc)
errx(EXIT_FAILURE,
"nvme_mi_aem_process failed with:%d (%d)",
rc,
errno);
}
if (fds[STD_IN_FD_INDEX].revents & POLLIN)
break;//we are done
}
}

//Cleanup
nvme_mi_disable_aem(ep);
nvme_mi_close(ep);
nvme_mi_free_root(root);

return rc ? EXIT_FAILURE : EXIT_SUCCESS;
}


5 changes: 5 additions & 0 deletions src/libnvme-mi.map
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
LIBNVME_MI_1_12 {
global:
nvme_mi_mi_xfer;
nvme_mi_get_aem_fd;
nvme_mi_enable_aem;
nvme_mi_aem_process;
nvme_mi_disable_aem;
nvme_mi_aem_get_next_event;
};

LIBNVME_MI_1_11 {
Expand Down
Loading

0 comments on commit 3835077

Please sign in to comment.