Skip to content

Commit ac53516

Browse files
committed
mi: Introduce asynchronous event message handling
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]>
1 parent 8ad28af commit ac53516

9 files changed

Lines changed: 1484 additions & 33 deletions

File tree

cross_arm.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[binaries]
2+
c = 'arm-linux-gnueabihf-gcc'
3+
cpp = 'arm-linux-gnueabihf-cpp'
4+
ar = 'arm-linux-gnueabihf-ar'
5+
strip = 'arm-linux-gnueabihf-strip'
6+
7+
[host_machine]
8+
system = 'linux'
9+
cpu_family = 'arm'
10+
cpu = 'arm'
11+
endian = 'little'
12+
13+
[built-in options]
14+
c_args = ['-mfloat-abi=hard']
15+
cpp_args = ['-mfloat-abi=hard']

cross_arm64.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[binaries]
2+
c = 'aarch64-linux-gnu-gcc'
3+
cpp = 'aarch64-linux-gnu-cpp'
4+
ar = 'aarch64-linux-gnu-gcc-ar'
5+
strip = 'aarch64-linux-gnu-strip'
6+
7+
[host_machine]
8+
system = 'linux'
9+
cpu_family = 'aarch64'
10+
cpu = 'aarch64'
11+
endian = 'little'

examples/meson.build

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ executable(
4040
include_directories: [incdir, internal_incdir]
4141
)
4242

