| File: | .build-ci/../libnvme/test/mi-mctp.c |
| Warning: | line 1190, column 3 Address of stack memory associated with local variable 'fn_data' is still referred to by the caller variable 'peer' upon returning to the caller. This will be a dangling reference |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | // SPDX-License-Identifier: LGPL-2.1-or-later | |||
| 2 | /** | |||
| 3 | * This file is part of libnvme. | |||
| 4 | * Copyright (c) 2022 Code Construct | |||
| 5 | */ | |||
| 6 | ||||
| 7 | #undef NDEBUG | |||
| 8 | #include <shr-assert.h> | |||
| 9 | #include <errno(*__errno_location ()).h> | |||
| 10 | #include <fcntl.h> | |||
| 11 | #include <stdio.h> | |||
| 12 | #include <stdlib.h> | |||
| 13 | #include <string.h> | |||
| 14 | #include <unistd.h> | |||
| 15 | ||||
| 16 | #include <sys/ioctl.h> | |||
| 17 | #include <sys/socket.h> | |||
| 18 | ||||
| 19 | #if NVME_HAVE_LINUX_MCTP_H1 | |||
| 20 | #include <linux1/mctp.h> | |||
| 21 | #else | |||
| 22 | #include "nvme/mi-mctp-compat.h" | |||
| 23 | #endif | |||
| 24 | ||||
| 25 | #include <ccan/array_size/array_size.h> | |||
| 26 | #include <ccan/endian/endian.h> | |||
| 27 | ||||
| 28 | #include <libnvme.h> | |||
| 29 | #include <libnvme-mi.h> | |||
| 30 | ||||
| 31 | #include "nvme/private.h" | |||
| 32 | #include "nvme/private-mi.h" | |||
| 33 | ||||
| 34 | #include "utils.h" | |||
| 35 | ||||
| 36 | /* 4096 byte max MCTP message, plus space for header data */ | |||
| 37 | #define MAX_BUFSIZ8192 8192 | |||
| 38 | ||||
| 39 | struct test_peer; | |||
| 40 | ||||
| 41 | typedef int (*rx_test_fn)(struct test_peer *peer, void *buf, size_t len, int sd); | |||
| 42 | typedef int (*poll_test_fn)(struct test_peer *peer, | |||
| 43 | struct pollfd *fds, nfds_t nfds, int timeout); | |||
| 44 | ||||
| 45 | #define TEST_PEER_SD_COMMANDS_IDX(0) (0) | |||
| 46 | #define TEST_PEER_SD_AEMS_IDX(1) (1) | |||
| 47 | ||||
| 48 | /* Our fake MCTP "peer". | |||
| 49 | * | |||
| 50 | * The terms TX (transmit) and RX (receive) are from the perspective of | |||
| 51 | * the NVMe device. TX is device-to-libnvme, RX is libnvme-to-device. | |||
| 52 | * | |||
| 53 | * The RX and TX buffers are linear versions of the data sent and received by | |||
| 54 | * libnvme-mi, and *include* the MCTP message type byte (even though it's | |||
| 55 | * omitted in the sendmsg/recvmsg interface), so that the buffer inspection | |||
| 56 | * in the tests can exactly match the NVMe-MI spec packet diagrams. | |||
| 57 | */ | |||
| 58 | static struct test_peer { | |||
| 59 | /* rx (sendmsg) data sent from libnvme, and return value */ | |||
| 60 | unsigned char rx_buf[MAX_BUFSIZ8192]; | |||
| 61 | size_t rx_buf_len; | |||
| 62 | ssize_t rx_rc; /* if zero, return the sendmsg len */ | |||
| 63 | int rx_errno; | |||
| 64 | ||||
| 65 | /* tx (recvmsg) data to be received by libnvme and return value */ | |||
| 66 | unsigned char tx_buf[MAX_BUFSIZ8192]; | |||
| 67 | size_t tx_buf_len; | |||
| 68 | ssize_t tx_rc; /* if zero, return the recvmsg len */ | |||
| 69 | int tx_errno; | |||
| 70 | ||||
| 71 | /* Optional, called before TX, may set tx_buf according to request. | |||
| 72 | * Return value stored in tx_res, may be used by test */ | |||
| 73 | rx_test_fn tx_fn; | |||
| 74 | void *tx_data; | |||
| 75 | int tx_fn_res; | |||
| 76 | ||||
| 77 | poll_test_fn poll_fn; | |||
| 78 | void *poll_data; | |||
| 79 | ||||
| 80 | /* store sd from socket() setup */ | |||
| 81 | int sd[2]; | |||
| 82 | } test_peer; | |||
| 83 | ||||
| 84 | /* ensure tests start from a standard state */ | |||
| 85 | void reset_test_peer(void) | |||
| 86 | { | |||
| 87 | int temp_sd[2] = {test_peer.sd[TEST_PEER_SD_COMMANDS_IDX(0)], | |||
| 88 | test_peer.sd[TEST_PEER_SD_AEMS_IDX(1)]}; | |||
| 89 | ||||
| 90 | memset(&test_peer, 0, sizeof(test_peer)); | |||
| 91 | test_peer.tx_buf[0] = NVME_MI_MSGTYPE_NVME0x84; | |||
| 92 | test_peer.rx_buf[0] = NVME_MI_MSGTYPE_NVME0x84; | |||
| 93 | memcpy(test_peer.sd, temp_sd, 2*sizeof(*temp_sd)); | |||
| 94 | } | |||
| 95 | ||||
| 96 | /* calculate MIC of peer-to-libnvme data, expand buf by 4 bytes and insert | |||
| 97 | * the new MIC */ | |||
| 98 | static void test_set_tx_mic(struct test_peer *peer) | |||
| 99 | { | |||
| 100 | extern __u32 libnvme_mi_crc32_update(__u32 crc, void *data, size_t len); | |||
| 101 | __u32 crc = 0xffffffff; | |||
| 102 | __le32 crc_le; | |||
| 103 | ||||
| 104 | shr_assert(peer->tx_buf_len + sizeof(crc_le) <= MAX_BUFSIZ)((void)((peer->tx_buf_len + sizeof(crc_le) <= 8192) || ( shr_assert_fail("../libnvme/test/mi-mctp.c", 104, "peer->tx_buf_len + sizeof(crc_le) <= MAX_BUFSIZ" ), 0))); | |||
| 105 | ||||
| 106 | crc = libnvme_mi_crc32_update(crc, peer->tx_buf, peer->tx_buf_len); | |||
| 107 | crc_le = cpu_to_le32(~crc); | |||
| 108 | memcpy(peer->tx_buf + peer->tx_buf_len, &crc_le, sizeof(crc_le)); | |||
| 109 | peer->tx_buf_len += sizeof(crc_le); | |||
| 110 | } | |||
| 111 | ||||
| 112 | int __wrap_msg_socket(void) | |||
| 113 | { | |||
| 114 | /* we do an open here to give the mi-mctp code something to close() */ | |||
| 115 | test_peer.sd[TEST_PEER_SD_COMMANDS_IDX(0)] = open("/dev/null", 0); | |||
| 116 | return test_peer.sd[TEST_PEER_SD_COMMANDS_IDX(0)]; | |||
| 117 | } | |||
| 118 | ||||
| 119 | int __wrap_aem_socket(__u8 eid, unsigned int network) | |||
| 120 | { | |||
| 121 | /* we do an open here to give the mi-mctp code something to close() */ | |||
| 122 | test_peer.sd[TEST_PEER_SD_AEMS_IDX(1)] = open("/dev/null", 0); | |||
| 123 | return test_peer.sd[TEST_PEER_SD_AEMS_IDX(1)]; | |||
| 124 | } | |||
| 125 | ||||
| 126 | ssize_t __wrap_sendmsg(int sd, const struct msghdr *hdr, int flags) | |||
| 127 | { | |||
| 128 | size_t i, pos; | |||
| 129 | ||||
| 130 | shr_assert(sd == test_peer.sd[TEST_PEER_SD_COMMANDS_IDX])((void)((sd == test_peer.sd[(0)]) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 130, "sd == test_peer.sd[TEST_PEER_SD_COMMANDS_IDX]"), 0))); | |||
| 131 | ||||
| 132 | test_peer.rx_buf[0] = NVME_MI_MSGTYPE_NVME0x84; | |||
| 133 | ||||
| 134 | /* gather iovec into buf */ | |||
| 135 | for (i = 0, pos = 1; i < hdr->msg_iovlen; i++) { | |||
| 136 | struct iovec *iov = &hdr->msg_iov[i]; | |||
| 137 | ||||
| 138 | shr_assert(pos + iov->iov_len < MAX_BUFSIZ - 1)((void)((pos + iov->iov_len < 8192 - 1) || (shr_assert_fail ("../libnvme/test/mi-mctp.c", 138, "pos + iov->iov_len < MAX_BUFSIZ - 1" ), 0))); | |||
| 139 | memcpy(test_peer.rx_buf + pos, iov->iov_base, iov->iov_len); | |||
| 140 | pos += iov->iov_len; | |||
| 141 | } | |||
| 142 | ||||
| 143 | test_peer.rx_buf_len = pos; | |||
| 144 | ||||
| 145 | errno(*__errno_location ()) = test_peer.rx_errno; | |||
| 146 | ||||
| 147 | return test_peer.rx_rc ?: (pos - 1); | |||
| 148 | } | |||
| 149 | ||||
| 150 | ssize_t __wrap_recvmsg(int sd, struct msghdr *hdr, int flags) | |||
| 151 | { | |||
| 152 | size_t i, pos, len; | |||
| 153 | ||||
| 154 | shr_assert(sd == test_peer.sd[TEST_PEER_SD_COMMANDS_IDX] ||((void)((sd == test_peer.sd[(0)] || sd == test_peer.sd[(1)]) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 155, "sd == test_peer.sd[TEST_PEER_SD_COMMANDS_IDX] || sd == test_peer.sd[TEST_PEER_SD_AEMS_IDX]" ), 0))) | |||
| 155 | sd == test_peer.sd[TEST_PEER_SD_AEMS_IDX])((void)((sd == test_peer.sd[(0)] || sd == test_peer.sd[(1)]) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 155, "sd == test_peer.sd[TEST_PEER_SD_COMMANDS_IDX] || sd == test_peer.sd[TEST_PEER_SD_AEMS_IDX]" ), 0))); | |||
| 156 | ||||
| 157 | //Check for purge case | |||
| 158 | if (flags & MSG_TRUNCMSG_TRUNC) | |||
| 159 | return 0; | |||
| 160 | ||||
| 161 | if (test_peer.tx_fn) { | |||
| 162 | test_peer.tx_fn_res = test_peer.tx_fn(&test_peer, | |||
| 163 | test_peer.rx_buf, | |||
| 164 | test_peer.rx_buf_len, | |||
| 165 | sd); | |||
| 166 | } else { | |||
| 167 | if (sd == test_peer.sd[TEST_PEER_SD_COMMANDS_IDX(0)] && test_peer.tx_buf_len == 0) { | |||
| 168 | errno(*__errno_location ()) = EAGAIN11; | |||
| 169 | return -1; | |||
| 170 | } | |||
| 171 | /* set up a few default response fields; caller may have | |||
| 172 | * initialised the rest of the response */ | |||
| 173 | test_peer.tx_buf[0] = NVME_MI_MSGTYPE_NVME0x84; | |||
| 174 | test_peer.tx_buf[1] = test_peer.rx_buf[1] | (NVME_MI_ROR_RSP << 7); | |||
| 175 | test_set_tx_mic(&test_peer); | |||
| 176 | } | |||
| 177 | ||||
| 178 | /* scatter buf into iovec */ | |||
| 179 | for (i = 0, pos = 1; i < hdr->msg_iovlen && pos < test_peer.tx_buf_len; | |||
| 180 | i++) { | |||
| 181 | struct iovec *iov = &hdr->msg_iov[i]; | |||
| 182 | ||||
| 183 | len = iov->iov_len; | |||
| 184 | if (len > test_peer.tx_buf_len - pos) | |||
| 185 | len = test_peer.tx_buf_len - pos; | |||
| 186 | ||||
| 187 | memcpy(iov->iov_base, test_peer.tx_buf + pos, len); | |||
| 188 | pos += len; | |||
| 189 | } | |||
| 190 | ||||
| 191 | errno(*__errno_location ()) = test_peer.tx_errno; | |||
| 192 | ||||
| 193 | test_peer.tx_buf_len = 0; //Clear since this is sent | |||
| 194 | return test_peer.tx_rc ?: (pos - 1); | |||
| 195 | } | |||
| 196 | ||||
| 197 | int __wrap_poll(struct pollfd *fds, nfds_t nfds, int timeout) | |||
| 198 | { | |||
| 199 | if (!test_peer.poll_fn) | |||
| 200 | return 1; | |||
| 201 | ||||
| 202 | return test_peer.poll_fn(&test_peer, fds, nfds, timeout); | |||
| 203 | } | |||
| 204 | ||||
| 205 | struct mctp_ioc_tag_ctl; | |||
| 206 | ||||
| 207 | #ifdef SIOCMCTPALLOCTAG(0x89E0 + 0) | |||
| 208 | int test_ioctl_tag(int sd, unsigned long req, struct mctp_ioc_tag_ctl *ctl) | |||
| 209 | { | |||
| 210 | shr_assert(sd == test_peer.sd[TEST_PEER_SD_COMMANDS_IDX])((void)((sd == test_peer.sd[(0)]) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 210, "sd == test_peer.sd[TEST_PEER_SD_COMMANDS_IDX]"), 0))); | |||
| 211 | ||||
| 212 | switch (req) { | |||
| 213 | case SIOCMCTPALLOCTAG(0x89E0 + 0): | |||
| 214 | ctl->tag = 1 | MCTP_TAG_PREALLOC0x10 | MCTP_TAG_OWNER0x08; | |||
| 215 | break; | |||
| 216 | case SIOCMCTPDROPTAG(0x89E0 + 1): | |||
| 217 | shr_assert(ctl->tag == (1 | MCTP_TAG_PREALLOC | MCTP_TAG_OWNER))((void)((ctl->tag == (1 | 0x10 | 0x08)) || (shr_assert_fail ("../libnvme/test/mi-mctp.c", 217, "ctl->tag == (1 | MCTP_TAG_PREALLOC | MCTP_TAG_OWNER)" ), 0))); | |||
| 218 | break; | |||
| 219 | }; | |||
| 220 | ||||
| 221 | return 0; | |||
| 222 | } | |||
| 223 | #else | |||
| 224 | int test_ioctl_tag(int sd, unsigned long req, struct mctp_ioc_tag_ctl *ctl) | |||
| 225 | { | |||
| 226 | shr_assert(sd == test_peer.sd[TEST_PEER_SD_COMMANDS_IDX])((void)((sd == test_peer.sd[(0)]) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 226, "sd == test_peer.sd[TEST_PEER_SD_COMMANDS_IDX]"), 0))); | |||
| 227 | return 0; | |||
| 228 | } | |||
| 229 | #endif | |||
| 230 | ||||
| 231 | static struct __mi_mctp_socket_ops ops = { | |||
| 232 | __wrap_msg_socket, | |||
| 233 | __wrap_aem_socket, | |||
| 234 | __wrap_sendmsg, | |||
| 235 | __wrap_recvmsg, | |||
| 236 | __wrap_poll, | |||
| 237 | test_ioctl_tag, | |||
| 238 | }; | |||
| 239 | ||||
| 240 | /* tests */ | |||
| 241 | static void test_rx_err(libnvme_mi_ep_t ep, struct test_peer *peer) | |||
| 242 | { | |||
| 243 | struct nvme_mi_read_nvm_ss_info ss_info; | |||
| 244 | int rc; | |||
| 245 | ||||
| 246 | peer->rx_rc = -1; | |||
| 247 | ||||
| 248 | rc = libnvme_mi_mi_read_mi_data_subsys(ep, &ss_info); | |||
| 249 | shr_assert(rc != 0)((void)((rc != 0) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 249, "rc != 0"), 0))); | |||
| 250 | } | |||
| 251 | ||||
| 252 | static int tx_none(struct test_peer *peer, void *buf, size_t len, int sd) | |||
| 253 | { | |||
| 254 | return 0; | |||
| 255 | } | |||
| 256 | ||||
| 257 | static void test_tx_none(libnvme_mi_ep_t ep, struct test_peer *peer) | |||
| 258 | { | |||
| 259 | struct nvme_mi_read_nvm_ss_info ss_info; | |||
| 260 | int rc; | |||
| 261 | ||||
| 262 | peer->tx_buf_len = 0; | |||
| 263 | peer->tx_fn = tx_none; | |||
| 264 | ||||
| 265 | rc = libnvme_mi_mi_read_mi_data_subsys(ep, &ss_info); | |||
| 266 | shr_assert(rc != 0)((void)((rc != 0) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 266, "rc != 0"), 0))); | |||
| 267 | } | |||
| 268 | ||||
| 269 | static void test_tx_err(libnvme_mi_ep_t ep, struct test_peer *peer) | |||
| 270 | { | |||
| 271 | struct nvme_mi_read_nvm_ss_info ss_info; | |||
| 272 | int rc; | |||
| 273 | ||||
| 274 | peer->tx_rc = -1; | |||
| 275 | ||||
| 276 | rc = libnvme_mi_mi_read_mi_data_subsys(ep, &ss_info); | |||
| 277 | shr_assert(rc != 0)((void)((rc != 0) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 277, "rc != 0"), 0))); | |||
| 278 | } | |||
| 279 | ||||
| 280 | static void test_tx_short(libnvme_mi_ep_t ep, struct test_peer *peer) | |||
| 281 | { | |||
| 282 | struct nvme_mi_read_nvm_ss_info ss_info; | |||
| 283 | int rc; | |||
| 284 | ||||
| 285 | peer->tx_buf_len = 11; | |||
| 286 | ||||
| 287 | rc = libnvme_mi_mi_read_mi_data_subsys(ep, &ss_info); | |||
| 288 | shr_assert(rc != 0)((void)((rc != 0) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 288, "rc != 0"), 0))); | |||
| 289 | } | |||
| 290 | ||||
| 291 | static int poll_fn_err(struct test_peer *peer, struct pollfd *fds, | |||
| 292 | nfds_t nfds, int timeout) | |||
| 293 | { | |||
| 294 | return -1; | |||
| 295 | } | |||
| 296 | ||||
| 297 | static void test_poll_err(libnvme_mi_ep_t ep, struct test_peer *peer) | |||
| 298 | { | |||
| 299 | struct nvme_mi_read_nvm_ss_info ss_info; | |||
| 300 | int rc; | |||
| 301 | ||||
| 302 | peer->poll_fn = poll_fn_err; | |||
| 303 | ||||
| 304 | rc = libnvme_mi_mi_read_mi_data_subsys(ep, &ss_info); | |||
| 305 | shr_assert(rc != 0)((void)((rc != 0) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 305, "rc != 0"), 0))); | |||
| 306 | } | |||
| 307 | ||||
| 308 | static void test_read_mi_data(libnvme_mi_ep_t ep, struct test_peer *peer) | |||
| 309 | { | |||
| 310 | struct nvme_mi_read_nvm_ss_info ss_info; | |||
| 311 | int rc; | |||
| 312 | ||||
| 313 | /* empty response data */ | |||
| 314 | peer->tx_buf_len = 8 + 32; | |||
| 315 | ||||
| 316 | rc = libnvme_mi_mi_read_mi_data_subsys(ep, &ss_info); | |||
| 317 | shr_assert(rc == 0)((void)((rc == 0) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 317, "rc == 0"), 0))); | |||
| 318 | } | |||
| 319 | ||||
| 320 | static void test_mi_resp_err(libnvme_mi_ep_t ep, struct test_peer *peer) | |||
| 321 | { | |||
| 322 | struct nvme_mi_read_nvm_ss_info ss_info; | |||
| 323 | int rc; | |||
| 324 | ||||
| 325 | /* simple error response */ | |||
| 326 | peer->tx_buf[4] = 0x02; /* internal error */ | |||
| 327 | peer->tx_buf_len = 8; | |||
| 328 | ||||
| 329 | rc = libnvme_mi_mi_read_mi_data_subsys(ep, &ss_info); | |||
| 330 | shr_assert(rc == 0x2)((void)((rc == 0x2) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 330, "rc == 0x2"), 0))); | |||
| 331 | } | |||
| 332 | ||||
| 333 | static void setup_unaligned_ctrl_list_resp(struct test_peer *peer) | |||
| 334 | { | |||
| 335 | /* even number of controllers */ | |||
| 336 | peer->tx_buf[8] = 0x02; | |||
| 337 | peer->tx_buf[9] = 0x00; | |||
| 338 | ||||
| 339 | /* controller ID 1 */ | |||
| 340 | peer->tx_buf[10] = 0x01; | |||
| 341 | peer->tx_buf[11] = 0x00; | |||
| 342 | ||||
| 343 | /* controller ID 2 */ | |||
| 344 | peer->tx_buf[12] = 0x02; | |||
| 345 | peer->tx_buf[13] = 0x00; | |||
| 346 | ||||
| 347 | peer->tx_buf_len = 14; | |||
| 348 | } | |||
| 349 | ||||
| 350 | /* Will call through the xfer/submit API expecting a full-sized list (so | |||
| 351 | * resp->data_len is set to sizeof(list)), but the endpoint will return an | |||
| 352 | * unaligned short list. | |||
| 353 | */ | |||
| 354 | static void test_mi_resp_unaligned(libnvme_mi_ep_t ep, struct test_peer *peer) | |||
| 355 | { | |||
| 356 | struct nvme_ctrl_list list; | |||
| 357 | int rc; | |||
| 358 | ||||
| 359 | setup_unaligned_ctrl_list_resp(peer); | |||
| 360 | ||||
| 361 | memset(&list, 0, sizeof(list)); | |||
| 362 | ||||
| 363 | rc = libnvme_mi_mi_read_mi_data_ctrl_list(ep, 0, &list); | |||
| 364 | shr_assert(rc == 0)((void)((rc == 0) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 364, "rc == 0"), 0))); | |||
| 365 | ||||
| 366 | shr_assert(le16_to_cpu(list.num) == 2)((void)((le16_to_cpu(list.num) == 2) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 366, "le16_to_cpu(list.num) == 2"), 0))); | |||
| 367 | shr_assert(le16_to_cpu(list.identifier[0]) == 1)((void)((le16_to_cpu(list.identifier[0]) == 1) || (shr_assert_fail ("../libnvme/test/mi-mctp.c", 367, "le16_to_cpu(list.identifier[0]) == 1" ), 0))); | |||
| 368 | shr_assert(le16_to_cpu(list.identifier[1]) == 2)((void)((le16_to_cpu(list.identifier[1]) == 2) || (shr_assert_fail ("../libnvme/test/mi-mctp.c", 368, "le16_to_cpu(list.identifier[1]) == 2" ), 0))); | |||
| 369 | } | |||
| 370 | ||||
| 371 | /* Will call through the xfer/submit API expecting an unaligned list, | |||
| 372 | * and get a response of exactly that size. | |||
| 373 | */ | |||
| 374 | static void test_mi_resp_unaligned_expected(libnvme_mi_ep_t ep, | |||
| 375 | struct test_peer *peer) | |||
| 376 | { | |||
| 377 | /* direct access to the raw submit() API */ | |||
| 378 | extern int libnvme_mi_submit(libnvme_mi_ep_t ep, struct libnvme_mi_req *req, | |||
| 379 | struct libnvme_mi_resp *resp); | |||
| 380 | struct nvme_mi_mi_resp_hdr resp_hdr; | |||
| 381 | struct nvme_mi_mi_req_hdr req_hdr; | |||
| 382 | struct nvme_ctrl_list list; | |||
| 383 | struct libnvme_mi_resp resp; | |||
| 384 | struct libnvme_mi_req req; | |||
| 385 | int rc; | |||
| 386 | ||||
| 387 | setup_unaligned_ctrl_list_resp(peer); | |||
| 388 | ||||
| 389 | memset(&list, 0, sizeof(list)); | |||
| 390 | ||||
| 391 | memset(&req_hdr, 0, sizeof(req_hdr)); | |||
| 392 | req_hdr.hdr.type = NVME_MI_MSGTYPE_NVME0x84; | |||
| 393 | req_hdr.hdr.nmp = (NVME_MI_ROR_REQ << 7) | (NVME_MI_MT_MI << 3); | |||
| 394 | req_hdr.opcode = nvme_mi_mi_opcode_mi_data_read; | |||
| 395 | req_hdr.cdw0 = cpu_to_le32(nvme_mi_dtyp_ctrl_list << 24); | |||
| 396 | ||||
| 397 | memset(&req, 0, sizeof(req)); | |||
| 398 | req.hdr = &req_hdr.hdr; | |||
| 399 | req.hdr_len = sizeof(req_hdr); | |||
| 400 | ||||
| 401 | memset(&resp, 0, sizeof(resp)); | |||
| 402 | resp.hdr = &resp_hdr.hdr; | |||
| 403 | resp.hdr_len = sizeof(resp_hdr); | |||
| 404 | resp.data = &list; | |||
| 405 | resp.data_len = peer->tx_buf_len; | |||
| 406 | ||||
| 407 | rc = libnvme_mi_submit(ep, &req, &resp); | |||
| 408 | shr_assert(rc == 0)((void)((rc == 0) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 408, "rc == 0"), 0))); | |||
| 409 | shr_assert(resp.data_len == 6)((void)((resp.data_len == 6) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 409, "resp.data_len == 6"), 0))); /* 2-byte length, 2*2 byte controller IDs */ | |||
| 410 | ||||
| 411 | shr_assert(le16_to_cpu(list.num) == 2)((void)((le16_to_cpu(list.num) == 2) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 411, "le16_to_cpu(list.num) == 2"), 0))); | |||
| 412 | shr_assert(le16_to_cpu(list.identifier[0]) == 1)((void)((le16_to_cpu(list.identifier[0]) == 1) || (shr_assert_fail ("../libnvme/test/mi-mctp.c", 412, "le16_to_cpu(list.identifier[0]) == 1" ), 0))); | |||
| 413 | shr_assert(le16_to_cpu(list.identifier[1]) == 2)((void)((le16_to_cpu(list.identifier[1]) == 2) || (shr_assert_fail ("../libnvme/test/mi-mctp.c", 413, "le16_to_cpu(list.identifier[1]) == 2" ), 0))); | |||
| 414 | } | |||
| 415 | ||||
| 416 | static void test_admin_resp_err(libnvme_mi_ep_t ep, struct test_peer *peer) | |||
| 417 | { | |||
| 418 | struct libnvme_transport_handle *hdl; | |||
| 419 | struct libnvme_passthru_cmd cmd; | |||
| 420 | struct nvme_id_ctrl id; | |||
| 421 | int rc; | |||
| 422 | ||||
| 423 | hdl = libnvme_mi_init_transport_handle(ep, 1); | |||
| 424 | shr_assert(hdl)((void)((hdl) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 424, "hdl"), 0))); | |||
| 425 | ||||
| 426 | /* Simple error response, will be shorter than the expected Admin | |||
| 427 | * command response header. */ | |||
| 428 | peer->tx_buf[4] = 0x02; /* internal error */ | |||
| 429 | peer->tx_buf_len = 8; | |||
| 430 | ||||
| 431 | nvme_init_identify_ctrl(&cmd, &id); | |||
| 432 | rc = libnvme_exec_admin_passthru(hdl, &cmd); | |||
| 433 | shr_assert(nvme_status_get_type(rc) == NVME_STATUS_TYPE_MI)((void)((nvme_status_get_type(rc) == NVME_STATUS_TYPE_MI) || ( shr_assert_fail("../libnvme/test/mi-mctp.c", 433, "nvme_status_get_type(rc) == NVME_STATUS_TYPE_MI" ), 0))); | |||
| 434 | shr_assert(nvme_status_get_value(rc) == NVME_MI_RESP_INTERNAL_ERR)((void)((nvme_status_get_value(rc) == NVME_MI_RESP_INTERNAL_ERR ) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 434, "nvme_status_get_value(rc) == NVME_MI_RESP_INTERNAL_ERR" ), 0))); | |||
| 435 | } | |||
| 436 | ||||
| 437 | /* test: all 4-byte aligned response sizes - should be decoded into the | |||
| 438 | * response status value. We use an admin command here as the header size will | |||
| 439 | * be larger than the minimum header size (it contains the completion | |||
| 440 | * doublewords), and we need to ensure that an error response is correctly | |||
| 441 | * interpreted, including having the MIC extracted from the message. | |||
| 442 | */ | |||
| 443 | static void test_admin_resp_sizes(libnvme_mi_ep_t ep, struct test_peer *peer) | |||
| 444 | { | |||
| 445 | struct libnvme_transport_handle *hdl; | |||
| 446 | struct libnvme_passthru_cmd cmd; | |||
| 447 | struct nvme_id_ctrl id; | |||
| 448 | unsigned int i; | |||
| 449 | int rc; | |||
| 450 | ||||
| 451 | hdl = libnvme_mi_init_transport_handle(ep, 1); | |||
| 452 | shr_assert(hdl)((void)((hdl) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 452, "hdl"), 0))); | |||
| 453 | ||||
| 454 | peer->tx_buf[4] = 0x02; /* internal error */ | |||
| 455 | ||||
| 456 | for (i = 8; i <= 4096 + 8; i+=4) { | |||
| 457 | peer->tx_buf_len = i; | |||
| 458 | nvme_init_identify_ctrl(&cmd, &id); | |||
| 459 | rc = libnvme_exec_admin_passthru(hdl, &cmd); | |||
| 460 | shr_assert(nvme_status_get_type(rc) == NVME_STATUS_TYPE_MI)((void)((nvme_status_get_type(rc) == NVME_STATUS_TYPE_MI) || ( shr_assert_fail("../libnvme/test/mi-mctp.c", 460, "nvme_status_get_type(rc) == NVME_STATUS_TYPE_MI" ), 0))); | |||
| 461 | shr_assert(nvme_status_get_value(rc) == NVME_MI_RESP_INTERNAL_ERR)((void)((nvme_status_get_value(rc) == NVME_MI_RESP_INTERNAL_ERR ) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 461, "nvme_status_get_value(rc) == NVME_MI_RESP_INTERNAL_ERR" ), 0))); | |||
| 462 | } | |||
| 463 | ||||
| 464 | libnvme_close(hdl); | |||
| 465 | } | |||
| 466 | ||||
| 467 | /* test: timeout value passed to poll */ | |||
| 468 | static int poll_fn_timeout_value(struct test_peer *peer, struct pollfd *fds, | |||
| 469 | nfds_t nfds, int timeout) | |||
| 470 | { | |||
| 471 | shr_assert(timeout == 3141)((void)((timeout == 3141) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 471, "timeout == 3141"), 0))); | |||
| 472 | return 1; | |||
| 473 | } | |||
| 474 | ||||
| 475 | static void test_poll_timeout_value(libnvme_mi_ep_t ep, struct test_peer *peer) | |||
| 476 | { | |||
| 477 | struct nvme_mi_read_nvm_ss_info ss_info; | |||
| 478 | int rc; | |||
| 479 | ||||
| 480 | /* empty response data */ | |||
| 481 | peer->tx_buf_len = 8 + 32; | |||
| 482 | ||||
| 483 | peer->poll_fn = poll_fn_timeout_value; | |||
| 484 | libnvme_mi_ep_set_timeout(ep, 3141); | |||
| 485 | ||||
| 486 | rc = libnvme_mi_mi_read_mi_data_subsys(ep, &ss_info); | |||
| 487 | shr_assert(rc == 0)((void)((rc == 0) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 487, "rc == 0"), 0))); | |||
| 488 | } | |||
| 489 | ||||
| 490 | /* test: poll timeout expiry */ | |||
| 491 | static int poll_fn_timeout(struct test_peer *peer, struct pollfd *fds, | |||
| 492 | nfds_t nfds, int timeout) | |||
| 493 | { | |||
| 494 | return 0; | |||
| 495 | } | |||
| 496 | ||||
| 497 | static void test_poll_timeout(libnvme_mi_ep_t ep, struct test_peer *peer) | |||
| 498 | { | |||
| 499 | struct nvme_mi_read_nvm_ss_info ss_info; | |||
| 500 | int rc; | |||
| 501 | ||||
| 502 | peer->poll_fn = poll_fn_timeout; | |||
| 503 | ||||
| 504 | rc = libnvme_mi_mi_read_mi_data_subsys(ep, &ss_info); | |||
| 505 | shr_assert(rc != 0)((void)((rc != 0) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 505, "rc != 0"), 0))); | |||
| 506 | shr_assert(errno == ETIMEDOUT)((void)(((*__errno_location ()) == 110) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 506, "errno == ETIMEDOUT"), 0))); | |||
| 507 | } | |||
| 508 | ||||
| 509 | /* test: send a More Processing Required response, then the actual response */ | |||
| 510 | struct mpr_tx_info { | |||
| 511 | int msg_no; | |||
| 512 | bool_Bool admin_quirk; | |||
| 513 | size_t final_len; | |||
| 514 | }; | |||
| 515 | ||||
| 516 | static int tx_mpr(struct test_peer *peer, void *buf, size_t len, int sd) | |||
| 517 | { | |||
| 518 | struct mpr_tx_info *tx_info = peer->tx_data; | |||
| 519 | ||||
| 520 | shr_assert(sd == peer->sd[TEST_PEER_SD_COMMANDS_IDX])((void)((sd == peer->sd[(0)]) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 520, "sd == peer->sd[TEST_PEER_SD_COMMANDS_IDX]"), 0))); | |||
| 521 | ||||
| 522 | memset(peer->tx_buf, 0, sizeof(peer->tx_buf)); | |||
| 523 | peer->tx_buf[0] = NVME_MI_MSGTYPE_NVME0x84; | |||
| 524 | peer->tx_buf[1] = test_peer.rx_buf[1] | (NVME_MI_ROR_RSP << 7); | |||
| 525 | ||||
| 526 | switch (tx_info->msg_no) { | |||
| 527 | case 1: | |||
| 528 | peer->tx_buf[4] = NVME_MI_RESP_MPR; | |||
| 529 | peer->tx_buf_len = 8; | |||
| 530 | if (tx_info->admin_quirk) { | |||
| 531 | peer->tx_buf_len = 20; | |||
| 532 | } | |||
| 533 | break; | |||
| 534 | case 2: | |||
| 535 | peer->tx_buf[4] = NVME_MI_RESP_SUCCESS; | |||
| 536 | peer->tx_buf_len = tx_info->final_len; | |||
| 537 | break; | |||
| 538 | default: | |||
| 539 | shr_assert(0)((void)((0) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 539 , "0"), 0))); | |||
| 540 | } | |||
| 541 | ||||
| 542 | test_set_tx_mic(peer); | |||
| 543 | ||||
| 544 | tx_info->msg_no++; | |||
| 545 | ||||
| 546 | return 0; | |||
| 547 | } | |||
| 548 | ||||
| 549 | static void test_mpr_mi(libnvme_mi_ep_t ep, struct test_peer *peer) | |||
| 550 | { | |||
| 551 | struct nvme_mi_read_nvm_ss_info ss_info; | |||
| 552 | struct mpr_tx_info tx_info; | |||
| 553 | int rc; | |||
| 554 | ||||
| 555 | tx_info.msg_no = 1; | |||
| 556 | tx_info.final_len = sizeof(struct nvme_mi_mi_resp_hdr) + sizeof(ss_info); | |||
| 557 | tx_info.admin_quirk = false0; | |||
| 558 | ||||
| 559 | peer->tx_fn = tx_mpr; | |||
| 560 | peer->tx_data = &tx_info; | |||
| 561 | ||||
| 562 | rc = libnvme_mi_mi_read_mi_data_subsys(ep, &ss_info); | |||
| 563 | shr_assert(rc == 0)((void)((rc == 0) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 563, "rc == 0"), 0))); | |||
| 564 | } | |||
| 565 | ||||
| 566 | static void test_mpr_admin(libnvme_mi_ep_t ep, struct test_peer *peer) | |||
| 567 | { | |||
| 568 | struct libnvme_transport_handle *hdl; | |||
| 569 | struct libnvme_passthru_cmd cmd; | |||
| 570 | struct mpr_tx_info tx_info; | |||
| 571 | struct nvme_id_ctrl id; | |||
| 572 | int rc; | |||
| 573 | ||||
| 574 | tx_info.msg_no = 1; | |||
| 575 | tx_info.final_len = sizeof(struct nvme_mi_admin_resp_hdr) + sizeof(id); | |||
| 576 | tx_info.admin_quirk = false0; | |||
| 577 | ||||
| 578 | peer->tx_fn = tx_mpr; | |||
| 579 | peer->tx_data = &tx_info; | |||
| 580 | ||||
| 581 | hdl = libnvme_mi_init_transport_handle(ep, 1); | |||
| 582 | ||||
| 583 | nvme_init_identify_ctrl(&cmd, &id); | |||
| 584 | rc = libnvme_exec_admin_passthru(hdl, &cmd); | |||
| 585 | shr_assert(rc == 0)((void)((rc == 0) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 585, "rc == 0"), 0))); | |||
| 586 | ||||
| 587 | libnvme_close(hdl); | |||
| 588 | } | |||
| 589 | ||||
| 590 | /* We have seen drives that send a MPR response as a full Admin message, | |||
| 591 | * rather than a MI message; these have a larger message body | |||
| 592 | */ | |||
| 593 | static void test_mpr_admin_quirked(libnvme_mi_ep_t ep, struct test_peer *peer) | |||
| 594 | { | |||
| 595 | struct libnvme_transport_handle *hdl; | |||
| 596 | struct libnvme_passthru_cmd cmd; | |||
| 597 | struct mpr_tx_info tx_info; | |||
| 598 | struct nvme_id_ctrl id; | |||
| 599 | int rc; | |||
| 600 | ||||
| 601 | tx_info.msg_no = 1; | |||
| 602 | tx_info.final_len = sizeof(struct nvme_mi_admin_resp_hdr) + sizeof(id); | |||
| 603 | tx_info.admin_quirk = true1; | |||
| 604 | ||||
| 605 | peer->tx_fn = tx_mpr; | |||
| 606 | peer->tx_data = &tx_info; | |||
| 607 | ||||
| 608 | hdl = libnvme_mi_init_transport_handle(ep, 1); | |||
| 609 | ||||
| 610 | nvme_init_identify_ctrl(&cmd, &id); | |||
| 611 | rc = libnvme_exec_admin_passthru(hdl, &cmd); | |||
| 612 | shr_assert(rc == 0)((void)((rc == 0) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 612, "rc == 0"), 0))); | |||
| 613 | ||||
| 614 | libnvme_close(hdl); | |||
| 615 | } | |||
| 616 | ||||
| 617 | /* helpers for the MPR + poll tests */ | |||
| 618 | struct mpr_poll_info { | |||
| 619 | int poll_no; | |||
| 620 | uint16_t mprt; | |||
| 621 | unsigned int timeouts[2]; | |||
| 622 | }; | |||
| 623 | ||||
| 624 | static int poll_fn_mpr_poll(struct test_peer *peer, struct pollfd *fds, | |||
| 625 | nfds_t nfds, int timeout) | |||
| 626 | { | |||
| 627 | struct mpr_poll_info *info = peer->poll_data; | |||
| 628 | ||||
| 629 | switch (info->poll_no) { | |||
| 630 | case 1: | |||
| 631 | case 2: | |||
| 632 | shr_assert(timeout == info->timeouts[info->poll_no - 1])((void)((timeout == info->timeouts[info->poll_no - 1]) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 632, "timeout == info->timeouts[info->poll_no - 1]" ), 0))); | |||
| 633 | break; | |||
| 634 | default: | |||
| 635 | shr_assert(0)((void)((0) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 635 , "0"), 0))); | |||
| 636 | } | |||
| 637 | ||||
| 638 | info->poll_no++; | |||
| 639 | return 1; | |||
| 640 | } | |||
| 641 | ||||
| 642 | static int tx_fn_mpr_poll(struct test_peer *peer, void *buf, size_t len, int sd) | |||
| 643 | { | |||
| 644 | struct mpr_tx_info *tx_info = peer->tx_data; | |||
| 645 | struct mpr_poll_info *poll_info = peer->poll_data; | |||
| 646 | unsigned int mprt; | |||
| 647 | ||||
| 648 | shr_assert(sd == peer->sd[TEST_PEER_SD_COMMANDS_IDX])((void)((sd == peer->sd[(0)]) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 648, "sd == peer->sd[TEST_PEER_SD_COMMANDS_IDX]"), 0))); | |||
| 649 | ||||
| 650 | memset(peer->tx_buf, 0, sizeof(peer->tx_buf)); | |||
| 651 | peer->tx_buf[0] = NVME_MI_MSGTYPE_NVME0x84; | |||
| 652 | peer->tx_buf[1] = test_peer.rx_buf[1] | (NVME_MI_ROR_RSP << 7); | |||
| 653 | ||||
| 654 | switch (tx_info->msg_no) { | |||
| 655 | case 1: | |||
| 656 | peer->tx_buf[4] = NVME_MI_RESP_MPR; | |||
| 657 | peer->tx_buf_len = 8; | |||
| 658 | mprt = poll_info->mprt; | |||
| 659 | peer->tx_buf[7] = mprt >> 8; | |||
| 660 | peer->tx_buf[6] = mprt & 0xff; | |||
| 661 | break; | |||
| 662 | case 2: | |||
| 663 | peer->tx_buf[4] = NVME_MI_RESP_SUCCESS; | |||
| 664 | peer->tx_buf_len = tx_info->final_len; | |||
| 665 | break; | |||
| 666 | default: | |||
| 667 | shr_assert(0)((void)((0) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 667 , "0"), 0))); | |||
| 668 | } | |||
| 669 | ||||
| 670 | test_set_tx_mic(peer); | |||
| 671 | ||||
| 672 | tx_info->msg_no++; | |||
| 673 | ||||
| 674 | return 0; | |||
| 675 | } | |||
| 676 | ||||
| 677 | /* test: correct timeout value used from MPR response */ | |||
| 678 | static void test_mpr_timeouts(libnvme_mi_ep_t ep, struct test_peer *peer) | |||
| 679 | { | |||
| 680 | struct nvme_mi_read_nvm_ss_info ss_info; | |||
| 681 | struct mpr_poll_info poll_info; | |||
| 682 | struct mpr_tx_info tx_info; | |||
| 683 | int rc; | |||
| 684 | ||||
| 685 | libnvme_mi_ep_set_timeout(ep, 3141); | |||
| 686 | ||||
| 687 | tx_info.msg_no = 1; | |||
| 688 | tx_info.final_len = sizeof(struct nvme_mi_mi_resp_hdr) + sizeof(ss_info); | |||
| 689 | ||||
| 690 | poll_info.poll_no = 1; | |||
| 691 | poll_info.mprt = 1234; | |||
| 692 | poll_info.timeouts[0] = 3141; | |||
| 693 | poll_info.timeouts[1] = 1234 * 100; | |||
| 694 | ||||
| 695 | peer->tx_fn = tx_fn_mpr_poll; | |||
| 696 | peer->tx_data = &tx_info; | |||
| 697 | ||||
| 698 | peer->poll_fn = poll_fn_mpr_poll; | |||
| 699 | peer->poll_data = &poll_info; | |||
| 700 | ||||
| 701 | rc = libnvme_mi_mi_read_mi_data_subsys(ep, &ss_info); | |||
| 702 | shr_assert(rc == 0)((void)((rc == 0) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 702, "rc == 0"), 0))); | |||
| 703 | } | |||
| 704 | ||||
| 705 | /* test: MPR value is limited to the max mpr */ | |||
| 706 | static void test_mpr_timeout_clamp(libnvme_mi_ep_t ep, struct test_peer *peer) | |||
| 707 | { | |||
| 708 | struct nvme_mi_read_nvm_ss_info ss_info; | |||
| 709 | struct mpr_poll_info poll_info; | |||
| 710 | struct mpr_tx_info tx_info; | |||
| 711 | int rc; | |||
| 712 | ||||
| 713 | libnvme_mi_ep_set_timeout(ep, 3141); | |||
| 714 | libnvme_mi_ep_set_mprt_max(ep, 123400); | |||
| 715 | ||||
| 716 | tx_info.msg_no = 1; | |||
| 717 | tx_info.final_len = sizeof(struct nvme_mi_mi_resp_hdr) + sizeof(ss_info); | |||
| 718 | ||||
| 719 | poll_info.poll_no = 1; | |||
| 720 | poll_info.mprt = 1235; | |||
| 721 | poll_info.timeouts[0] = 3141; | |||
| 722 | poll_info.timeouts[1] = 1234 * 100; | |||
| 723 | ||||
| 724 | peer->tx_fn = tx_fn_mpr_poll; | |||
| 725 | peer->tx_data = &tx_info; | |||
| 726 | ||||
| 727 | peer->poll_fn = poll_fn_mpr_poll; | |||
| 728 | peer->poll_data = &poll_info; | |||
| 729 | ||||
| 730 | rc = libnvme_mi_mi_read_mi_data_subsys(ep, &ss_info); | |||
| 731 | shr_assert(rc == 0)((void)((rc == 0) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 731, "rc == 0"), 0))); | |||
| 732 | } | |||
| 733 | ||||
| 734 | /* test: MPR value of zero doesn't result in poll with zero timeout */ | |||
| 735 | static void test_mpr_mprt_zero(libnvme_mi_ep_t ep, struct test_peer *peer) | |||
| 736 | { | |||
| 737 | struct nvme_mi_read_nvm_ss_info ss_info; | |||
| 738 | struct mpr_poll_info poll_info; | |||
| 739 | struct mpr_tx_info tx_info; | |||
| 740 | int rc; | |||
| 741 | ||||
| 742 | libnvme_mi_ep_set_timeout(ep, 3141); | |||
| 743 | libnvme_mi_ep_set_mprt_max(ep, 123400); | |||
| 744 | ||||
| 745 | tx_info.msg_no = 1; | |||
| 746 | tx_info.final_len = sizeof(struct nvme_mi_mi_resp_hdr) + sizeof(ss_info); | |||
| 747 | ||||
| 748 | poll_info.poll_no = 1; | |||
| 749 | poll_info.mprt = 0; | |||
| 750 | poll_info.timeouts[0] = 3141; | |||
| 751 | poll_info.timeouts[1] = 3141; | |||
| 752 | ||||
| 753 | peer->tx_fn = tx_fn_mpr_poll; | |||
| 754 | peer->tx_data = &tx_info; | |||
| 755 | ||||
| 756 | peer->poll_fn = poll_fn_mpr_poll; | |||
| 757 | peer->poll_data = &poll_info; | |||
| 758 | ||||
| 759 | rc = libnvme_mi_mi_read_mi_data_subsys(ep, &ss_info); | |||
| 760 | shr_assert(rc == 0)((void)((rc == 0) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 760, "rc == 0"), 0))); | |||
| 761 | } | |||
| 762 | ||||
| 763 | enum aem_enable_state { | |||
| 764 | AEM_ES_GET_ENABLED, | |||
| 765 | AEM_ES_SET_TO_DISABLED, | |||
| 766 | AEM_ES_ENABLE_SET_ENABLED, | |||
| 767 | AEM_ES_PROCESS, | |||
| 768 | AEM_ES_ACK_RESPONSE, | |||
| 769 | AEM_ES_ACK_RECEIVED | |||
| 770 | }; | |||
| 771 | ||||
| 772 | enum aem_failure_condition { | |||
| 773 | AEM_FC_NONE, | |||
| 774 | AEM_FC_BAD_GET_CONFIG_HEADER_LEN, | |||
| 775 | AEM_FC_BAD_GET_CONFIG_TOTAL_LEN, | |||
| 776 | AEM_FC_BAD_GET_CONFIG_BUFFER_LEN, | |||
| 777 | AEM_FC_BAD_OCC_RSP_HDR_LEN_SYNC, | |||
| 778 | AEM_FC_BAD_OCC_RSP_TOTAL_LEN_SYNC, | |||
| 779 | AEM_FC_BAD_OCC_RSP_BUFFER_LEN_SYNC, | |||
| 780 | AEM_FC_BAD_OCC_RSP_HDR_LEN_AEM, | |||
| 781 | AEM_FC_BAD_OCC_RSP_TOTAL_LEN_AEM, | |||
| 782 | AEM_FC_BAD_OCC_RSP_BUFFER_LEN_AEM, | |||
| 783 | }; | |||
| 784 | ||||
| 785 | struct aem_rcv_enable_fn_data { | |||
| 786 | enum aem_enable_state state; | |||
| 787 | enum aem_failure_condition fc; | |||
| 788 | struct libnvme_mi_aem_enabled_map ep_enabled_map; | |||
| 789 | struct libnvme_mi_aem_enabled_map host_enabled_map; | |||
| 790 | struct libnvme_mi_aem_enabled_map aem_during_process_map; | |||
| 791 | struct libnvme_mi_aem_enabled_map ack_events_map; | |||
| 792 | struct libnvme_mi_event *events[256]; | |||
| 793 | int callback_count; | |||
| 794 | }; | |||
| 795 | ||||
| 796 | static void populate_tx_occ_list(bool_Bool aem_not_ack, | |||
| 797 | struct aem_rcv_enable_fn_data *fn_data, struct libnvme_mi_aem_enabled_map *to_send) | |||
| 798 | { | |||
| 799 | struct nvme_mi_mi_resp_hdr *resp_hdr = | |||
| 800 | (struct nvme_mi_mi_resp_hdr *)test_peer.tx_buf; | |||
| 801 | ||||
| 802 | struct nvme_mi_msg_hdr *mi_msg_hdr = | |||
| 803 | (struct nvme_mi_msg_hdr *)test_peer.tx_buf; | |||
| 804 | ||||
| 805 | size_t hdr_len = sizeof(*resp_hdr); | |||
| 806 | ||||
| 807 | struct nvme_mi_aem_occ_list_hdr *list_hdr = | |||
| 808 | (struct nvme_mi_aem_occ_list_hdr *)(resp_hdr+1); | |||
| 809 | ||||
| 810 | //For AEM, the data is actually in request format | |||
| 811 | //since it originates from the endpoint | |||
| 812 | if (aem_not_ack) { | |||
| 813 | list_hdr = (struct nvme_mi_aem_occ_list_hdr *)(mi_msg_hdr+1); | |||
| 814 | hdr_len = sizeof(*mi_msg_hdr); | |||
| 815 | mi_msg_hdr->nmp = (NVME_MI_MT_AE << 3); | |||
| 816 | } else { | |||
| 817 | resp_hdr->status = 0; | |||
| 818 | } | |||
| 819 | ||||
| 820 | list_hdr->aelver = 0; | |||
| 821 | list_hdr->aeolhl = sizeof(*list_hdr); | |||
| 822 | list_hdr->numaeo = 0; | |||
| 823 | __u32 aeoltl = list_hdr->aeolhl; | |||
| 824 | ||||
| 825 | struct nvme_mi_aem_occ_data *data = | |||
| 826 | (struct nvme_mi_aem_occ_data *)(list_hdr+1); | |||
| 827 | ||||
| 828 | for (int i = 0; i < 255; i++) { | |||
| 829 | if (fn_data->events[i] && to_send->enabled[i]) { | |||
| 830 | struct libnvme_mi_event *event = fn_data->events[i]; | |||
| 831 | ||||
| 832 | list_hdr->numaeo++; | |||
| 833 | aeoltl += sizeof(struct nvme_mi_aem_occ_data); | |||
| 834 | aeoltl += event->spec_info_len + | |||
| 835 | event->vend_spec_info_len; | |||
| 836 | ||||
| 837 | data->aelhlen = sizeof(*data); | |||
| 838 | ||||
| 839 | if ((fn_data->fc == AEM_FC_BAD_OCC_RSP_HDR_LEN_SYNC && !aem_not_ack) || | |||
| 840 | (fn_data->fc == AEM_FC_BAD_OCC_RSP_HDR_LEN_AEM && aem_not_ack)) | |||
| 841 | data->aelhlen--; | |||
| 842 | ||||
| 843 | data->aeoui.aeocidi = event->aeocidi; | |||
| 844 | data->aeoui.aeoi = event->aeoi; | |||
| 845 | data->aeoui.aessi = event->aessi; | |||
| 846 | data->aeosil = event->spec_info_len; | |||
| 847 | data->aeovsil = event->vend_spec_info_len; | |||
| 848 | ||||
| 849 | if ((fn_data->fc == AEM_FC_BAD_OCC_RSP_TOTAL_LEN_SYNC && | |||
| 850 | !aem_not_ack) || | |||
| 851 | (fn_data->fc == AEM_FC_BAD_OCC_RSP_TOTAL_LEN_AEM && | |||
| 852 | aem_not_ack)) | |||
| 853 | aeoltl -= 1; | |||
| 854 | ||||
| 855 | //Now the data | |||
| 856 | uint8_t *spec = (uint8_t *)(data+1); | |||
| 857 | ||||
| 858 | if (data->aeosil) { | |||
| 859 | memcpy(spec, event->spec_info, event->spec_info_len); | |||
| 860 | spec += event->spec_info_len; | |||
| 861 | } | |||
| 862 | ||||
| 863 | if (data->aeovsil) { | |||
| 864 | memcpy(spec, event->vend_spec_info, event->vend_spec_info_len); | |||
| 865 | spec += event->vend_spec_info_len; | |||
| 866 | } | |||
| 867 | ||||
| 868 | data = (struct nvme_mi_aem_occ_data *)(spec); | |||
| 869 | } | |||
| 870 | } | |||
| 871 | ||||
| 872 | nvme_mi_aem_aeolli_set_aeoltl(list_hdr, aeoltl); | |||
| 873 | test_peer.tx_buf_len = hdr_len + aeoltl; | |||
| 874 | ||||
| 875 | if ((fn_data->fc == AEM_FC_BAD_OCC_RSP_BUFFER_LEN_SYNC && !aem_not_ack) || | |||
| 876 | (fn_data->fc == AEM_FC_BAD_OCC_RSP_BUFFER_LEN_AEM && aem_not_ack)) | |||
| 877 | test_peer.tx_buf_len--; | |||
| 878 | ||||
| 879 | test_set_tx_mic(&test_peer); | |||
| 880 | } | |||
| 881 | ||||
| 882 | static void check_aem_sync_message(struct libnvme_mi_aem_enabled_map *expected_mask, | |||
| 883 | struct libnvme_mi_aem_enabled_map *expected_state, | |||
| 884 | struct aem_rcv_enable_fn_data *fn_data) | |||
| 885 | { | |||
| 886 | //Check the RX buffer for the endpoint. We should be getting a CONFIG SET AEM | |||
| 887 | //with all enabled items disabled | |||
| 888 | struct nvme_mi_mi_req_hdr *req = | |||
| 889 | (struct nvme_mi_mi_req_hdr *)test_peer.rx_buf; | |||
| 890 | ||||
| 891 | struct nvme_mi_aem_supported_list *list = | |||
| 892 | (struct nvme_mi_aem_supported_list *)(req+1); | |||
| 893 | ||||
| 894 | shr_assert(req->opcode == nvme_mi_mi_opcode_configuration_set)((void)((req->opcode == nvme_mi_mi_opcode_configuration_set ) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 894, "req->opcode == nvme_mi_mi_opcode_configuration_set" ), 0))); | |||
| 895 | shr_assert((le32_to_cpu(req->cdw0) & 0xFF) == NVME_MI_CONFIG_AE)((void)(((le32_to_cpu(req->cdw0) & 0xFF) == NVME_MI_CONFIG_AE ) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 895, "(le32_to_cpu(req->cdw0) & 0xFF) == NVME_MI_CONFIG_AE" ), 0))); | |||
| 896 | shr_assert(list->hdr.aeslver == 0)((void)((list->hdr.aeslver == 0) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 896, "list->hdr.aeslver == 0"), 0))); | |||
| 897 | ||||
| 898 | int count = 0; | |||
| 899 | //Count how many events we want to act are in the expected state | |||
| 900 | for (int i = 0; i < 256; i++) { | |||
| 901 | if (expected_mask->enabled[i]) | |||
| 902 | count++; | |||
| 903 | } | |||
| 904 | ||||
| 905 | shr_assert(list->hdr.numaes == count)((void)((list->hdr.numaes == count) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 905, "list->hdr.numaes == count"), 0))); | |||
| 906 | shr_assert(list->hdr.aeslhl == sizeof(struct nvme_mi_aem_supported_list))((void)((list->hdr.aeslhl == sizeof(struct nvme_mi_aem_supported_list )) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 906, "list->hdr.aeslhl == sizeof(struct nvme_mi_aem_supported_list)" ), 0))); | |||
| 907 | shr_assert(list->hdr.aest == list->hdr.aeslhl +((void)((list->hdr.aest == list->hdr.aeslhl + count * sizeof (struct nvme_mi_aem_supported_item)) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 908, "list->hdr.aest == list->hdr.aeslhl + count * sizeof(struct nvme_mi_aem_supported_item)" ), 0))) | |||
| 908 | count * sizeof(struct nvme_mi_aem_supported_item))((void)((list->hdr.aest == list->hdr.aeslhl + count * sizeof (struct nvme_mi_aem_supported_item)) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 908, "list->hdr.aest == list->hdr.aeslhl + count * sizeof(struct nvme_mi_aem_supported_item)" ), 0))); | |||
| 909 | ||||
| 910 | struct nvme_mi_aem_supported_item *item = | |||
| 911 | (struct nvme_mi_aem_supported_item *)(list+1); | |||
| 912 | ||||
| 913 | //Check the items | |||
| 914 | for (int i = 0; i < 256; i++) { | |||
| 915 | if (expected_mask->enabled[i]) { | |||
| 916 | bool_Bool found = false0; | |||
| 917 | ||||
| 918 | for (int j = 0; j < count; j++) { | |||
| 919 | if (nvme_mi_aem_aesi_get_aesid(item[j].aesi) == i && | |||
| 920 | nvme_mi_aem_aesi_get_aese(item[j].aesi) == | |||
| 921 | expected_state->enabled[i]) { | |||
| 922 | found = true1; | |||
| 923 | break; | |||
| 924 | } | |||
| 925 | } | |||
| 926 | shr_assert(found)((void)((found) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 926, "found"), 0))); | |||
| 927 | } | |||
| 928 | } | |||
| 929 | } | |||
| 930 | ||||
| 931 | static int aem_rcv_enable_fn(struct test_peer *peer, void *buf, size_t len, int sd) | |||
| 932 | { | |||
| 933 | struct aem_rcv_enable_fn_data *fn_data = peer->tx_data; | |||
| 934 | struct nvme_mi_mi_resp_hdr *tx_hdr = (struct nvme_mi_mi_resp_hdr *)peer->tx_buf; | |||
| 935 | ||||
| 936 | /* set up a few default response fields; caller may have | |||
| 937 | * initialised the rest of the response | |||
| 938 | */ | |||
| 939 | test_peer.tx_buf[0] = NVME_MI_MSGTYPE_NVME0x84; | |||
| 940 | test_peer.tx_buf[1] = test_peer.rx_buf[1] | (NVME_MI_ROR_RSP << 7); | |||
| 941 | tx_hdr->status = 0; | |||
| 942 | ||||
| 943 | switch (fn_data->state) { | |||
| 944 | case AEM_ES_GET_ENABLED: | |||
| 945 | { | |||
| 946 | shr_assert(sd == peer->sd[TEST_PEER_SD_COMMANDS_IDX])((void)((sd == peer->sd[(0)]) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 946, "sd == peer->sd[TEST_PEER_SD_COMMANDS_IDX]"), 0))); | |||
| 947 | ||||
| 948 | //First, we want to return some data about what is already enabled | |||
| 949 | struct nvme_mi_aem_supported_list_header *list_hdr = | |||
| 950 | (struct nvme_mi_aem_supported_list_header *)(tx_hdr+1); | |||
| 951 | ||||
| 952 | if (fn_data->fc == AEM_FC_BAD_GET_CONFIG_HEADER_LEN) | |||
| 953 | list_hdr->aeslhl = | |||
| 954 | sizeof(struct nvme_mi_aem_supported_list_header) - 1; | |||
| 955 | else | |||
| 956 | list_hdr->aeslhl = | |||
| 957 | sizeof(struct nvme_mi_aem_supported_list_header); | |||
| 958 | ||||
| 959 | list_hdr->aeslver = 0; | |||
| 960 | struct nvme_mi_aem_supported_item *item = | |||
| 961 | (struct nvme_mi_aem_supported_item *)(list_hdr+1); | |||
| 962 | int item_count = 0; | |||
| 963 | ||||
| 964 | list_hdr->numaes = 0; | |||
| 965 | //Count how many events we want to act are enabled | |||
| 966 | for (int i = 0; i < 256; i++) { | |||
| 967 | if (fn_data->ep_enabled_map.enabled[i]) { | |||
| 968 | list_hdr->numaes++; | |||
| 969 | nvme_mi_aem_aesi_set_aesid(&item[item_count], i); | |||
| 970 | nvme_mi_aem_aesi_set_aee(&item[item_count], 1); | |||
| 971 | item[item_count].aesl = | |||
| 972 | sizeof(struct nvme_mi_aem_supported_item); | |||
| 973 | item_count++; | |||
| 974 | } | |||
| 975 | } | |||
| 976 | ||||
| 977 | list_hdr->aest = list_hdr->aeslhl + | |||
| 978 | list_hdr->numaes * sizeof(struct nvme_mi_aem_supported_item); | |||
| 979 | if (fn_data->fc == AEM_FC_BAD_GET_CONFIG_TOTAL_LEN) | |||
| 980 | list_hdr->aest--;//Shrink | |||
| 981 | ||||
| 982 | test_peer.tx_buf_len = | |||
| 983 | sizeof(struct nvme_mi_mi_resp_hdr) + list_hdr->aest; | |||
| 984 | if (fn_data->fc == AEM_FC_BAD_GET_CONFIG_BUFFER_LEN) | |||
| 985 | test_peer.tx_buf_len--; | |||
| 986 | ||||
| 987 | test_set_tx_mic(&test_peer); | |||
| 988 | ||||
| 989 | fn_data->state = AEM_ES_SET_TO_DISABLED; | |||
| 990 | break; | |||
| 991 | } | |||
| 992 | case AEM_ES_SET_TO_DISABLED: | |||
| 993 | { | |||
| 994 | shr_assert(sd == peer->sd[TEST_PEER_SD_COMMANDS_IDX])((void)((sd == peer->sd[(0)]) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 994, "sd == peer->sd[TEST_PEER_SD_COMMANDS_IDX]"), 0))); | |||
| 995 | ||||
| 996 | struct libnvme_mi_aem_enabled_map expected = {false0}; | |||
| 997 | //The items in the ep_enabled_map should get disabled | |||
| 998 | check_aem_sync_message(&fn_data->ep_enabled_map, &expected, fn_data); | |||
| 999 | ||||
| 1000 | //Need to queue a reasonable response with no OCC | |||
| 1001 | struct nvme_mi_mi_resp_hdr *tx_hdr = | |||
| 1002 | (struct nvme_mi_mi_resp_hdr *)test_peer.tx_buf; | |||
| 1003 | struct nvme_mi_aem_occ_list_hdr *list_hdr = | |||
| 1004 | (struct nvme_mi_aem_occ_list_hdr *)(tx_hdr+1); | |||
| 1005 | ||||
| 1006 | list_hdr->aelver = 0; | |||
| 1007 | list_hdr->aeolhl = sizeof(*list_hdr); | |||
| 1008 | list_hdr->numaeo = 0; | |||
| 1009 | nvme_mi_aem_aeolli_set_aeoltl(list_hdr, list_hdr->aeolhl); | |||
| 1010 | ||||
| 1011 | test_peer.tx_buf_len = sizeof(struct nvme_mi_mi_resp_hdr) + | |||
| 1012 | nvme_mi_aem_aeolli_get_aeoltl(list_hdr->aeolli); | |||
| 1013 | ||||
| 1014 | test_set_tx_mic(&test_peer); | |||
| 1015 | ||||
| 1016 | fn_data->state = AEM_ES_ENABLE_SET_ENABLED; | |||
| 1017 | break; | |||
| 1018 | } | |||
| 1019 | case AEM_ES_ENABLE_SET_ENABLED: | |||
| 1020 | shr_assert(sd == peer->sd[TEST_PEER_SD_COMMANDS_IDX])((void)((sd == peer->sd[(0)]) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 1020, "sd == peer->sd[TEST_PEER_SD_COMMANDS_IDX]"), 0))); | |||
| 1021 | ||||
| 1022 | //We should verify the right things are enabled | |||
| 1023 | //The items in the host enable map should get enabled | |||
| 1024 | check_aem_sync_message(&fn_data->host_enabled_map, | |||
| 1025 | &fn_data->host_enabled_map, fn_data); | |||
| 1026 | ||||
| 1027 | //Prepare an OCC list response | |||
| 1028 | populate_tx_occ_list(false0, fn_data, &fn_data->host_enabled_map); | |||
| 1029 | ||||
| 1030 | fn_data->state = AEM_ES_PROCESS; | |||
| 1031 | break; | |||
| 1032 | case AEM_ES_PROCESS: | |||
| 1033 | //This case is actually a TX without any request from the host | |||
| 1034 | shr_assert(sd == peer->sd[TEST_PEER_SD_AEMS_IDX])((void)((sd == peer->sd[(1)]) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 1034, "sd == peer->sd[TEST_PEER_SD_AEMS_IDX]"), 0))); | |||
| 1035 | ||||
| 1036 | //Prepare an OCC list response | |||
| 1037 | populate_tx_occ_list(true1, fn_data, &fn_data->aem_during_process_map); | |||
| 1038 | ||||
| 1039 | fn_data->state = AEM_ES_ACK_RESPONSE; | |||
| 1040 | break; | |||
| 1041 | case AEM_ES_ACK_RESPONSE: | |||
| 1042 | shr_assert(sd == peer->sd[TEST_PEER_SD_COMMANDS_IDX])((void)((sd == peer->sd[(0)]) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 1042, "sd == peer->sd[TEST_PEER_SD_COMMANDS_IDX]"), 0))); | |||
| 1043 | ||||
| 1044 | //Prepare an OCC list response | |||
| 1045 | populate_tx_occ_list(false0, fn_data, &fn_data->ack_events_map); | |||
| 1046 | ||||
| 1047 | fn_data->state = AEM_ES_ACK_RECEIVED; | |||
| 1048 | break; | |||
| 1049 | default: | |||
| 1050 | shr_assert(false)((void)((0) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 1050 , "false"), 0)));//Not expected | |||
| 1051 | } | |||
| 1052 | ||||
| 1053 | return 0; | |||
| 1054 | } | |||
| 1055 | ||||
| 1056 | enum libnvme_mi_aem_handler_next_action aem_handler(libnvme_mi_ep_t ep, size_t num_events, void *userdata) | |||
| 1057 | { | |||
| 1058 | struct aem_rcv_enable_fn_data *fn_data = userdata; | |||
| 1059 | ||||
| 1060 | fn_data->callback_count++; | |||
| 1061 | ||||
| 1062 | switch (fn_data->state) { | |||
| 1063 | case AEM_ES_PROCESS: | |||
| 1064 | case AEM_ES_ACK_RESPONSE: | |||
| 1065 | case AEM_ES_ACK_RECEIVED: | |||
| 1066 | { | |||
| 1067 | //This means we just sent out first OCC data | |||
| 1068 | int item_count = 0; | |||
| 1069 | struct libnvme_mi_aem_enabled_map *map; | |||
| 1070 | ||||
| 1071 | //Count how many events we want to act are enabled | |||
| 1072 | switch (fn_data->state) { | |||
| 1073 | case AEM_ES_PROCESS: | |||
| 1074 | map = &fn_data->host_enabled_map; | |||
| 1075 | break; | |||
| 1076 | case AEM_ES_ACK_RESPONSE: | |||
| 1077 | map = &fn_data->aem_during_process_map; | |||
| 1078 | break; | |||
| 1079 | case AEM_ES_ACK_RECEIVED: | |||
| 1080 | map = &fn_data->ack_events_map; | |||
| 1081 | break; | |||
| 1082 | default: | |||
| 1083 | shr_assert(false)((void)((0) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 1083 , "false"), 0))); | |||
| 1084 | } | |||
| 1085 | ||||
| 1086 | for (int i = 0; i < 256; i++) | |||
| 1087 | if (map->enabled[i]) | |||
| 1088 | item_count++; | |||
| 1089 | ||||
| 1090 | shr_assert(num_events == item_count)((void)((num_events == item_count) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 1090, "num_events == item_count"), 0))); | |||
| 1091 | ||||
| 1092 | for (int i = 0; i < num_events; i++) { | |||
| 1093 | struct libnvme_mi_event *e = libnvme_mi_aem_get_next_event(ep); | |||
| 1094 | uint8_t idx = e->aeoi; | |||
| 1095 | ||||
| 1096 | shr_assert(fn_data->events[idx])((void)((fn_data->events[idx]) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 1096, "fn_data->events[idx]"), 0))); | |||
| 1097 | shr_assert(fn_data->host_enabled_map.enabled[idx])((void)((fn_data->host_enabled_map.enabled[idx]) || (shr_assert_fail ("../libnvme/test/mi-mctp.c", 1097, "fn_data->host_enabled_map.enabled[idx]" ), 0))); | |||
| 1098 | shr_assert(fn_data->events[idx]->aeocidi == e->aeocidi)((void)((fn_data->events[idx]->aeocidi == e->aeocidi ) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 1098, "fn_data->events[idx]->aeocidi == e->aeocidi" ), 0))); | |||
| 1099 | shr_assert(fn_data->events[idx]->aessi == e->aessi)((void)((fn_data->events[idx]->aessi == e->aessi) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 1099, "fn_data->events[idx]->aessi == e->aessi" ), 0))); | |||
| 1100 | shr_assert(fn_data->events[idx]->spec_info_len ==((void)((fn_data->events[idx]->spec_info_len == e->spec_info_len ) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 1101, "fn_data->events[idx]->spec_info_len == e->spec_info_len" ), 0))) | |||
| 1101 | e->spec_info_len)((void)((fn_data->events[idx]->spec_info_len == e->spec_info_len ) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 1101, "fn_data->events[idx]->spec_info_len == e->spec_info_len" ), 0))); | |||
| 1102 | shr_assert(memcmp(fn_data->events[idx]->spec_info,((void)((memcmp(fn_data->events[idx]->spec_info, e-> spec_info, e->spec_info_len) == 0) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 1103, "memcmp(fn_data->events[idx]->spec_info, e->spec_info, e->spec_info_len) == 0" ), 0))) | |||
| 1103 | e->spec_info, e->spec_info_len) == 0)((void)((memcmp(fn_data->events[idx]->spec_info, e-> spec_info, e->spec_info_len) == 0) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 1103, "memcmp(fn_data->events[idx]->spec_info, e->spec_info, e->spec_info_len) == 0" ), 0))); | |||
| 1104 | shr_assert(fn_data->events[idx]->vend_spec_info_len ==((void)((fn_data->events[idx]->vend_spec_info_len == e-> vend_spec_info_len) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 1105, "fn_data->events[idx]->vend_spec_info_len == e->vend_spec_info_len" ), 0))) | |||
| 1105 | e->vend_spec_info_len)((void)((fn_data->events[idx]->vend_spec_info_len == e-> vend_spec_info_len) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 1105, "fn_data->events[idx]->vend_spec_info_len == e->vend_spec_info_len" ), 0))); | |||
| 1106 | shr_assert(memcmp(fn_data->events[idx]->vend_spec_info,((void)((memcmp(fn_data->events[idx]->vend_spec_info, e ->vend_spec_info, e->vend_spec_info_len) == 0) || (shr_assert_fail ("../libnvme/test/mi-mctp.c", 1107, "memcmp(fn_data->events[idx]->vend_spec_info, e->vend_spec_info, e->vend_spec_info_len) == 0" ), 0))) | |||
| 1107 | e->vend_spec_info, e->vend_spec_info_len) == 0)((void)((memcmp(fn_data->events[idx]->vend_spec_info, e ->vend_spec_info, e->vend_spec_info_len) == 0) || (shr_assert_fail ("../libnvme/test/mi-mctp.c", 1107, "memcmp(fn_data->events[idx]->vend_spec_info, e->vend_spec_info, e->vend_spec_info_len) == 0" ), 0))); | |||
| 1108 | } | |||
| 1109 | ||||
| 1110 | shr_assert(libnvme_mi_aem_get_next_event(ep) == NULL)((void)((libnvme_mi_aem_get_next_event(ep) == ((void*)0)) || ( shr_assert_fail("../libnvme/test/mi-mctp.c", 1110, "libnvme_mi_aem_get_next_event(ep) == NULL" ), 0))); | |||
| 1111 | break; | |||
| 1112 | } | |||
| 1113 | default: | |||
| 1114 | shr_assert(false)((void)((0) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 1114 , "false"), 0))); | |||
| 1115 | } | |||
| 1116 | ||||
| 1117 | return NVME_MI_AEM_HNA_ACK; | |||
| 1118 | } | |||
| 1119 | ||||
| 1120 | static void aem_test_aem_api_helper(libnvme_mi_ep_t ep, | |||
| 1121 | struct libnvme_mi_aem_config *config, int expected_event_count) | |||
| 1122 | { | |||
| 1123 | struct aem_rcv_enable_fn_data *fn_data = | |||
| 1124 | (struct aem_rcv_enable_fn_data *)test_peer.tx_data; | |||
| 1125 | int rc = 0; | |||
| 1126 | ||||
| 1127 | test_peer.tx_fn = aem_rcv_enable_fn; | |||
| 1128 | ||||
| 1129 | //This should not work outside the handler | |||
| 1130 | shr_assert(libnvme_mi_aem_get_next_event(ep) == NULL)((void)((libnvme_mi_aem_get_next_event(ep) == ((void*)0)) || ( shr_assert_fail("../libnvme/test/mi-mctp.c", 1130, "libnvme_mi_aem_get_next_event(ep) == NULL" ), 0))); | |||
| 1131 | ||||
| 1132 | rc = libnvme_mi_aem_enable(ep, config, test_peer.tx_data); | |||
| 1133 | shr_assert(rc == 0)((void)((rc == 0) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 1133, "rc == 0"), 0))); | |||
| 1134 | ||||
| 1135 | //This should not work outside the handler | |||
| 1136 | shr_assert(libnvme_mi_aem_get_next_event(ep) == NULL)((void)((libnvme_mi_aem_get_next_event(ep) == ((void*)0)) || ( shr_assert_fail("../libnvme/test/mi-mctp.c", 1136, "libnvme_mi_aem_get_next_event(ep) == NULL" ), 0))); | |||
| 1137 | ||||
| 1138 | rc = libnvme_mi_aem_process(ep, test_peer.tx_data); | |||
| 1139 | shr_assert(rc == 0)((void)((rc == 0) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 1139, "rc == 0"), 0))); | |||
| 1140 | ||||
| 1141 | //One for initial enable, one for AEM. No ACK events | |||
| 1142 | shr_assert(fn_data->callback_count == expected_event_count)((void)((fn_data->callback_count == expected_event_count) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 1142, "fn_data->callback_count == expected_event_count" ), 0))); | |||
| 1143 | ||||
| 1144 | //This should not work outside the handler | |||
| 1145 | shr_assert(libnvme_mi_aem_get_next_event(ep) == NULL)((void)((libnvme_mi_aem_get_next_event(ep) == ((void*)0)) || ( shr_assert_fail("../libnvme/test/mi-mctp.c", 1145, "libnvme_mi_aem_get_next_event(ep) == NULL" ), 0))); | |||
| 1146 | } | |||
| 1147 | ||||
| 1148 | static void aem_test_aem_disable_helper(libnvme_mi_ep_t ep, | |||
| 1149 | struct aem_rcv_enable_fn_data *fn_data) | |||
| 1150 | { | |||
| 1151 | memcpy(&fn_data->ep_enabled_map, &fn_data->host_enabled_map, | |||
| 1152 | sizeof(fn_data->host_enabled_map)); | |||
| 1153 | ||||
| 1154 | fn_data->state = AEM_ES_GET_ENABLED;//This is the flow for disabling | |||
| 1155 | shr_assert(libnvme_mi_aem_disable(ep) == 0)((void)((libnvme_mi_aem_disable(ep) == 0) || (shr_assert_fail ("../libnvme/test/mi-mctp.c", 1155, "libnvme_mi_aem_disable(ep) == 0" ), 0))); | |||
| 1156 | } | |||
| 1157 | ||||
| 1158 | static void test_mi_aem_ep_based_failure_helper(libnvme_mi_ep_t ep, | |||
| 1159 | enum aem_failure_condition fc, struct test_peer *peer) | |||
| 1160 | { | |||
| 1161 | struct aem_rcv_enable_fn_data fn_data = {0}; | |||
| 1162 | struct libnvme_mi_aem_config config = {0}; | |||
| 1163 | ||||
| 1164 | config.aemd = 1; | |||
| 1165 | config.aerd = 2; | |||
| 1166 | config.enabled_map.enabled[3] = true1; | |||
| 1167 | fn_data.aem_during_process_map.enabled[3] = true1; | |||
| 1168 | struct libnvme_mi_event e = {0}; | |||
| 1169 | ||||
| 1170 | e.aeoi = 3; | |||
| 1171 | e.spec_info_len = 0; | |||
| 1172 | fn_data.events[3] = &e; | |||
| 1173 | ||||
| 1174 | memcpy(&fn_data.host_enabled_map, &config.enabled_map, sizeof(config.enabled_map)); | |||
| 1175 | ||||
| 1176 | config.aem_handler = aem_handler; | |||
| 1177 | peer->tx_data = (void *) &fn_data; | |||
| 1178 | peer->tx_fn = aem_rcv_enable_fn; | |||
| 1179 | ||||
| 1180 | fn_data.fc = fc; | |||
| 1181 | switch (fc) { | |||
| 1182 | case AEM_FC_BAD_GET_CONFIG_HEADER_LEN: | |||
| 1183 | case AEM_FC_BAD_GET_CONFIG_TOTAL_LEN: | |||
| 1184 | case AEM_FC_BAD_GET_CONFIG_BUFFER_LEN: | |||
| 1185 | case AEM_FC_BAD_OCC_RSP_HDR_LEN_SYNC: | |||
| 1186 | case AEM_FC_BAD_OCC_RSP_TOTAL_LEN_SYNC: | |||
| 1187 | case AEM_FC_BAD_OCC_RSP_BUFFER_LEN_SYNC: | |||
| 1188 | //These all should fail before processing | |||
| 1189 | shr_assert(libnvme_mi_aem_enable(ep, &config, &fn_data) == -EPROTO)((void)((libnvme_mi_aem_enable(ep, &config, &fn_data) == -71) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 1189 , "libnvme_mi_aem_enable(ep, &config, &fn_data) == -EPROTO" ), 0))); | |||
| 1190 | break; | |||
| ||||
| 1191 | case AEM_FC_BAD_OCC_RSP_HDR_LEN_AEM: | |||
| 1192 | case AEM_FC_BAD_OCC_RSP_TOTAL_LEN_AEM: | |||
| 1193 | case AEM_FC_BAD_OCC_RSP_BUFFER_LEN_AEM: | |||
| 1194 | //These should fail on the processing | |||
| 1195 | shr_assert(libnvme_mi_aem_enable(ep, &config, &fn_data) == 0)((void)((libnvme_mi_aem_enable(ep, &config, &fn_data) == 0) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 1195, "libnvme_mi_aem_enable(ep, &config, &fn_data) == 0") , 0))); | |||
| 1196 | shr_assert(libnvme_mi_aem_process(ep, &fn_data) == -EPROTO)((void)((libnvme_mi_aem_process(ep, &fn_data) == -71) || ( shr_assert_fail("../libnvme/test/mi-mctp.c", 1196, "libnvme_mi_aem_process(ep, &fn_data) == -EPROTO" ), 0))); | |||
| 1197 | break; | |||
| 1198 | default: | |||
| 1199 | shr_assert(false)((void)((0) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 1199 , "false"), 0)));//Unexpected | |||
| 1200 | } | |||
| 1201 | } | |||
| 1202 | ||||
| 1203 | /* test: Check validation of endpoint messages in various stages of aem handling */ | |||
| 1204 | static void test_mi_aem_ep_based_failure_conditions(libnvme_mi_ep_t ep, struct test_peer *peer) | |||
| 1205 | { | |||
| 1206 | test_mi_aem_ep_based_failure_helper(ep, AEM_FC_BAD_GET_CONFIG_HEADER_LEN, peer); | |||
| ||||
| 1207 | test_mi_aem_ep_based_failure_helper(ep, AEM_FC_BAD_GET_CONFIG_TOTAL_LEN, peer); | |||
| 1208 | test_mi_aem_ep_based_failure_helper(ep, AEM_FC_BAD_GET_CONFIG_BUFFER_LEN, peer); | |||
| 1209 | test_mi_aem_ep_based_failure_helper(ep, AEM_FC_BAD_OCC_RSP_HDR_LEN_SYNC, peer); | |||
| 1210 | test_mi_aem_ep_based_failure_helper(ep, AEM_FC_BAD_OCC_RSP_HDR_LEN_AEM, peer); | |||
| 1211 | test_mi_aem_ep_based_failure_helper(ep, AEM_FC_BAD_OCC_RSP_TOTAL_LEN_SYNC, peer); | |||
| 1212 | test_mi_aem_ep_based_failure_helper(ep, AEM_FC_BAD_OCC_RSP_TOTAL_LEN_AEM, peer); | |||
| 1213 | test_mi_aem_ep_based_failure_helper(ep, AEM_FC_BAD_OCC_RSP_BUFFER_LEN_SYNC, peer); | |||
| 1214 | test_mi_aem_ep_based_failure_helper(ep, AEM_FC_BAD_OCC_RSP_BUFFER_LEN_AEM, peer); | |||
| 1215 | } | |||
| 1216 | ||||
| 1217 | /* test: Check aem process logic when API used improperly */ | |||
| 1218 | static void test_mi_aem_enable_invalid_usage(libnvme_mi_ep_t ep, struct test_peer *peer) | |||
| 1219 | { | |||
| 1220 | struct libnvme_mi_aem_config config = {0}; | |||
| 1221 | ||||
| 1222 | config.aem_handler = aem_handler; | |||
| 1223 | config.enabled_map.enabled[0] = false0; | |||
| 1224 | config.aemd = 1; | |||
| 1225 | config.aerd = 2; | |||
| 1226 | ||||
| 1227 | //Call with invalid config due to nothing enabled | |||
| 1228 | shr_assert(libnvme_mi_aem_enable(ep, &config, NULL) == -1)((void)((libnvme_mi_aem_enable(ep, &config, ((void*)0)) == -1) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 1228, "libnvme_mi_aem_enable(ep, &config, NULL) == -1" ), 0))); | |||
| 1229 | ||||
| 1230 | config.aem_handler = NULL((void*)0); | |||
| 1231 | config.enabled_map.enabled[0] = true1; | |||
| 1232 | ||||
| 1233 | //Call with invalid config due to no callback | |||
| 1234 | shr_assert(libnvme_mi_aem_enable(ep, &config, NULL) == -1)((void)((libnvme_mi_aem_enable(ep, &config, ((void*)0)) == -1) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 1234, "libnvme_mi_aem_enable(ep, &config, NULL) == -1" ), 0))); | |||
| 1235 | ||||
| 1236 | //Call with invalid config due to being NULL | |||
| 1237 | shr_assert(libnvme_mi_aem_enable(ep, NULL, NULL) == -1)((void)((libnvme_mi_aem_enable(ep, ((void*)0), ((void*)0)) == -1) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 1237, "libnvme_mi_aem_enable(ep, NULL, NULL) == -1" ), 0))); | |||
| 1238 | ||||
| 1239 | config.aem_handler = aem_handler; | |||
| 1240 | config.enabled_map.enabled[0] = true1; | |||
| 1241 | ||||
| 1242 | //Call with invalid endpoint | |||
| 1243 | shr_assert(libnvme_mi_aem_enable(NULL, &config, NULL) == -1)((void)((libnvme_mi_aem_enable(((void*)0), &config, ((void *)0)) == -1) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 1243, "libnvme_mi_aem_enable(NULL, &config, NULL) == -1" ), 0))); | |||
| 1244 | } | |||
| 1245 | ||||
| 1246 | /* test: Check aem process logic when API used improperly */ | |||
| 1247 | static void test_mi_aem_process_invalid_usage(libnvme_mi_ep_t ep, struct test_peer *peer) | |||
| 1248 | { | |||
| 1249 | //Without calling enable first | |||
| 1250 | shr_assert(libnvme_mi_aem_process(ep, NULL) == -1)((void)((libnvme_mi_aem_process(ep, ((void*)0)) == -1) || (shr_assert_fail ("../libnvme/test/mi-mctp.c", 1250, "libnvme_mi_aem_process(ep, NULL) == -1" ), 0))); | |||
| 1251 | ||||
| 1252 | //Call with invalid ep | |||
| 1253 | shr_assert(libnvme_mi_aem_process(NULL, NULL) == -1)((void)((libnvme_mi_aem_process(((void*)0), ((void*)0)) == -1 ) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 1253, "libnvme_mi_aem_process(NULL, NULL) == -1" ), 0))); | |||
| 1254 | } | |||
| 1255 | ||||
| 1256 | /* test: Check aem disable logic when API used improperly */ | |||
| 1257 | static void test_mi_aem_disable_invalid_usage(libnvme_mi_ep_t ep, struct test_peer *peer) | |||
| 1258 | { | |||
| 1259 | shr_assert(libnvme_mi_aem_disable(NULL) == -1)((void)((libnvme_mi_aem_disable(((void*)0)) == -1) || (shr_assert_fail ("../libnvme/test/mi-mctp.c", 1259, "libnvme_mi_aem_disable(NULL) == -1" ), 0))); | |||
| 1260 | } | |||
| 1261 | ||||
| 1262 | static void test_mi_aem_get_enabled_invalid_usage(libnvme_mi_ep_t ep, struct test_peer *peer) | |||
| 1263 | { | |||
| 1264 | struct libnvme_mi_aem_enabled_map map; | |||
| 1265 | ||||
| 1266 | shr_assert(libnvme_mi_aem_get_enabled(ep, NULL) == -1)((void)((libnvme_mi_aem_get_enabled(ep, ((void*)0)) == -1) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 1266, "libnvme_mi_aem_get_enabled(ep, NULL) == -1" ), 0))); | |||
| 1267 | shr_assert(libnvme_mi_aem_get_enabled(NULL, &map) == -1)((void)((libnvme_mi_aem_get_enabled(((void*)0), &map) == - 1) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 1267, "libnvme_mi_aem_get_enabled(NULL, &map) == -1" ), 0))); | |||
| 1268 | } | |||
| 1269 | ||||
| 1270 | /* test: Check aem get enabled logic*/ | |||
| 1271 | static void test_mi_aem_get_enabled(libnvme_mi_ep_t ep, struct test_peer *peer) | |||
| 1272 | { | |||
| 1273 | //When no events enabled on Endpoint | |||
| 1274 | struct aem_rcv_enable_fn_data fn_data = {0}; | |||
| 1275 | struct libnvme_mi_aem_enabled_map map; | |||
| 1276 | ||||
| 1277 | test_peer.tx_fn = aem_rcv_enable_fn; | |||
| 1278 | peer->tx_data = (void *) &fn_data; | |||
| 1279 | fn_data.ep_enabled_map.enabled[8] = true1; | |||
| 1280 | fn_data.ep_enabled_map.enabled[20] = true1; | |||
| 1281 | fn_data.ep_enabled_map.enabled[51] = true1; | |||
| 1282 | fn_data.ep_enabled_map.enabled[255] = true1; | |||
| 1283 | ||||
| 1284 | shr_assert(libnvme_mi_aem_get_enabled(ep, &map) == 0)((void)((libnvme_mi_aem_get_enabled(ep, &map) == 0) || (shr_assert_fail ("../libnvme/test/mi-mctp.c", 1284, "libnvme_mi_aem_get_enabled(ep, &map) == 0" ), 0))); | |||
| 1285 | shr_assert(memcmp(&fn_data.ep_enabled_map, &map, sizeof(map)) == 0)((void)((memcmp(&fn_data.ep_enabled_map, &map, sizeof (map)) == 0) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 1285, "memcmp(&fn_data.ep_enabled_map, &map, sizeof(map)) == 0" ), 0))); | |||
| 1286 | } | |||
| 1287 | ||||
| 1288 | ||||
| 1289 | /* test: Check aem disable logic when called without an enable */ | |||
| 1290 | static void test_mi_aem_disable_no_enable(libnvme_mi_ep_t ep, struct test_peer *peer) | |||
| 1291 | { | |||
| 1292 | //When no events enabled on Endpoint | |||
| 1293 | struct aem_rcv_enable_fn_data fn_data = {0}; | |||
| 1294 | ||||
| 1295 | test_peer.tx_fn = aem_rcv_enable_fn; | |||
| 1296 | peer->tx_data = (void *) &fn_data; | |||
| 1297 | ||||
| 1298 | aem_test_aem_disable_helper(ep, &fn_data); | |||
| 1299 | ||||
| 1300 | //When some events enabled on Endpoint | |||
| 1301 | fn_data.ep_enabled_map.enabled[45] = true1; | |||
| 1302 | ||||
| 1303 | aem_test_aem_disable_helper(ep, &fn_data); | |||
| 1304 | } | |||
| 1305 | ||||
| 1306 | /* test: Check aem enable logic with ack carrying events */ | |||
| 1307 | static void test_mi_aem_api_w_ack_events(libnvme_mi_ep_t ep, struct test_peer *peer) | |||
| 1308 | { | |||
| 1309 | struct aem_rcv_enable_fn_data fn_data = {0}; | |||
| 1310 | struct libnvme_mi_aem_config config = {0}; | |||
| 1311 | ||||
| 1312 | config.aemd = 1; | |||
| 1313 | config.aerd = 2; | |||
| 1314 | peer->tx_data = (void *) &fn_data; | |||
| 1315 | config.aem_handler = aem_handler; | |||
| 1316 | ||||
| 1317 | config.enabled_map.enabled[5] = true1; | |||
| 1318 | config.enabled_map.enabled[15] = true1; | |||
| 1319 | ||||
| 1320 | fn_data.aem_during_process_map.enabled[5] = true1; | |||
| 1321 | ||||
| 1322 | //No ack_events_map will be enabled in this test | |||
| 1323 | fn_data.ack_events_map.enabled[15] = true1; | |||
| 1324 | ||||
| 1325 | //Will have EP have nothing enabled at start (ep_enabled_map) | |||
| 1326 | ||||
| 1327 | struct libnvme_mi_event ev5 = {0}; | |||
| 1328 | ||||
| 1329 | ev5.aeoi = 5; | |||
| 1330 | ev5.aeocidi = 2; | |||
| 1331 | ev5.aessi = 3; | |||
| 1332 | ||||
| 1333 | struct libnvme_mi_event ev15 = {0}; | |||
| 1334 | uint8_t ev15_spec[] = { 45, 15}; | |||
| 1335 | ||||
| 1336 | ev15.aeoi = 15; | |||
| 1337 | ev15.aeocidi = 60213; | |||
| 1338 | ev15.aessi = 200; | |||
| 1339 | ev15.spec_info = ev15_spec; | |||
| 1340 | ev15.spec_info_len = sizeof(ev15_spec); | |||
| 1341 | ||||
| 1342 | fn_data.events[5] = &ev5; | |||
| 1343 | fn_data.events[15] = &ev15; | |||
| 1344 | ||||
| 1345 | memcpy(&fn_data.host_enabled_map, &config.enabled_map, sizeof(config.enabled_map)); | |||
| 1346 | ||||
| 1347 | aem_test_aem_api_helper(ep, &config, 3); | |||
| 1348 | ||||
| 1349 | aem_test_aem_disable_helper(ep, &fn_data); | |||
| 1350 | } | |||
| 1351 | ||||
| 1352 | /* test: Check aem enable logic */ | |||
| 1353 | static void test_mi_aem_api_simple(libnvme_mi_ep_t ep, struct test_peer *peer) | |||
| 1354 | { | |||
| 1355 | struct aem_rcv_enable_fn_data fn_data = {0}; | |||
| 1356 | struct libnvme_mi_aem_config config = {0}; | |||
| 1357 | ||||
| 1358 | config.aemd = 1; | |||
| 1359 | config.aerd = 2; | |||
| 1360 | peer->tx_data = (void *) &fn_data; | |||
| 1361 | config.aem_handler = aem_handler; | |||
| 1362 | ||||
| 1363 | config.enabled_map.enabled[1] = true1; | |||
| 1364 | config.enabled_map.enabled[3] = true1; | |||
| 1365 | config.enabled_map.enabled[16] = true1; | |||
| 1366 | ||||
| 1367 | fn_data.aem_during_process_map.enabled[3] = true1; | |||
| 1368 | ||||
| 1369 | //No ack_events_map will be enabled in this test | |||
| 1370 | ||||
| 1371 | fn_data.ep_enabled_map.enabled[3] = true1; | |||
| 1372 | fn_data.ep_enabled_map.enabled[20] = true1; | |||
| 1373 | fn_data.ep_enabled_map.enabled[200] = true1; | |||
| 1374 | ||||
| 1375 | struct libnvme_mi_event ev1 = {0}; | |||
| 1376 | uint8_t ev1_spec[] = { 98, 56, 32, 12}; | |||
| 1377 | ||||
| 1378 | ev1.aeoi = 1; | |||
| 1379 | ev1.aeocidi = 2; | |||
| 1380 | ev1.aessi = 3; | |||
| 1381 | ev1.spec_info = ev1_spec; | |||
| 1382 | ev1.spec_info_len = sizeof(ev1_spec); | |||
| 1383 | ||||
| 1384 | struct libnvme_mi_event ev3 = {0}; | |||
| 1385 | uint8_t ev3_spec[] = { 45, 15}; | |||
| 1386 | ||||
| 1387 | ev3.aeoi = 3; | |||
| 1388 | ev3.aeocidi = 4; | |||
| 1389 | ev3.aessi = 5; | |||
| 1390 | ev3.spec_info = ev3_spec; | |||
| 1391 | ev3.spec_info_len = sizeof(ev3_spec); | |||
| 1392 | ||||
| 1393 | struct libnvme_mi_event ev16 = {0}; | |||
| 1394 | ||||
| 1395 | ev16.aeoi = 16; | |||
| 1396 | ev16.aeocidi = 6; | |||
| 1397 | ev16.aessi = 7; | |||
| 1398 | ||||
| 1399 | fn_data.events[1] = &ev1; | |||
| 1400 | fn_data.events[3] = &ev3; | |||
| 1401 | fn_data.events[16] = &ev16; | |||
| 1402 | ||||
| 1403 | memcpy(&fn_data.host_enabled_map, &config.enabled_map, sizeof(config.enabled_map)); | |||
| 1404 | ||||
| 1405 | aem_test_aem_api_helper(ep, &config, 2); | |||
| 1406 | ||||
| 1407 | aem_test_aem_disable_helper(ep, &fn_data); | |||
| 1408 | } | |||
| 1409 | ||||
| 1410 | #define DEFINE_TEST(name){ "name", test_name } { #name, test_ ## name } | |||
| 1411 | struct test { | |||
| 1412 | const char *name; | |||
| 1413 | void (*fn)(libnvme_mi_ep_t, struct test_peer *); | |||
| 1414 | } tests[] = { | |||
| 1415 | DEFINE_TEST(rx_err){ "rx_err", test_rx_err }, | |||
| 1416 | DEFINE_TEST(tx_none){ "tx_none", test_tx_none }, | |||
| 1417 | DEFINE_TEST(tx_err){ "tx_err", test_tx_err }, | |||
| 1418 | DEFINE_TEST(tx_short){ "tx_short", test_tx_short }, | |||
| 1419 | DEFINE_TEST(read_mi_data){ "read_mi_data", test_read_mi_data }, | |||
| 1420 | DEFINE_TEST(poll_err){ "poll_err", test_poll_err }, | |||
| 1421 | DEFINE_TEST(mi_resp_err){ "mi_resp_err", test_mi_resp_err }, | |||
| 1422 | DEFINE_TEST(mi_resp_unaligned){ "mi_resp_unaligned", test_mi_resp_unaligned }, | |||
| 1423 | DEFINE_TEST(mi_resp_unaligned_expected){ "mi_resp_unaligned_expected", test_mi_resp_unaligned_expected }, | |||
| 1424 | DEFINE_TEST(admin_resp_err){ "admin_resp_err", test_admin_resp_err }, | |||
| 1425 | DEFINE_TEST(admin_resp_sizes){ "admin_resp_sizes", test_admin_resp_sizes }, | |||
| 1426 | DEFINE_TEST(poll_timeout_value){ "poll_timeout_value", test_poll_timeout_value }, | |||
| 1427 | DEFINE_TEST(poll_timeout){ "poll_timeout", test_poll_timeout }, | |||
| 1428 | DEFINE_TEST(mpr_mi){ "mpr_mi", test_mpr_mi }, | |||
| 1429 | DEFINE_TEST(mpr_admin){ "mpr_admin", test_mpr_admin }, | |||
| 1430 | DEFINE_TEST(mpr_admin_quirked){ "mpr_admin_quirked", test_mpr_admin_quirked }, | |||
| 1431 | DEFINE_TEST(mpr_timeouts){ "mpr_timeouts", test_mpr_timeouts }, | |||
| 1432 | DEFINE_TEST(mpr_timeout_clamp){ "mpr_timeout_clamp", test_mpr_timeout_clamp }, | |||
| 1433 | DEFINE_TEST(mpr_mprt_zero){ "mpr_mprt_zero", test_mpr_mprt_zero }, | |||
| 1434 | DEFINE_TEST(mi_aem_api_simple){ "mi_aem_api_simple", test_mi_aem_api_simple }, | |||
| 1435 | DEFINE_TEST(mi_aem_api_w_ack_events){ "mi_aem_api_w_ack_events", test_mi_aem_api_w_ack_events }, | |||
| 1436 | DEFINE_TEST(mi_aem_disable_no_enable){ "mi_aem_disable_no_enable", test_mi_aem_disable_no_enable }, | |||
| 1437 | DEFINE_TEST(mi_aem_process_invalid_usage){ "mi_aem_process_invalid_usage", test_mi_aem_process_invalid_usage }, | |||
| 1438 | DEFINE_TEST(mi_aem_enable_invalid_usage){ "mi_aem_enable_invalid_usage", test_mi_aem_enable_invalid_usage }, | |||
| 1439 | DEFINE_TEST(mi_aem_disable_invalid_usage){ "mi_aem_disable_invalid_usage", test_mi_aem_disable_invalid_usage }, | |||
| 1440 | DEFINE_TEST(mi_aem_get_enabled){ "mi_aem_get_enabled", test_mi_aem_get_enabled }, | |||
| 1441 | DEFINE_TEST(mi_aem_get_enabled_invalid_usage){ "mi_aem_get_enabled_invalid_usage", test_mi_aem_get_enabled_invalid_usage }, | |||
| 1442 | DEFINE_TEST(mi_aem_ep_based_failure_conditions){ "mi_aem_ep_based_failure_conditions", test_mi_aem_ep_based_failure_conditions }, | |||
| 1443 | }; | |||
| 1444 | ||||
| 1445 | static void run_test(struct test *test, FILE *logfd, libnvme_mi_ep_t ep, | |||
| 1446 | struct test_peer *peer) | |||
| 1447 | { | |||
| 1448 | printf("Running test %s...", test->name); | |||
| 1449 | fflush(stdoutstdout); | |||
| 1450 | test->fn(ep, peer); | |||
| 1451 | printf(" OK\n"); | |||
| 1452 | test_print_log_buf(logfd); | |||
| 1453 | } | |||
| 1454 | ||||
| 1455 | int main(void) | |||
| 1456 | { | |||
| 1457 | struct libnvme_global_ctx *ctx; | |||
| 1458 | libnvme_mi_ep_t ep; | |||
| 1459 | unsigned int i; | |||
| 1460 | FILE *fd; | |||
| 1461 | ||||
| 1462 | fd = test_setup_log(); | |||
| 1463 | ||||
| 1464 | __libnvme_mi_mctp_set_ops(&ops); | |||
| 1465 | ||||
| 1466 | ctx = libnvme_create_global_ctx(); | |||
| 1467 | shr_assert(ctx)((void)((ctx) || (shr_assert_fail("../libnvme/test/mi-mctp.c" , 1467, "ctx"), 0))); | |||
| 1468 | libnvme_set_logging_file(ctx, fd); | |||
| 1469 | ||||
| 1470 | ep = libnvme_mi_open_mctp(ctx, 0, 0); | |||
| 1471 | shr_assert(ep)((void)((ep) || (shr_assert_fail("../libnvme/test/mi-mctp.c", 1471, "ep"), 0))); | |||
| 1472 | ||||
| 1473 | for (i = 0; i < ARRAY_SIZE(tests)(sizeof(tests) / sizeof((tests)[0]) + 0); i++) { | |||
| 1474 | reset_test_peer(); | |||
| 1475 | run_test(&tests[i], fd, ep, &test_peer); | |||
| 1476 | } | |||
| 1477 | ||||
| 1478 | libnvme_mi_close(ep); | |||
| 1479 | libnvme_free_global_ctx(ctx); | |||
| 1480 | ||||
| 1481 | test_close_log(fd); | |||
| 1482 | ||||
| 1483 | return EXIT_SUCCESS0; | |||
| 1484 | } |