1 /*
2  * Copyright (c) 2015-2017 Los Alamos National Security, LLC.
3  *                         All rights reserved.
4  * Copyright (c) 2015-2017 Cray Inc. All rights reserved.
5  *
6  * This software is available to you under a choice of one of two
7  * licenses.  You may choose to be licensed under the terms of the GNU
8  * General Public License (GPL) Version 2, available from the file
9  * COPYING in the main directory of this source tree, or the
10  * BSD license below:
11  *
12  *     Redistribution and use in source and binary forms, with or
13  *     without modification, are permitted provided that the following
14  *     conditions are met:
15  *
16  *      - Redistributions of source code must retain the above
17  *        copyright notice, this list of conditions and the following
18  *        disclaimer.
19  *
20  *      - Redistributions in binary form must reproduce the above
21  *        copyright notice, this list of conditions and the following
22  *        disclaimer in the documentation and/or other materials
23  *        provided with the distribution.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32  * SOFTWARE.
33  */
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <errno.h>
38 #include <getopt.h>
39 #include <poll.h>
40 #include <time.h>
41 #include <string.h>
42 
43 
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <inttypes.h>
47 
48 #include "gnix_cq.h"
49 #include "gnix.h"
50 
51 #include <criterion/criterion.h>
52 #include "gnix_rdma_headers.h"
53 #include "common.h"
54 
55 /* Note: Set to ~FI_NOTIFY_FLAGS_ONLY since this was written before api 1.5 */
56 static uint64_t mode_bits = ~FI_NOTIFY_FLAGS_ONLY;
57 static uint64_t old_mode_bits;
58 static struct fid_fabric *fab;
59 static struct fid_domain *dom;
60 static struct gnix_fid_ep *ep;
61 static struct fid_ep *fid_ep;
62 static struct fid_cq *rcq;
63 static struct fi_info *hints;
64 static struct fi_info *fi;
65 static struct fi_cq_attr cq_attr;
66 static struct gnix_fid_cq *cq_priv;
67 
68 static struct gnix_fid_wait *wait_priv;
69 static struct fid_wait *wait_set;
70 static struct fi_wait_attr wait_attr;
71 
_setup(uint32_t version)72 static void _setup(uint32_t version)
73 {
74 	int ret = 0;
75 
76 	hints = fi_allocinfo();
77 	cr_assert(hints, "fi_allocinfo");
78 	if (FI_VERSION_LT(version, FI_VERSION(1, 5)))
79 		hints->domain_attr->mr_mode = FI_MR_BASIC;
80 	else
81 		hints->domain_attr->mr_mode = GNIX_DEFAULT_MR_MODE;
82 	hints->domain_attr->cq_data_size = 4;
83 	hints->mode = mode_bits;
84 
85 	hints->fabric_attr->prov_name = strdup("gni");
86 
87 	ret = fi_getinfo(version, NULL, 0, 0, hints, &fi);
88 	cr_assert(!ret, "fi_getinfo");
89 
90 	ret = fi_fabric(fi->fabric_attr, &fab, NULL);
91 	cr_assert(!ret, "fi_fabric");
92 
93 	ret = fi_domain(fab, fi, &dom, NULL);
94 	cr_assert(!ret, "fi_domain");
95 
96 	cq_attr.wait_obj = FI_WAIT_NONE;
97 }
98 
setup(void)99 static void setup(void)
100 {
101 	_setup(fi_version());
102 }
103 
setup_1_4(void)104 static void setup_1_4(void)
105 {
106 	_setup(FI_VERSION(1, 4));
107 }
108 
teardown(void)109 static void teardown(void)
110 {
111 	int ret = 0;
112 
113 	ret = fi_close(&dom->fid);
114 	cr_assert(!ret, "failure in closing domain.");
115 	ret = fi_close(&fab->fid);
116 	cr_assert(!ret, "failure in closing fabric.");
117 	fi_freeinfo(fi);
118 	fi_freeinfo(hints);
119 }
120 
cq_create(enum fi_cq_format format,enum fi_wait_obj wait_obj,size_t size)121 void cq_create(enum fi_cq_format format, enum fi_wait_obj wait_obj,
122 	       size_t size)
123 {
124 	int ret = 0;
125 
126 	cq_attr.format = format;
127 	cq_attr.size = size;
128 	cq_attr.wait_obj = wait_obj;
129 
130 	ret = fi_cq_open(dom, &cq_attr, &rcq, NULL);
131 	cr_assert(!ret, "fi_cq_open");
132 
133 	cq_priv = container_of(rcq, struct gnix_fid_cq, cq_fid);
134 
135 	if (cq_priv->wait) {
136 		wait_priv = container_of(cq_priv->wait, struct gnix_fid_wait,
137 					 wait);
138 	}
139 }
140 
cq_setup(void)141 void cq_setup(void)
142 {
143 	setup();
144 	cq_create(FI_CQ_FORMAT_UNSPEC, FI_WAIT_NONE, 0);
145 }
146 
cq_setup_1_4(void)147 void cq_setup_1_4(void)
148 {
149 	setup_1_4();
150 	cq_create(FI_CQ_FORMAT_UNSPEC, FI_WAIT_NONE, 0);
151 }
152 
cq_msg_setup(void)153 void cq_msg_setup(void)
154 {
155 	setup();
156 	cq_create(FI_CQ_FORMAT_MSG, FI_WAIT_NONE, 8);
157 }
158 
cq_data_setup(void)159 void cq_data_setup(void)
160 {
161 	setup();
162 	cq_create(FI_CQ_FORMAT_DATA, FI_WAIT_NONE, 8);
163 }
164 
cq_tagged_setup(void)165 void cq_tagged_setup(void)
166 {
167 	setup();
168 	cq_create(FI_CQ_FORMAT_TAGGED, FI_WAIT_NONE, 8);
169 }
170 
cq_wait_none_setup(void)171 void cq_wait_none_setup(void)
172 {
173 	setup();
174 	cq_create(FI_CQ_FORMAT_MSG, FI_WAIT_NONE, 8);
175 }
176 
cq_wait_fd_setup(void)177 void cq_wait_fd_setup(void)
178 {
179 	setup();
180 	cq_create(FI_CQ_FORMAT_MSG, FI_WAIT_FD, 8);
181 }
182 
cq_wait_unspec_setup(void)183 void cq_wait_unspec_setup(void)
184 {
185 	setup();
186 	cq_create(FI_CQ_FORMAT_MSG, FI_WAIT_UNSPEC, 8);
187 }
188 
cq_wait_mutex_cond_setup(void)189 void cq_wait_mutex_cond_setup(void)
190 {
191 	setup();
192 	cq_create(FI_CQ_FORMAT_MSG, FI_WAIT_MUTEX_COND, 8);
193 }
194 
cq_notify_setup(void)195 void cq_notify_setup(void)
196 {
197 	int ret;
198 	old_mode_bits = mode_bits;
199 	mode_bits = FI_NOTIFY_FLAGS_ONLY;
200 	setup();
201 
202 	ret = fi_endpoint(dom, fi, &fid_ep, NULL);
203 	cr_assert(!ret, "fi_endpoint");
204 	cr_assert(fid_ep != NULL);
205 
206 	ep = container_of(fid_ep, struct gnix_fid_ep, ep_fid);
207 	cr_assert(ep, "ep not allocated");
208 
209 	cq_create(FI_CQ_FORMAT_MSG, FI_WAIT_NONE, 0);
210 }
211 
cq_teardown(void)212 void cq_teardown(void)
213 {
214 	cr_assert(!fi_close(&rcq->fid), "failure in closing cq.");
215 	teardown();
216 }
217 
cq_notify_teardown(void)218 void cq_notify_teardown(void)
219 {
220 	cr_assert(!fi_close(&rcq->fid), "failure in closing cq.");
221 	cr_assert(!fi_close(&fid_ep->fid), "failure in closing ep.");
222 	teardown();
223 	mode_bits = old_mode_bits;
224 
225 }
226 
227 /*******************************************************************************
228  * Creation Tests:
229  *
230  * Create the CQ with various parameters and make sure the fields are being
231  * initialized correctly.
232  ******************************************************************************/
233 
234 TestSuite(creation, .init = setup, .fini = cq_teardown);
235 
Test(creation,format_unspec)236 Test(creation, format_unspec)
237 {
238 	int ret = 0;
239 
240 	cq_attr.format = FI_CQ_FORMAT_UNSPEC;
241 
242 	ret = fi_cq_open(dom, &cq_attr, &rcq, NULL);
243 	cr_assert(!ret, "fi_cq_open");
244 
245 	cq_priv = container_of(rcq, struct gnix_fid_cq, cq_fid);
246 	cr_assert(cq_priv->entry_size == sizeof(struct fi_cq_entry));
247 }
248 
Test(creation,format_context)249 Test(creation, format_context)
250 {
251 	int ret = 0;
252 
253 	cq_attr.format = FI_CQ_FORMAT_CONTEXT;
254 
255 	ret = fi_cq_open(dom, &cq_attr, &rcq, NULL);
256 	cr_assert(!ret, "fi_cq_open");
257 
258 	cq_priv = container_of(rcq, struct gnix_fid_cq, cq_fid);
259 	cr_assert(cq_priv->entry_size == sizeof(struct fi_cq_entry));
260 }
261 
Test(creation,format_msg)262 Test(creation, format_msg)
263 {
264 	int ret = 0;
265 
266 	cq_attr.format = FI_CQ_FORMAT_MSG;
267 
268 	ret = fi_cq_open(dom, &cq_attr, &rcq, NULL);
269 	cr_assert(!ret, "fi_cq_open");
270 
271 	cq_priv = container_of(rcq, struct gnix_fid_cq, cq_fid);
272 	cr_assert(cq_priv->entry_size == sizeof(struct fi_cq_msg_entry));
273 }
274 
Test(creation,format_data)275 Test(creation, format_data)
276 {
277 	int ret = 0;
278 
279 	cq_attr.format = FI_CQ_FORMAT_DATA;
280 
281 	ret = fi_cq_open(dom, &cq_attr, &rcq, NULL);
282 	cr_assert(!ret, "fi_cq_open");
283 
284 	cq_priv = container_of(rcq, struct gnix_fid_cq, cq_fid);
285 	cr_assert(cq_priv->entry_size == sizeof(struct fi_cq_data_entry));
286 }
287 
Test(creation,format_tagged)288 Test(creation, format_tagged)
289 {
290 	int ret = 0;
291 
292 	cq_attr.format = FI_CQ_FORMAT_TAGGED;
293 
294 	ret = fi_cq_open(dom, &cq_attr, &rcq, NULL);
295 	cr_assert(!ret, "fi_cq_open");
296 
297 	cq_priv = container_of(rcq, struct gnix_fid_cq, cq_fid);
298 	cr_assert(cq_priv->entry_size == sizeof(struct fi_cq_tagged_entry));
299 }
300 
301 TestSuite(insertion, .init = cq_setup, .fini = cq_teardown);
302 
Test(insertion,single)303 Test(insertion, single)
304 {
305 	int ret = 0;
306 	char input_ctx = 'a';
307 	struct fi_cq_entry entry;
308 
309 	cr_assert(!cq_priv->events->item_list.head);
310 
311 	_gnix_cq_add_event(cq_priv, NULL, &input_ctx, 0, 0, 0, 0, 0, 0);
312 
313 	cr_assert(cq_priv->events->item_list.head);
314 	cr_assert_eq(cq_priv->events->item_list.head,
315 		     cq_priv->events->item_list.tail);
316 
317 	ret = fi_cq_read(rcq, &entry, 1);
318 	cr_assert(ret == 1);
319 	cr_assert(!cq_priv->events->item_list.head);
320 
321 	cr_assert_eq(*(char *) entry.op_context, input_ctx,
322 		     "Expected same op_context as inserted.");
323 }
324 
Test(insertion,limit)325 Test(insertion, limit)
326 {
327 	int ret = 0;
328 	char input_ctx = 'a';
329 	struct fi_cq_entry entry;
330 	const size_t cq_size = cq_priv->attr.size;
331 
332 	for (size_t i = 0; i < cq_size; i++)
333 		_gnix_cq_add_event(cq_priv, NULL, &input_ctx, 0, 0, 0, 0, 0, 0);
334 
335 	cr_assert(cq_priv->events->item_list.head);
336 	cr_assert(!cq_priv->events->free_list.head);
337 
338 	_gnix_cq_add_event(cq_priv, NULL, &input_ctx, 0, 0, 0, 0, 0, 0);
339 
340 	for (size_t i = 0; i < cq_size + 1; i++) {
341 		ret = fi_cq_read(rcq, &entry, 1);
342 		cr_assert_eq(ret, 1);
343 	}
344 
345 	cr_assert(!cq_priv->events->item_list.head);
346 	cr_assert(cq_priv->events->free_list.head);
347 }
348 
349 TestSuite(mode_bits, .init = NULL, .fini = teardown);
350 
Test(mode_bits,fi_notify_flags_only_1_4)351 Test(mode_bits, fi_notify_flags_only_1_4)
352 {
353 	old_mode_bits = mode_bits;
354 	mode_bits = ~0;
355 	_setup(FI_VERSION(1, 4));
356 	cr_assert_eq(fi->mode & FI_NOTIFY_FLAGS_ONLY, 0, "Did not clear notify flag for version 1.4");
357 	mode_bits = old_mode_bits;
358 }
359 
Test(mode_bits,fi_notify_flags_only)360 Test(mode_bits, fi_notify_flags_only)
361 {
362 	old_mode_bits = mode_bits;
363 	mode_bits = ~0;
364 	_setup(fi_version());
365 	cr_assert(fi->mode & FI_NOTIFY_FLAGS_ONLY, "Cleared the notify flag when we shouldn't have\n");
366 	mode_bits = old_mode_bits;
367 }
368 
369 TestSuite(reading, .init = cq_setup, .fini = cq_teardown);
370 
Test(reading,empty)371 Test(reading, empty)
372 {
373 	int ret = 0;
374 	struct fi_cq_entry entry;
375 
376 	ret = fi_cq_read(rcq, &entry, 1);
377 	cr_assert_eq(ret, -FI_EAGAIN);
378 }
379 
Test(reading,error)380 Test(reading, error)
381 {
382 	int ret = 0;
383 	struct fi_cq_entry entry;
384 	struct fi_cq_err_entry err_entry;
385 
386 	char input_ctx = 'a';
387 	uint64_t flags = 0xb;
388 	size_t len = sizeof(input_ctx);
389 	void *buf = &input_ctx;
390 	uint64_t data = 20;
391 	uint64_t tag = 40;
392 	size_t olen = 20;
393 	int err = 50;
394 	int prov_errno = 80;
395 
396 	/*
397 	 * By default CQ start out with no error entries and no entries
398 	 * in the error entry free list.
399 	 */
400 	cr_assert(!cq_priv->errors->item_list.head);
401 	cr_assert(!cq_priv->errors->free_list.head);
402 
403 	_gnix_cq_add_error(cq_priv, &input_ctx, flags, len, buf, data, tag,
404 			   olen, err, prov_errno, 0, 0);
405 
406 	cr_assert(cq_priv->errors->item_list.head);
407 
408 	ret = fi_cq_read(rcq, &entry, 1);
409 	cr_assert_eq(ret, -FI_EAVAIL);
410 
411 	cr_assert(!cq_priv->events->item_list.head);
412 	cr_assert(cq_priv->errors->item_list.head);
413 	/* Testing err_data == NULL path set size to something
414 	 * other than 0 then verify it was set back to 0 */
415 	err_entry.err_data_size = 12;
416 	err_entry.err_data = malloc(12);
417 	ret = fi_cq_readerr(rcq, &err_entry, 0);
418 	cr_assert_eq(ret, 1);
419 
420 	/*
421 	 * Item should have been removed from error queue and placed on free
422 	 * queue.
423 	 */
424 	cr_assert(!cq_priv->errors->item_list.head);
425 	cr_assert(cq_priv->errors->free_list.head);
426 
427 	/*
428 	 * Compare structural items...
429 	 */
430 	cr_assert_eq(*(char *) err_entry.op_context, input_ctx);
431 	cr_assert_eq(err_entry.flags, flags);
432 	cr_assert_eq(err_entry.len, len);
433 	cr_assert_eq(err_entry.buf, buf);
434 	cr_assert_eq(err_entry.data, data);
435 	cr_assert_eq(err_entry.tag, tag);
436 	cr_assert_eq(err_entry.olen, olen);
437 	cr_assert_eq(err_entry.err, err);
438 	cr_assert_eq(err_entry.prov_errno, prov_errno);
439 	cr_assert(err_entry.err_data != NULL);
440 	free(err_entry.err_data);
441 	cr_assert(err_entry.err_data_size == 0);
442 }
443 
444 TestSuite(reading_1_4, .init = cq_setup_1_4, .fini = cq_teardown);
445 
Test(reading_1_4,error)446 Test(reading_1_4, error)
447 {
448 	int ret = 0;
449 	struct fi_cq_entry entry;
450 	struct fi_cq_err_entry err_entry;
451 
452 	char input_ctx = 'a';
453 	uint64_t flags = 0xb;
454 	size_t len = sizeof(input_ctx);
455 	void *buf = &input_ctx;
456 	uint64_t data = 20;
457 	uint64_t tag = 40;
458 	size_t olen = 20;
459 	int err = 50;
460 	int prov_errno = 80;
461 
462 	/*
463 	 * By default CQ start out with no error entries and no entries
464 	 * in the error entry free list.
465 	 */
466 	cr_assert(!cq_priv->errors->item_list.head);
467 	cr_assert(!cq_priv->errors->free_list.head);
468 
469 	_gnix_cq_add_error(cq_priv, &input_ctx, flags, len, buf, data, tag,
470 			   olen, err, prov_errno, 0, 0);
471 
472 	cr_assert(cq_priv->errors->item_list.head);
473 
474 	ret = fi_cq_read(rcq, &entry, 1);
475 	cr_assert_eq(ret, -FI_EAVAIL);
476 
477 	cr_assert(!cq_priv->events->item_list.head);
478 	cr_assert(cq_priv->errors->item_list.head);
479 	ret = fi_cq_readerr(rcq, &err_entry, 0);
480 	cr_assert_eq(ret, 1);
481 
482 	/*
483 	 * Item should have been removed from error queue and placed on free
484 	 * queue.
485 	 */
486 	cr_assert(!cq_priv->errors->item_list.head);
487 	cr_assert(cq_priv->errors->free_list.head);
488 
489 	/*
490 	 * Compare structural items...
491 	 */
492 	cr_assert_eq(*(char *) err_entry.op_context, input_ctx);
493 	cr_assert_eq(err_entry.flags, flags);
494 	cr_assert_eq(err_entry.len, len);
495 	cr_assert_eq(err_entry.buf, buf);
496 	cr_assert_eq(err_entry.data, data);
497 	cr_assert_eq(err_entry.tag, tag);
498 	cr_assert_eq(err_entry.olen, olen);
499 	cr_assert_eq(err_entry.err, err);
500 	cr_assert_eq(err_entry.prov_errno, prov_errno);
501 	cr_assert(err_entry.err_data == NULL);
502 }
503 
504 #define ENTRY_CNT 5
Test(reading,issue192)505 Test(reading, issue192)
506 {
507 	int ret = 0;
508 	char input_ctx = 'a';
509 	struct fi_cq_entry entries[ENTRY_CNT];
510 
511 	_gnix_cq_add_event(cq_priv, NULL, &input_ctx, 0, 0, 0, 0, 0, 0);
512 
513 	ret = fi_cq_read(rcq, &entries, ENTRY_CNT);
514 	cr_assert_eq(ret, 1);
515 
516 	ret = fi_cq_read(rcq, &entries, ENTRY_CNT);
517 	cr_assert_eq(ret, -FI_EAGAIN);
518 }
519 
520 
cq_add_read_setup(enum fi_cq_format format)521 static void cq_add_read_setup(enum fi_cq_format format)
522 {
523 	switch (format) {
524 	default:
525 	case FI_CQ_FORMAT_UNSPEC:
526 		cq_setup();
527 		break;
528 	case FI_CQ_FORMAT_MSG:
529 		cq_msg_setup();
530 		break;
531 	case FI_CQ_FORMAT_DATA:
532 		cq_data_setup();
533 		break;
534 	case FI_CQ_FORMAT_TAGGED:
535 		cq_tagged_setup();
536 		break;
537 	}
538 }
539 
cq_add_read_check(enum fi_cq_format format,struct fi_cq_tagged_entry * entry,struct fi_cq_tagged_entry * expected)540 static void cq_add_read_check(enum fi_cq_format format,
541 			      struct fi_cq_tagged_entry *entry,
542 			      struct fi_cq_tagged_entry *expected)
543 {
544 	cr_assert_eq(*(char *) entry->op_context,
545 		     *(char *) expected->op_context);
546 
547 	if (format == FI_CQ_FORMAT_UNSPEC ||
548 	    format == FI_CQ_FORMAT_CONTEXT) {
549 		return;
550 	}
551 
552 	cr_assert_eq(entry->flags, expected->flags);
553 	cr_assert_eq(entry->len, expected->len);
554 
555 	if (format == FI_CQ_FORMAT_MSG) {
556 		return;
557 	}
558 
559 	cr_assert_eq(entry->buf, expected->buf);
560 	cr_assert_eq(entry->data, expected->data);
561 
562 	if (format == FI_CQ_FORMAT_DATA) {
563 		return;
564 	}
565 
566 	cr_assert_eq(entry->tag, expected->tag);
567 }
568 
569 /*
570  * Add an event and read the cq.
571  */
cq_add_read(enum fi_cq_format format)572 static void cq_add_read(enum fi_cq_format format)
573 {
574 	int ret = 0;
575 	char input_ctx = 'a';
576 	struct fi_cq_tagged_entry entry; /* biggest one */
577 	struct fi_cq_tagged_entry expected = { &input_ctx, 2, 4, (void *) 8,
578 					       16, 32 };
579 
580 	cq_add_read_setup(format);
581 
582 	cr_assert(!cq_priv->events->item_list.head);
583 
584 	_gnix_cq_add_event(cq_priv, NULL, expected.op_context, expected.flags,
585 			   expected.len, expected.buf, expected.data,
586 			   expected.tag, 0x0);
587 
588 	cr_assert(cq_priv->events->item_list.head);
589 
590 	ret = fi_cq_read(rcq, &entry, 1);
591 	cr_assert_eq(ret, 1);
592 
593 	cq_add_read_check(format, &entry, &expected);
594 
595 	cr_assert(!cq_priv->events->item_list.head);
596 }
597 
598 /*
599  * Create up to the size events to fill it up. Check that all the properties
600  * are correct, then add one more that is different. Read size items and then
601  * add an error and try reading. Ensure that we get back -FI_EAVAIL. Then read
602  * the last item and make sure it's the same values put in originally.
603  */
cq_fill_test(enum fi_cq_format format)604 static void cq_fill_test(enum fi_cq_format format)
605 {
606 	char input_ctx = 'a';
607 	struct fi_cq_tagged_entry entry; /* biggest one */
608 	struct fi_cq_tagged_entry expected = { &input_ctx, 2, 4, (void *) 8,
609 					       16, 32 };
610 	struct fi_cq_err_entry err_entry;
611 	int ret = 0;
612 	uint64_t flags = 2;
613 	size_t len = 4;
614 	size_t cq_size;
615 
616 	cq_add_read_setup(format);
617 
618 	cr_assert(!cq_priv->events->item_list.head);
619 	cr_assert(cq_priv->events->free_list.head);
620 
621 	cq_size = cq_priv->attr.size;
622 	for (size_t i = 0; i < cq_size; i++) {
623 		_gnix_cq_add_event(cq_priv, NULL, expected.op_context,
624 				   expected.flags, expected.len,
625 				   expected.buf, expected.data,
626 				   expected.tag, 0x0);
627 	}
628 
629 	cr_assert(cq_priv->events->item_list.head);
630 	cr_assert(!cq_priv->events->free_list.head);
631 
632 	_gnix_cq_add_event(cq_priv, NULL, expected.op_context,
633 			   expected.flags, 2 * expected.len, expected.buf,
634 			   expected.data, expected.tag, 0x0);
635 
636 	for (size_t i = 0; i < cq_size; i++) {
637 		ret = fi_cq_read(rcq, &entry, 1);
638 		cr_assert_eq(ret, 1);
639 		cq_add_read_check(format, &entry, &expected);
640 	}
641 
642 	/*
643 	 * If we insert an error it should return -FI_EAVAIL despite having
644 	 * something to read.
645 	 */
646 
647 	_gnix_cq_add_error(cq_priv, &input_ctx, flags, len, 0, 0, 0, 0, 0, 0,
648 			   0, 0);
649 	cr_assert(cq_priv->errors->item_list.head);
650 
651 	ret = fi_cq_read(rcq, &entry, 1);
652 	cr_assert_eq(ret, -FI_EAVAIL);
653 
654 	ret = fi_cq_readerr(rcq, &err_entry, 0);
655 	cr_assert_eq(ret, 1);
656 
657 	/*
658 	 * Creating an error allocs an error but it is then placed in the free
659 	 * list after reading.
660 	 */
661 	cr_assert(cq_priv->errors->free_list.head);
662 	cr_assert(!cq_priv->errors->item_list.head);
663 
664 	ret = fi_cq_read(rcq, &entry, 1);
665 	cr_assert_eq(ret, 1);
666 
667 	cr_assert(cq_priv->events->free_list.head);
668 	cr_assert(!cq_priv->events->item_list.head);
669 
670 	expected.len *= 2;
671 	cq_add_read_check(format, &entry, &expected);
672 }
673 
674 /*
675  * Read more than one cqe at a time.
676  */
cq_multi_read_test(enum fi_cq_format format)677 static void cq_multi_read_test(enum fi_cq_format format)
678 {
679 	int ret = 0;
680 	size_t count = 3;
681 	char input_ctx = 'a';
682 	struct fi_cq_tagged_entry entry[count]; /* biggest one */
683 	struct fi_cq_tagged_entry expected = { &input_ctx, 2, 4, (void *) 8,
684 					       16, 32 };
685 
686 	cq_add_read_setup(format);
687 
688 	cr_assert(cq_priv->events->free_list.head);
689 	cr_assert(!cq_priv->events->item_list.head);
690 
691 	for (size_t i = 0; i < count; i++) {
692 		_gnix_cq_add_event(cq_priv, NULL, expected.op_context,
693 				   expected.flags, expected.len,
694 				   expected.buf, expected.data,
695 				   expected.tag, 0x0);
696 	}
697 
698 	cr_assert(cq_priv->events->item_list.head);
699 
700 	ret = fi_cq_read(rcq, &entry, count);
701 	cr_assert_eq(ret, count);
702 
703 	for (size_t j = 0; j < count; j++) {
704 		/* This is gross */
705 		switch (format) {
706 		default:
707 		case FI_CQ_FORMAT_UNSPEC:
708 		{
709 			struct fi_cq_entry *e = (struct fi_cq_entry *) entry;
710 
711 			cq_add_read_check(format,
712 					  (struct fi_cq_tagged_entry *) &e[j],
713 					  &expected);
714 			break;
715 		}
716 		case FI_CQ_FORMAT_MSG:
717 		{
718 			struct fi_cq_msg_entry *e =
719 				(struct fi_cq_msg_entry *) entry;
720 
721 			cq_add_read_check(format,
722 					  (struct fi_cq_tagged_entry *) &e[j],
723 					  &expected);
724 			break;
725 		}
726 		case FI_CQ_FORMAT_DATA:
727 		{
728 			struct fi_cq_data_entry *e =
729 				(struct fi_cq_data_entry *) entry;
730 
731 			cq_add_read_check(format,
732 					  (struct fi_cq_tagged_entry *) &e[j],
733 					  &expected);
734 			break;
735 		}
736 		case FI_CQ_FORMAT_TAGGED:
737 		{
738 			cq_add_read_check(format, &entry[j], &expected);
739 			break;
740 		}
741 		}
742 	}
743 }
744 
745 TestSuite(check_cqe, .init = NULL, .fini = cq_teardown);
746 
Test(check_cqe,context)747 Test(check_cqe, context) {
748 	cq_add_read(FI_CQ_FORMAT_CONTEXT);
749 }
750 
Test(check_cqe,context_fill)751 Test(check_cqe, context_fill) {
752 	cq_fill_test(FI_CQ_FORMAT_CONTEXT);
753 }
754 
Test(check_cqe,context_multi_read)755 Test(check_cqe, context_multi_read) {
756 	cq_multi_read_test(FI_CQ_FORMAT_CONTEXT);
757 }
758 
Test(check_cqe,msg)759 Test(check_cqe, msg) {
760 	cq_add_read(FI_CQ_FORMAT_MSG);
761 }
762 
Test(check_cqe,msg_fill)763 Test(check_cqe, msg_fill) {
764 	cq_fill_test(FI_CQ_FORMAT_MSG);
765 }
766 
Test(check_cqe,msg_multi_read)767 Test(check_cqe, msg_multi_read) {
768 	cq_multi_read_test(FI_CQ_FORMAT_MSG);
769 }
770 
Test(check_cqe,data)771 Test(check_cqe, data) {
772 	cq_add_read(FI_CQ_FORMAT_DATA);
773 }
774 
Test(check_cqe,data_fill)775 Test(check_cqe, data_fill) {
776 	cq_fill_test(FI_CQ_FORMAT_DATA);
777 }
778 
Test(check_cqe,data_multi_read)779 Test(check_cqe, data_multi_read) {
780 	cq_multi_read_test(FI_CQ_FORMAT_DATA);
781 }
782 
Test(check_cqe,tagged)783 Test(check_cqe, tagged) {
784 	cq_add_read(FI_CQ_FORMAT_TAGGED);
785 }
786 
Test(check_cqe,tagged_fill)787 Test(check_cqe, tagged_fill) {
788 	cq_fill_test(FI_CQ_FORMAT_TAGGED);
789 }
790 
Test(check_cqe,tagged_multi_read)791 Test(check_cqe, tagged_multi_read) {
792 	cq_multi_read_test(FI_CQ_FORMAT_TAGGED);
793 }
794 
795 /* This test should be combined with cq_multi_read_test above when
796  * wait object are implemented.
797  */
798 Test(cq_msg, multi_sread, .init = cq_wait_unspec_setup, .disabled = false)
799 {
800 	int ret = 0;
801 	size_t count = 3;
802 	struct fi_cq_msg_entry entry[count];
803 
804 	cr_assert(cq_priv->events->free_list.head);
805 	cr_assert(!cq_priv->events->item_list.head);
806 
807 	ret = fi_cq_sread(rcq, &entry, count, NULL, 100);
808 	cr_assert_eq(ret, -FI_EAGAIN);
809 
810 	for (size_t i = 0; i < count; i++)
811 		_gnix_cq_add_event(cq_priv, NULL, 0, (uint64_t) i, 0, 0, 0, 0, 0);
812 
813 	cr_assert(cq_priv->events->item_list.head);
814 
815 	ret = fi_cq_sread(rcq, &entry, count, NULL, -1);
816 	cr_assert_eq(ret, count);
817 
818 	for (size_t j = 0; j < count; j++)
819 		cr_assert_eq(entry[j].flags, (uint64_t) j);
820 }
821 
822 TestSuite(cq_wait_obj, .fini = cq_teardown);
823 TestSuite(cq_wait_control, .fini = cq_teardown, .disabled = true);
824 TestSuite(cq_wait_ops, .fini = cq_teardown);
825 
826 Test(cq_wait_obj, none, .init = cq_wait_none_setup)
827 {
828 	cr_expect(!wait_priv, "wait_priv is not null.");
829 }
830 
831 Test(cq_wait_obj, unspec, .init = cq_wait_unspec_setup)
832 {
833 	cr_expect_eq(wait_priv->type, FI_WAIT_UNSPEC);
834 	cr_expect_eq(wait_priv->type, cq_priv->attr.wait_obj);
835 	cr_expect_eq(wait_priv->type, cq_attr.wait_obj);
836 	cr_expect_eq(&wait_priv->fabric->fab_fid, fab);
837 	cr_expect_eq(wait_priv->cond_type, FI_CQ_COND_NONE);
838 }
839 
840 Test(cq_wait_obj, fd, .init = cq_wait_fd_setup, .disabled = true)
841 {
842 	cr_expect_eq(wait_priv->type, FI_WAIT_FD);
843 	cr_expect_eq(wait_priv->type, cq_priv->attr.wait_obj);
844 	cr_expect_eq(wait_priv->type, cq_attr.wait_obj);
845 	cr_expect_eq(&wait_priv->fabric->fab_fid, fab);
846 	cr_expect_eq(wait_priv->cond_type, FI_CQ_COND_NONE);
847 }
848 
849 Test(cq_wait_obj, mutex_cond, .init = cq_wait_mutex_cond_setup, .disabled = true)
850 {
851 	cr_expect_eq(wait_priv->type, FI_WAIT_MUTEX_COND);
852 	cr_expect_eq(wait_priv->type, cq_priv->attr.wait_obj);
853 	cr_expect_eq(wait_priv->type, cq_attr.wait_obj);
854 	cr_expect_eq(&wait_priv->fabric->fab_fid, fab);
855 	cr_expect_eq(wait_priv->cond_type, FI_CQ_COND_NONE);
856 }
857 
858 Test(cq_wait_control, none, .init = cq_wait_none_setup)
859 {
860 	int ret;
861 	int fd;
862 
863 	ret = fi_control(&cq_priv->cq_fid.fid, FI_GETWAIT, &fd);
864 	cr_expect_eq(-FI_ENOSYS, ret, "fi_control exists for none.");
865 }
866 
867 Test(cq_wait_control, unspec, .init = cq_wait_unspec_setup, .disabled = true)
868 {
869 	int ret;
870 	int fd;
871 
872 	ret = fi_control(&cq_priv->cq_fid.fid, FI_GETWAIT, &fd);
873 	cr_expect_eq(FI_SUCCESS, ret, "fi_control failed.");
874 
875 	cr_expect_eq(wait_priv->fd[WAIT_READ], fd);
876 }
877 
878 Test(cq_wait_control, fd, .init = cq_wait_fd_setup,
879 	.disabled = true)
880 {
881 	int ret;
882 	int fd;
883 
884 	ret = fi_control(&cq_priv->cq_fid.fid, FI_GETWAIT, &fd);
885 	cr_expect_eq(FI_SUCCESS, ret, "fi_control failed.");
886 
887 	cr_expect_eq(wait_priv->fd[WAIT_READ], fd);
888 }
889 
890 Test(cq_wait_control, mutex_cond, .init = cq_wait_mutex_cond_setup,
891 	.disabled = true)
892 {
893 	int ret;
894 	struct fi_mutex_cond mutex_cond;
895 
896 	ret = fi_control(&cq_priv->cq_fid.fid, FI_GETWAIT, &mutex_cond);
897 	cr_expect_eq(FI_SUCCESS, ret, "fi_control failed.");
898 
899 	ret = memcmp(&wait_priv->mutex, mutex_cond.mutex,
900 		     sizeof(*mutex_cond.mutex));
901 	cr_expect_eq(0, ret, "mutex compare failed.");
902 
903 	ret = memcmp(&wait_priv->cond, mutex_cond.cond,
904 		     sizeof(*mutex_cond.cond));
905 	cr_expect_eq(0, ret, "cond compare failed.");
906 }
907 
908 Test(cq_wait_ops, none, .init = cq_wait_none_setup)
909 {
910 	cr_expect_eq(cq_priv->cq_fid.ops->signal, fi_no_cq_signal,
911 		     "signal implementation available.");
912 	cr_expect_eq(cq_priv->cq_fid.ops->sread, fi_no_cq_sread,
913 		     "sread implementation available.");
914 	cr_expect_eq(cq_priv->cq_fid.ops->sreadfrom, fi_no_cq_sreadfrom,
915 		     "sreadfrom implementation available.");
916 	cr_expect_eq(cq_priv->cq_fid.fid.ops->control, fi_no_control,
917 		     "control implementation available.");
918 }
919 
920 Test(cq_wait_ops, fd, .init = cq_wait_fd_setup, .disabled = true)
921 {
922 	cr_expect_neq(cq_priv->cq_fid.ops->signal, fi_no_cq_signal,
923 		      "signal implementation not available.");
924 	cr_expect_neq(cq_priv->cq_fid.fid.ops->control, fi_no_control,
925 		      "control implementation not available.");
926 }
927 
928 Test(cq_wait_set, fd, .init = setup, .disabled = true)
929 {
930 	int ret;
931 	int fd;
932 
933 	wait_attr.wait_obj = FI_WAIT_FD;
934 
935 	ret = fi_wait_open(fab, &wait_attr, &wait_set);
936 	cr_expect_eq(FI_SUCCESS, ret, "fi_wait_open failed.");
937 
938 	wait_priv = container_of(wait_set, struct gnix_fid_wait, wait);
939 
940 	cq_attr.format = FI_CQ_FORMAT_MSG;
941 	cq_attr.size = 8;
942 	cq_attr.wait_obj = FI_WAIT_SET;
943 	cq_attr.wait_set = wait_set;
944 
945 	ret = fi_cq_open(dom, &cq_attr, &rcq, NULL);
946 	cr_expect_eq(FI_SUCCESS, ret, "fi_cq_open failed.");
947 
948 	cq_priv = container_of(rcq, struct gnix_fid_cq, cq_fid);
949 
950 	ret = fi_control(&cq_priv->cq_fid.fid, FI_GETWAIT, &fd);
951 	cr_expect_eq(FI_SUCCESS, ret, "fi_control failed.");
952 
953 	cr_expect_eq(wait_priv->fd[WAIT_READ], fd);
954 
955 	ret = fi_close(&rcq->fid);
956 	cr_expect_eq(FI_SUCCESS, ret, "failure in closing cq.");
957 
958 	ret = fi_close(&wait_set->fid);
959 	cr_expect_eq(FI_SUCCESS, ret, "failure in closing waitset.");
960 
961 	teardown();
962 }
963 
964 TestSuite(cq_notify_flags, .init = cq_notify_setup, .fini = cq_notify_teardown);
965 
do_cq_notify(uint64_t flags)966 void do_cq_notify(uint64_t flags)
967 {
968 	ssize_t ret;
969 	struct fi_cq_msg_entry entry;
970 
971 	ret = _gnix_cq_add_event(cq_priv, ep, NULL, flags, 0, NULL,
972 				 0, 0, 0);
973 	cr_assert(ret == FI_SUCCESS, "failing in _gnix_cq_add_event");
974 
975 	ret = fi_cq_read(rcq, &entry, 1);
976 	cr_assert(ret == 1, "failing in fi_cq_read");
977 
978 	if (flags & FI_RMA_EVENT) {
979 		flags &= (FI_REMOTE_READ | FI_REMOTE_WRITE |
980 			  FI_RMA | FI_REMOTE_CQ_DATA |
981 			  FI_MULTI_RECV);
982 	} else {
983 		flags &= (FI_REMOTE_CQ_DATA | FI_MULTI_RECV);
984 	}
985 
986 	cr_assert_eq(flags, entry.flags, "unexpected cq entry flags");
987 }
988 
Test(cq_notify_flags,fi_rma_event)989 Test(cq_notify_flags, fi_rma_event)
990 {
991 	do_cq_notify(FI_REMOTE_READ | FI_REMOTE_WRITE |
992 		     FI_RMA | FI_REMOTE_CQ_DATA |
993 		     FI_MULTI_RECV | FI_RMA_EVENT);
994 }
995 
Test(cq_notify_flags,not_fi_rma_event)996 Test(cq_notify_flags, not_fi_rma_event)
997 {
998 	do_cq_notify(~FI_RMA_EVENT);
999 }
1000 
1001 
1002 struct test_err {
1003 	int padding_1;
1004 	struct fi_cq_err_entry_1_0 error;
1005 	int padding_2;
1006 };
1007 
Test(reading_1_4,issue_ofiwg_3227)1008 Test(reading_1_4, issue_ofiwg_3227)
1009 {
1010 	struct test_err error_entry;
1011 	int ret = 0;
1012 	char input_ctx = 'a';
1013 	uint64_t flags = 0xb;
1014 	size_t len = sizeof(input_ctx);
1015 	void *buf = &input_ctx;
1016 	uint64_t data = 20;
1017 	uint64_t tag = 40;
1018 	size_t olen = 20;
1019 	int err = 50;
1020 	int prov_errno = 80;
1021 
1022 	/*
1023 	 * By default CQ start out with no error entries and no entries
1024 	 * in the error entry free list.
1025 	 */
1026 	cr_assert(!cq_priv->errors->item_list.head);
1027 	cr_assert(!cq_priv->errors->free_list.head);
1028 
1029 	_gnix_cq_add_error(cq_priv, &input_ctx, flags, len, buf, data, tag,
1030 		olen, err, prov_errno, 0, 0);
1031 
1032 	error_entry.padding_1 = 0xcafebabe;
1033 	error_entry.padding_2 = 0xcafed00d;
1034 
1035 	ret = fi_cq_readerr((struct fid_cq *) cq_priv,
1036 		(struct fi_cq_err_entry *) &error_entry.error, 0);
1037 	cr_assert_eq(ret, 1);
1038 
1039 	cr_assert_eq(error_entry.padding_1, 0xcafebabe);
1040 	cr_assert_eq(error_entry.padding_2, 0xcafed00d);
1041 }
1042