Skip to content

Commit 4a89153

Browse files
chorkinigaw
authored andcommitted
mi: Add support for multiple csi buffers
These are used to send up to two concurrent requests over MI to the endpoint. Signed-off-by: Chuck Horkin <chorkin@microsoft.com>
1 parent 28b0e03 commit 4a89153

File tree

7 files changed

+388
-91
lines changed

7 files changed

+388
-91
lines changed

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-csi-test',
45+
['mi-mctp-csi-test.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-csi-test.c

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
// SPDX-License-Identifier: LGPL-2.1-or-later
2+
/**
3+
* This file is part of libnvme.
4+
*/
5+
6+
/**
7+
* mi-mctp-csi-test: open a MI connection over MCTP, and send two commands
8+
* in parallel with different CSI buffers
9+
*/
10+
11+
#include <assert.h>
12+
#include <ctype.h>
13+
#include <err.h>
14+
#include <stdio.h>
15+
#include <stdlib.h>
16+
#include <stddef.h>
17+
#include <string.h>
18+
#include <pthread.h>
19+
20+
#include <libnvme-mi.h>
21+
22+
#include <ccan/array_size/array_size.h>
23+
#include <ccan/endian/endian.h>
24+
#include <bits/pthreadtypes.h>
25+
26+
void fhexdump(FILE *fp, const unsigned char *buf, int len)
27+
{
28+
const int row_len = 16;
29+
int i, j;
30+
31+
for (i = 0; i < len; i += row_len) {
32+
char hbuf[row_len * strlen("00 ") + 1];
33+
char cbuf[row_len + strlen("|") + 1];
34+
35+
for (j = 0; (j < row_len) && ((i+j) < len); j++) {
36+
unsigned char c = buf[i + j];
37+
38+
sprintf(hbuf + j * 3, "%02x ", c);
39+
40+
if (!isprint(c))
41+
c = '.';
42+
43+
sprintf(cbuf + j, "%c", c);
44+
}
45+
46+
strcat(cbuf, "|");
47+
48+
fprintf(fp, "%08x %*s |%s\n", i,
49+
0 - (int)sizeof(hbuf) + 1, hbuf, cbuf);
50+
}
51+
}
52+
53+
void hexdump(const unsigned char *buf, int len)
54+
{
55+
fhexdump(stdout, buf, len);
56+
}
57+
58+
int do_get_log_page(nvme_mi_ep_t ep, int argc, char **argv)
59+
{
60+
struct nvme_get_log_args args = { 0 };
61+
struct nvme_mi_ctrl *ctrl;
62+
uint8_t buf[4096];
63+
uint16_t ctrl_id;
64+
int rc, tmp;
65+
66+
if (argc < 2) {
67+
fprintf(stderr, "no controller ID specified\n");
68+
return -1;
69+
}
70+
71+
tmp = atoi(argv[1]);
72+
if (tmp < 0 || tmp > 0xffff) {
73+
fprintf(stderr, "invalid controller ID\n");
74+
return -1;
75+
}
76+
77+
ctrl_id = tmp & 0xffff;
78+
79+
args.args_size = sizeof(args);
80+
args.log = buf;
81+
args.len = sizeof(buf);
82+
83+
if (argc > 2) {
84+
tmp = atoi(argv[2]);
85+
args.lid = tmp & 0xff;
86+
} else {
87+
args.lid = 0x1;
88+
}
89+
90+
ctrl = nvme_mi_init_ctrl(ep, ctrl_id);
91+
if (!ctrl) {
92+
warn("can't create controller");
93+
return -1;
94+
}
95+
96+
rc = nvme_mi_admin_get_log(ctrl, &args);
97+
if (rc) {
98+
warn("can't perform Get Log page command");
99+
return -1;
100+
}
101+
102+
printf("Get log page (log id = 0x%02x) data:\n", args.lid);
103+
hexdump(buf, args.len);
104+
105+
return 0;
106+
}
107+
108+
struct thread_struct {
109+
nvme_mi_ep_t ep;
110+
int argc;
111+
char **argv;
112+
int rc;
113+
};
114+
115+
void *csi_thread_helper(void *context)
116+
{
117+
struct thread_struct *s = (struct thread_struct *) context;
118+
119+
s->rc = do_get_log_page(s->ep, s->argc, s->argv);
120+
return NULL;
121+
}
122+
123+
enum action {
124+
ACTION_CSI_TEST,
125+
};
126+
127+
int do_csi_test(nvme_root_t root, int net, __u8 eid,
128+
int argc, char **argv)
129+
{
130+
int rc = 0;
131+
nvme_mi_ep_t ep1, ep2;
132+
133+
ep1 = nvme_mi_open_mctp(root, net, eid);
134+
if (!ep1)
135+
errx(EXIT_FAILURE, "can't open MCTP endpoint %d:%d", net, eid);
136+
ep2 = nvme_mi_open_mctp(root, net, eid);
137+
if (!ep2)
138+
errx(EXIT_FAILURE, "can't open MCTP endpoint %d:%d", net, eid);
139+
140+
pthread_t thread;
141+
142+
nvme_mi_set_csi(ep1, 0);//Not necessary, but to be explicit
143+
nvme_mi_set_csi(ep2, 1);
144+
struct thread_struct s;
145+
146+
s.ep = ep2;
147+
s.argc = argc;
148+
s.argv = argv;
149+
150+
// Create a new thread to run my_function
151+
if (pthread_create(&thread, NULL, csi_thread_helper, &s)) {
152+
fprintf(stderr, "Error creating thread\n");
153+
return 1;
154+
}
155+
156+
rc = do_get_log_page(ep1, argc, argv);
157+
158+
// Main thread continues to do other work
159+
printf("Main thread finished with rc=%d\n", rc);
160+
161+
// Wait for the created thread to finish
162+
if (pthread_join(thread, NULL)) {
163+
fprintf(stderr, "Error joining thread\n");
164+
return 2;
165+
}
166+
167+
printf("Second thread finished with rc=%d\n", s.rc);
168+
169+
nvme_mi_close(ep1);
170+
nvme_mi_close(ep2);
171+
172+
if (rc)
173+
return rc;
174+
if (s.rc)
175+
return s.rc;
176+
return 0;
177+
}
178+
179+
static int do_action_endpoint(enum action action,
180+
nvme_root_t root,
181+
int net,
182+
uint8_t eid,
183+
int argc,
184+
char **argv)
185+
{
186+
int rc;
187+
188+
switch (action) {
189+
case ACTION_CSI_TEST:
190+
rc = do_csi_test(root, net, eid, argc, argv);
191+
break;
192+
default:
193+
/* This shouldn't be possible, as we should be covering all
194+
* of the enum action options above. Hoever, keep the compilers
195+
* happy and fail gracefully.
196+
*/
197+
fprintf(stderr, "invalid action %d?\n", action);
198+
rc = -1;
199+
}
200+
return rc;
201+
}
202+
203+
int main(int argc, char **argv)
204+
{
205+
enum action action;
206+
nvme_root_t root;
207+
bool usage = true;
208+
uint8_t eid = 0;
209+
int rc = 0, net = 0;
210+
211+
if (argc >= 5) {
212+
usage = false;
213+
net = atoi(argv[1]);
214+
eid = atoi(argv[2]) & 0xff;
215+
argv += 2;
216+
argc -= 2;
217+
}
218+
219+
if (usage) {
220+
fprintf(stderr,
221+
"usage: %s <net> <eid> [action] [action args]\n",
222+
argv[0]);
223+
fprintf(stderr, "where action is:\n"
224+
" csi-test <controller-id> [<log-id>]\n"
225+
"\n"
226+
);
227+
return EXIT_FAILURE;
228+
}
229+
230+
char *action_str = argv[1];
231+
232+
argc--;
233+
argv++;
234+
235+
if (!strcmp(action_str, "csi-test")) {
236+
action = ACTION_CSI_TEST;
237+
} else {
238+
fprintf(stderr, "invalid action '%s'\n", action_str);
239+
return EXIT_FAILURE;
240+
}
241+
242+
root = nvme_mi_create_root(stderr, DEFAULT_LOGLEVEL);
243+
if (!root)
244+
err(EXIT_FAILURE, "can't create NVMe root");
245+
246+
rc = do_action_endpoint(action, root, net, eid, argc, argv);
247+
nvme_mi_free_root(root);
248+
249+
return rc ? EXIT_FAILURE : EXIT_SUCCESS;
250+
}
251+
252+

src/libnvme-mi.map

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# SPDX-License-Identifier: LGPL-2.1-or-later
22
LIBNVME_MI_UNRELEASED {
33
global:
4+
nvme_mi_set_csi;
45
nvme_mi_submit_entry;
56
nvme_mi_submit_exit;
67
};

0 commit comments

Comments
 (0)