forked from linux-nvme/libnvme
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmi-mctp-ae.c
More file actions
181 lines (144 loc) · 4.07 KB
/
mi-mctp-ae.c
File metadata and controls
181 lines (144 loc) · 4.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// 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;
}