Skip to content

Commit 1c5c394

Browse files
chorkinigaw
authored andcommitted
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. Added tests for mi-mctp. Signed-off-by: Chuck Horkin <chorkin@microsoft.com>
1 parent 8971789 commit 1c5c394

File tree

9 files changed

+2355
-48
lines changed

9 files changed

+2355
-48
lines changed

examples/meson.build

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ executable(
4747
include_directories: [incdir, internal_incdir]
4848
)
4949

50+
executable(
51+
'mi-mctp-ae',
52+
['mi-mctp-ae.c'],
53+
dependencies: libnvme_mi_dep,
54+
include_directories: [incdir, internal_incdir]
55+
)
56+
5057
if libdbus_dep.found()
5158
executable(
5259
'mi-conf',

examples/mi-mctp-ae.c

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
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+
struct app_userdata {
28+
uint32_t count;
29+
};
30+
31+
static void print_byte_array(void *data, size_t len)
32+
{
33+
uint8_t *byte_data = (uint8_t *)data;
34+
35+
for (size_t i = 0; i < len; ++i)
36+
printf("%02X ", byte_data[i]);
37+
printf("\n");
38+
}
39+
40+
static void print_event_info(struct nvme_mi_event *event)
41+
{
42+
printf("aeoi: %02X\n", event->aeoi);
43+
printf("aeocidi: %04X\n", event->aeocidi);
44+
printf("aessi: %02X\n", event->aessi);
45+
46+
if (event->spec_info_len && event->spec_info) {
47+
printf("specific_info: ");
48+
print_byte_array(event->spec_info, event->spec_info_len);
49+
}
50+
51+
if (event->vend_spec_info_len && event->vend_spec_info) {
52+
printf("vendor_specific_info: ");
53+
print_byte_array(event->vend_spec_info, event->vend_spec_info_len);
54+
}
55+
}
56+
57+
enum nvme_mi_aem_handler_next_action aem_handler(nvme_mi_ep_t ep, size_t num_events, void *userdata)
58+
{
59+
struct app_userdata *data = (struct app_userdata *) userdata;
60+
61+
data->count++;
62+
63+
printf("Received notification #%d with %zu events:\n", data->count, num_events);
64+
for (int i = 0; i < num_events; i++) {
65+
struct nvme_mi_event *event = nvme_mi_aem_get_next_event(ep);
66+
67+
if (event == NULL)
68+
printf("Unexpected NULL event\n");
69+
else {
70+
printf("Event:\n");
71+
print_event_info(event);
72+
printf("\n");
73+
}
74+
}
75+
76+
return NVME_MI_AEM_HNA_ACK;
77+
}
78+
79+
int main(int argc, char **argv)
80+
{
81+
nvme_root_t root;
82+
nvme_mi_ep_t ep;
83+
uint8_t eid = 0;
84+
int rc = 0, net = 0;
85+
struct nvme_mi_aem_config aem_config = {0};
86+
struct nvme_mi_aem_enabled_map enabled_map = {0};
87+
struct app_userdata data = {0};
88+
89+
const uint8_t AEM_FD_INDEX = 0;
90+
const uint8_t STD_IN_FD_INDEX = 1;
91+
92+
if (argc == 4) {
93+
net = atoi(argv[1]);
94+
eid = atoi(argv[2]) & 0xff;
95+
argv += 2;
96+
argc -= 2;
97+
98+
int event_count = argc - 1;
99+
100+
for (int i = 0; i < event_count; i++) {
101+
int event = atoi(argv[1+i]);
102+
103+
aem_config.enabled_map.enabled[event] = true;
104+
}
105+
} else {
106+
fprintf(stderr,
107+
"usage: %s <net> <eid> [AE #s separated by spaces]\n",
108+
argv[0]);
109+
return EXIT_FAILURE;
110+
}
111+
112+
root = nvme_mi_create_root(stderr, DEFAULT_LOGLEVEL);
113+
if (!root)
114+
err(EXIT_FAILURE, "can't create NVMe root");
115+
116+
ep = nvme_mi_open_mctp(root, net, eid);
117+
if (!ep)
118+
err(EXIT_FAILURE, "can't open MCTP endpoint %d:%d", net, eid);
119+
120+
aem_config.aem_handler = aem_handler;
121+
aem_config.aemd = 1;
122+
aem_config.aerd = 100;
123+
124+
rc = nvme_mi_aem_get_enabled(ep, &enabled_map);
125+
if (rc)
126+
err(EXIT_FAILURE, "Can't query enabled aems:%d", rc);
127+
printf("The following events were previously enabled:\n");
128+
for (int i = 0; i < 256; i++) {
129+
if (enabled_map.enabled[i])
130+
printf("Event: %d\n", i);
131+
}
132+
133+
rc = nvme_mi_aem_enable(ep, &aem_config, &data);
134+
if (rc && errno == EOPNOTSUPP)
135+
errx(EXIT_FAILURE, "MCTP Peer-Bind is required for AEM");
136+
else if (rc)
137+
err(EXIT_FAILURE, "Can't enable aem:%d", rc);
138+
139+
rc = nvme_mi_aem_get_enabled(ep, &enabled_map);
140+
if (rc)
141+
err(EXIT_FAILURE, "Can't query enabled aems:%d", rc);
142+
143+
struct pollfd fds[2];
144+
145+
fds[AEM_FD_INDEX].fd = nvme_mi_aem_get_fd(ep);
146+
if (fds[AEM_FD_INDEX].fd < 0)
147+
errx(EXIT_FAILURE, "Can't get aem fd");
148+
149+
fds[STD_IN_FD_INDEX].fd = STDIN_FILENO;
150+
151+
fds[AEM_FD_INDEX].events = POLLIN;
152+
fds[STD_IN_FD_INDEX].events = POLLIN;
153+
154+
printf("Press any key to exit\n");
155+
while (1) {
156+
rc = poll(fds, 2, -1);
157+
158+
if (rc == -1) {
159+
warn("poll");
160+
break;
161+
}
162+
//Time to do the work
163+
if (fds[AEM_FD_INDEX].revents & POLLIN) {
164+
rc = nvme_mi_aem_process(ep, &data);
165+
if (rc)
166+
err(EXIT_FAILURE,
167+
"nvme_mi_aem_process failed with:%d", rc);
168+
}
169+
if (fds[STD_IN_FD_INDEX].revents & POLLIN)
170+
break;//we are done
171+
}
172+
173+
//Cleanup
174+
nvme_mi_aem_disable(ep);
175+
nvme_mi_close(ep);
176+
nvme_mi_free_root(root);
177+
178+
return rc ? EXIT_FAILURE : EXIT_SUCCESS;
179+
}
180+
181+

src/libnvme-mi.map

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
# SPDX-License-Identifier: LGPL-2.1-or-later
22
LIBNVME_MI_UNRELEASED {
33
global:
4+
nvme_mi_aem_disable;
5+
nvme_mi_aem_enable;
6+
nvme_mi_aem_get_enabled;
7+
nvme_mi_aem_get_fd;
8+
nvme_mi_aem_get_next_event;
9+
nvme_mi_aem_process;
410
nvme_mi_set_csi;
511
nvme_mi_submit_entry;
612
nvme_mi_submit_exit;

0 commit comments

Comments
 (0)