43+
executable(
44+
'mi-mctp-ae',
45+
['mi-mctp-ae.c'],
46+
dependencies: libnvme_mi_dep,
47+
include_directories: [incdir, internal_incdir]
48+
)
49+
4350
if libdbus_dep.found()
4451
executable(
4552
'mi-conf',

examples/mi-mctp-ae.c

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
// SPDX-License-Identifier: LGPL-2.1-or-later
2+
/**
3+
* This file is part of libnvme.
4+
*/
5+
6+
/**
7+
* mi-mctp-ae: open a MI connection over MCTP, supporting asynchronous event messages
8+
*/
9+
10+
#include <assert.h>
11+
#include <ctype.h>
12+
#include <err.h>
13+
#include <stdio.h>
14+
#include <stdlib.h>
15+
#include <stddef.h>
16+
#include <string.h>
17+
#include <errno.h>
18+
#include <unistd.h> // for usleep
19+
20+
#include <libnvme-mi.h>
21+
#include <poll.h>
22+
23+
#include <ccan/array_size/array_size.h>
24+
#include <ccan/endian/endian.h>
25+
#include <sys/select.h>
26+
27+
// Function to print the byte array
28+
static void print_byte_array(void *data, size_t len)
29+
{
30+
uint8_t *byte_data = (uint8_t *)data;
31+
32+
for (size_t i = 0; i < len; ++i)
33+
printf("%02X ", byte_data[i]);
34+
printf("\n");
35+
}
36+
37+
static void print_event_info(struct nvme_mi_event *event)
38+
{
39+
printf("aeoi: %02X\n", event->aeoi);
40+
printf("aeocidi: %04X\n", event->aeocidi);
41+
printf("aessi: %02X\n", event->aessi);
42+
43+
printf("specific_info: ");
44+
if (event->spec_info_len && event->spec_info)
45+
print_byte_array(event->spec_info, event->spec_info_len);
46+
else
47+
printf("EMPTY\n");
48+
49+
printf("vendor_specific_info: ");
50+
if (event->vend_spec_info_len && event->vend_spec_info)
51+
print_byte_array(event->vend_spec_info, event->vend_spec_info_len);
52+
else
53+
printf("EMPTY\n");
54+
}
55+
56+
enum handler_next_action aem_handler(nvme_mi_ep_t ep, size_t num_events, void *userdata)
57+
{
58+
uint32_t *count = (uint32_t *) userdata;
59+
*count = *count+1;
60+
61+
printf("Received notification #%ls\n with %ld events", count, num_events);
62+
for (int i = 0; i < num_events; i++) {
63+
struct nvme_mi_event *event = nvme_mi_aem_get_next_event(ep);
64+
65+
if (event == NULL)
66+
printf("Unexpected NULL event\n");
67+
else {
68+
printf("Event:\n");
69+
print_event_info(event);
70+
printf("\n");
71+
}
72+
}
73+
74+
return Ack;
75+
}
76+
77+
int main(int argc, char **argv)
78+
{
79+
nvme_root_t root;
80+
nvme_mi_ep_t ep;
81+
bool usage = true;
82+
uint8_t eid = 0;
83+
int rc = 0, net = 0;
84+
struct nvme_mi_aem_callbacks aem_cb_info = {0};
85+
uint32_t notification_counter = 0;
86+
87+
if (argc > 3) {
88+
usage = false;
89+
net = atoi(argv[1]);
90+
eid = atoi(argv[2]) & 0xff;
91+
argv += 2;
92+
argc -= 2;
93+
94+
int event_count = argc - 1;
95+
96+
for (int i = 0; i < event_count; i++) {
97+
int event = atoi(argv[1+i]);
98+
99+
aem_cb_info.enabled[event] = true;
100+
}
101+
}
102+
103+
if (usage) {
104+
fprintf(stderr,
105+
"usage: %s <net> <eid> [AE #s separated by spaces]\n",
106+
argv[0]);
107+
return EXIT_FAILURE;
108+
}
109+
110+
root = nvme_mi_create_root(stderr, DEFAULT_LOGLEVEL);
111+
if (!root)
112+
err(EXIT_FAILURE, "can't create NVMe root");
113+
114+
ep = nvme_mi_open_mctp(root, net, eid);
115+
if (!ep)
116+
errx(EXIT_FAILURE, "can't open MCTP endpoint %d:%d", net, eid);
117+
118+
aem_cb_info.aem_handler = aem_handler;
119+
120+
rc = nvme_mi_enable_aem(ep, true, true, true, 1, 4, &aem_cb_info, &notification_counter);
121+
if (rc)
122+
errx(EXIT_FAILURE, "Can't enable aem:%d (%d)", rc, errno);
123+
124+
struct pollfd fds;
125+
126+
rc = nvme_mi_get_pollfd(ep, &fds);
127+
if (rc)
128+
errx(EXIT_FAILURE, "Can't get pollfd:%d (%d)", rc, errno);
129+
130+
printf("Press any key to exit\n");
131+
while (1) {
132+
int poll_timeout = 500; // Timeout in milliseconds
133+
134+
fd_set read_fds;
135+
struct timeval std_in_timeout;
136+
int retval;
137+
138+
// Initialize the file descriptor set
139+
FD_ZERO(&read_fds);
140+
FD_SET(STDIN_FILENO, &read_fds);
141+
142+
// Set timeout to 0 seconds for non-blocking
143+
std_in_timeout.tv_sec = 0;
144+
std_in_timeout.tv_usec = 0;
145+
146+
// Check if there's input on stdin
147+
retval = select(STDIN_FILENO + 1, &read_fds, NULL, NULL, &std_in_timeout);
148+
149+
if (retval == -1) {
150+
perror("select()");
151+
exit(EXIT_FAILURE);
152+
} else if (retval) {
153+
char c = getchar();
154+
155+
if (c != EOF) {
156+
printf("Key pressed: %c\n", c);
157+
break;
158+
}
159+
}
160+
161+
rc = poll(&fds, 1, poll_timeout);
162+
163+
if (rc == -1) {
164+
perror("poll");
165+
break;
166+
} else if (rc == 0) {
167+
//printf("No data within %d milliseconds.\n", timeout);
168+
} else {
169+
//Time to do the work
170+
rc = nvme_mi_aem_process(ep, &notification_counter);
171+
if (rc) {
172+
errx(EXIT_FAILURE, "nvme_mi_aem_process failed with:%d (%d)", rc, errno);
173+
return rc;
174+
}
175+
}
176+
}
177+
178+
//Cleanup
179+
nvme_mi_disable_aem(ep);
180+
nvme_mi_close(ep);
181+
nvme_mi_free_root(root);
182+
183+
return rc ? EXIT_FAILURE : EXIT_SUCCESS;
184+
}
185+
186+

src/libnvme-mi.map

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
LIBNVME_MI_1_12 {
22
global:
33
nvme_mi_mi_xfer;
4+
nvme_mi_get_pollfd;
5+
nvme_mi_enable_aem;
6+
nvme_mi_aem_process;
7+
nvme_mi_disable_aem;
8+
nvme_mi_aem_get_next_event;
49
};
510

611
LIBNVME_MI_1_11 {
712
global:
813
nvme_mi_control;
14+
nvme_mi_get_async_message;
915
};
1016

1117
LIBNVME_MI_1_10 {

0 commit comments

Comments
 (0)