-
Notifications
You must be signed in to change notification settings - Fork 134
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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]>
- Loading branch information
Showing
9 changed files
with
1,497 additions
and
38 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
// 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; | ||
bool enabled[256] = {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_aem_get_enabled(ep, enabled, sizeof(enabled)); | ||
if (rc) | ||
errx(EXIT_FAILURE, "Can't query enabled aems:%d (%d)", rc, errno); | ||
printf("The following events are now enabled:\n"); | ||
for (int i = 0; i < sizeof(enabled); i++) { | ||
if (enabled[i]) | ||
printf("Event: %d\n", i); | ||
} | ||
|
||
rc = nvme_mi_aem_enable(ep, true, true, true, 1, 100, &aem_cb_info, ¬ification_counter); | ||
if (rc) | ||
errx(EXIT_FAILURE, "Can't enable aem:%d (%d)", rc, errno); | ||
|
||
rc = nvme_mi_aem_get_enabled(ep, enabled, sizeof(enabled)); | ||
if (rc) | ||
errx(EXIT_FAILURE, "Can't query enabled aems:%d (%d)", rc, errno); | ||
|
||
|
||
|
||
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\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, ¬ification_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_aem_disable(ep); | ||
nvme_mi_close(ep); | ||
nvme_mi_free_root(root); | ||
|
||
return rc ? EXIT_FAILURE : EXIT_SUCCESS; | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.