xref: /spdk/test/unit/lib/scsi/scsi_pr.c/scsi_pr_ut.c (revision 9889ab2dc80e40dae92dcef361d53dcba722043d)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "spdk/stdinc.h"
35 
36 #include "scsi/port.c"
37 #include "scsi/scsi_pr.c"
38 
39 #include "spdk_cunit.h"
40 
41 #include "spdk_internal/mock.h"
42 
43 SPDK_LOG_REGISTER_COMPONENT("scsi", SPDK_LOG_SCSI)
44 
45 void
46 spdk_scsi_task_set_status(struct spdk_scsi_task *task, int sc, int sk,
47 			  int asc, int ascq)
48 {
49 	task->status = sc;
50 }
51 
52 /*
53  * Reservation Unit Test Configuration
54  *
55  *  --------      --------      -------
56  * | Host A |    | Host B |    | Host C|
57  *  --------      --------      -------
58  *     |             |             |
59  *   ------        ------        ------
60  *  |Port A|      |Port B|      |Port C|
61  *   ------        ------        ------
62  *      \            |             /
63  *       \           |            /
64  *        \          |           /
65  *        ------------------------
66  *       |  Target Node 1 Port 0  |
67  *        ------------------------
68  *                   |
69  *   ----------------------------------
70  *  |           Target Node            |
71  *   ----------------------------------
72  *                  |
73  *                -----
74  *               |LUN 0|
75  *                -----
76  *
77  */
78 
79 static struct spdk_scsi_lun g_lun;
80 static struct spdk_scsi_port g_i_port_a;
81 static struct spdk_scsi_port g_i_port_b;
82 static struct spdk_scsi_port g_i_port_c;
83 static struct spdk_scsi_port g_t_port_0;
84 
85 static void
86 ut_lun_deinit(void)
87 {
88 	struct spdk_scsi_pr_registrant *reg, *tmp;
89 
90 	TAILQ_FOREACH_SAFE(reg, &g_lun.reg_head, link, tmp) {
91 		TAILQ_REMOVE(&g_lun.reg_head, reg, link);
92 		free(reg);
93 	}
94 	g_lun.reservation.rtype = 0;
95 	g_lun.reservation.crkey = 0;
96 	g_lun.reservation.holder = NULL;
97 	g_lun.pr_generation = 0;
98 }
99 
100 static void
101 ut_port_init(void)
102 {
103 	int rc;
104 
105 	/* g_i_port_a */
106 	rc = spdk_scsi_port_construct(&g_i_port_a, 0xa, 0,
107 				      "iqn.2016-06.io.spdk:fe5aacf7420a,i,0x00023d00000a");
108 	SPDK_CU_ASSERT_FATAL(rc == 0);
109 	spdk_scsi_port_set_iscsi_transport_id(&g_i_port_a,
110 					      "iqn.2016-06.io.spdk:fe5aacf7420a", 0x00023d00000a);
111 	/* g_i_port_b */
112 	rc = spdk_scsi_port_construct(&g_i_port_b, 0xb, 0,
113 				      "iqn.2016-06.io.spdk:fe5aacf7420b,i,0x00023d00000b");
114 	SPDK_CU_ASSERT_FATAL(rc == 0);
115 	spdk_scsi_port_set_iscsi_transport_id(&g_i_port_b,
116 					      "iqn.2016-06.io.spdk:fe5aacf7420b", 0x00023d00000b);
117 	/* g_i_port_c */
118 	rc = spdk_scsi_port_construct(&g_i_port_c, 0xc, 0,
119 				      "iqn.2016-06.io.spdk:fe5aacf7420c,i,0x00023d00000c");
120 	SPDK_CU_ASSERT_FATAL(rc == 0);
121 	spdk_scsi_port_set_iscsi_transport_id(&g_i_port_c,
122 					      "iqn.2016-06.io.spdk:fe5aacf7420c", 0x00023d00000c);
123 	/* g_t_port_0 */
124 	rc = spdk_scsi_port_construct(&g_t_port_0, 0x0, 1,
125 				      "iqn.2016-06.io.spdk:fe5aacf74200,t,0x00023d000000");
126 	SPDK_CU_ASSERT_FATAL(rc == 0);
127 	spdk_scsi_port_set_iscsi_transport_id(&g_t_port_0,
128 					      "iqn.2016-06.io.spdk:fe5aacf74200", 0x00023d000000);
129 }
130 
131 static void
132 ut_lun_init(void)
133 {
134 	TAILQ_INIT(&g_lun.reg_head);
135 }
136 
137 static void
138 ut_init_reservation_test(void)
139 {
140 	ut_lun_init();
141 	ut_port_init();
142 	ut_lun_init();
143 }
144 
145 static void
146 ut_deinit_reservation_test(void)
147 {
148 	ut_lun_deinit();
149 }
150 
151 /* Host A: register with key 0xa.
152  * Host B: register with key 0xb.
153  * Host C: register with key 0xc.
154  */
155 static void
156 test_build_registrants(void)
157 {
158 	struct spdk_scsi_pr_registrant *reg;
159 	struct spdk_scsi_task task = {0};
160 	uint32_t gen;
161 	int rc;
162 
163 	task.lun = &g_lun;
164 	task.target_port = &g_t_port_0;
165 
166 	gen = g_lun.pr_generation;
167 
168 	/* I_T nexus: Initiator Port A to Target Port 0 */
169 	task.initiator_port = &g_i_port_a;
170 	/* Test Case: Host A registers with a new key */
171 	task.status = 0;
172 	rc = spdk_scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER,
173 				       0x0, 0xa1, 0, 0, 0);
174 	SPDK_CU_ASSERT_FATAL(rc == 0);
175 	reg = spdk_scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0);
176 	SPDK_CU_ASSERT_FATAL(reg != NULL);
177 	SPDK_CU_ASSERT_FATAL(reg->rkey == 0xa1);
178 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1);
179 
180 	/* Test Case: Host A replaces with a new key */
181 	task.status = 0;
182 	rc = spdk_scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER,
183 				       0xa1, 0xa, 0, 0, 0);
184 	SPDK_CU_ASSERT_FATAL(rc == 0);
185 	reg = spdk_scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0);
186 	SPDK_CU_ASSERT_FATAL(reg != NULL);
187 	SPDK_CU_ASSERT_FATAL(reg->rkey == 0xa);
188 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 2);
189 
190 	/* Test Case: Host A replaces with a new key, reservation conflict is expected */
191 	task.status = 0;
192 	rc = spdk_scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER,
193 				       0xa1, 0xdead, 0, 0, 0);
194 	SPDK_CU_ASSERT_FATAL(rc < 0);
195 	reg = spdk_scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0);
196 	SPDK_CU_ASSERT_FATAL(reg != NULL);
197 	SPDK_CU_ASSERT_FATAL(reg->rkey == 0xa);
198 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 2);
199 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT);
200 
201 	/* I_T nexus: Initiator Port B to Target Port 0 */
202 	task.initiator_port = &g_i_port_b;
203 	/* Test Case: Host B registers with a new key */
204 	task.status = 0;
205 	rc = spdk_scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER,
206 				       0x0, 0xb, 0, 0, 0);
207 	SPDK_CU_ASSERT_FATAL(rc == 0);
208 	reg = spdk_scsi_pr_get_registrant(&g_lun, &g_i_port_b, &g_t_port_0);
209 	SPDK_CU_ASSERT_FATAL(reg != NULL);
210 	SPDK_CU_ASSERT_FATAL(reg->rkey == 0xb);
211 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 3);
212 
213 	/* I_T nexus: Initiator Port C to Target Port 0 */
214 	task.initiator_port = &g_i_port_c;
215 	/* Test Case: Host C registers with a new key */
216 	task.status = 0;
217 	rc = spdk_scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER,
218 				       0x0, 0xc, 0, 0, 0);
219 	SPDK_CU_ASSERT_FATAL(rc == 0);
220 	reg = spdk_scsi_pr_get_registrant(&g_lun, &g_i_port_c, &g_t_port_0);
221 	SPDK_CU_ASSERT_FATAL(reg != NULL);
222 	SPDK_CU_ASSERT_FATAL(reg->rkey == 0xc);
223 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 4);
224 }
225 
226 static void
227 test_reservation_register(void)
228 {
229 	ut_init_reservation_test();
230 
231 	test_build_registrants();
232 
233 	ut_deinit_reservation_test();
234 }
235 
236 static void
237 test_reservation_reserve(void)
238 {
239 	struct spdk_scsi_pr_registrant *reg;
240 	struct spdk_scsi_task task = {0};
241 	uint32_t gen;
242 	int rc;
243 
244 	task.lun = &g_lun;
245 	task.target_port = &g_t_port_0;
246 
247 	ut_init_reservation_test();
248 	test_build_registrants();
249 
250 	gen = g_lun.pr_generation;
251 
252 	task.initiator_port = &g_i_port_a;
253 	task.status = 0;
254 	/* Test Case: Host A acquires the reservation */
255 	rc = spdk_scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE,
256 				      0xa, 0, 0, 0);
257 	SPDK_CU_ASSERT_FATAL(rc == 0);
258 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE);
259 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa);
260 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen);
261 
262 	/* Test Case: Host B acquires the reservation, reservation
263 	 * conflict is expected.
264 	 */
265 	task.initiator_port = &g_i_port_b;
266 	task.status = 0;
267 	rc = spdk_scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE,
268 				      0xb, 0, 0, 0);
269 	SPDK_CU_ASSERT_FATAL(rc < 0);
270 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT);
271 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE);
272 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa);
273 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen);
274 
275 	/* Test Case: Host A unregister with reservation */
276 	task.initiator_port = &g_i_port_a;
277 	task.status = 0;
278 	rc = spdk_scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER,
279 				       0xa, 0, 0, 0, 0);
280 	SPDK_CU_ASSERT_FATAL(rc == 0);
281 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == 0);
282 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0);
283 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1);
284 	reg = spdk_scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0);
285 	SPDK_CU_ASSERT_FATAL(reg == NULL);
286 
287 	/* Test Case: Host B acquires the reservation */
288 	task.initiator_port = &g_i_port_b;
289 	task.status = 0;
290 	rc = spdk_scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS,
291 				      0xb, 0, 0, 0);
292 	SPDK_CU_ASSERT_FATAL(rc == 0);
293 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS);
294 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1);
295 
296 	/* Test Case: Host C acquires the reservation with invalid type */
297 	task.initiator_port = &g_i_port_c;
298 	task.status = 0;
299 	rc = spdk_scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE,
300 				      0xc, 0, 0, 0);
301 	SPDK_CU_ASSERT_FATAL(rc < 0);
302 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT);
303 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS);
304 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1);
305 
306 	/* Test Case: Host C acquires the reservation, all registrants type */
307 	task.status = 0;
308 	rc = spdk_scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS,
309 				      0xc, 0, 0, 0);
310 	SPDK_CU_ASSERT_FATAL(rc == 0);
311 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS);
312 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1);
313 
314 	ut_deinit_reservation_test();
315 }
316 
317 static void
318 test_reservation_preempt_non_all_regs(void)
319 {
320 	struct spdk_scsi_pr_registrant *reg;
321 	struct spdk_scsi_task task = {0};
322 	uint32_t gen;
323 	int rc;
324 
325 	task.lun = &g_lun;
326 	task.target_port = &g_t_port_0;
327 
328 	ut_init_reservation_test();
329 	test_build_registrants();
330 
331 	task.initiator_port = &g_i_port_a;
332 	task.status = 0;
333 	gen = g_lun.pr_generation;
334 	/* Host A acquires the reservation */
335 	rc = spdk_scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY,
336 				      0xa, 0, 0, 0);
337 	SPDK_CU_ASSERT_FATAL(rc == 0);
338 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY);
339 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa);
340 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen);
341 
342 	/* Test Case: Host B premmpts Host A, Check condition is expected
343 	 * for zeroed service action reservation key */
344 	task.initiator_port = &g_i_port_b;
345 	task.status = 0;
346 	rc = spdk_scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT,
347 				      SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY,
348 				      0xb, 0);
349 	SPDK_CU_ASSERT_FATAL(rc < 0);
350 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_CHECK_CONDITION);
351 
352 	/* Test Case: Host B preempts Host A, Host A is unregisted */
353 	task.status = 0;
354 	gen = g_lun.pr_generation;
355 	rc = spdk_scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT,
356 				      SPDK_SCSI_PR_WRITE_EXCLUSIVE,
357 				      0xb, 0xa);
358 	SPDK_CU_ASSERT_FATAL(rc == 0);
359 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE);
360 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xb);
361 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen);
362 	reg = spdk_scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0);
363 	SPDK_CU_ASSERT_FATAL(reg == NULL);
364 
365 	/* Test Case: Host B preempts itself */
366 	task.status = 0;
367 	gen = g_lun.pr_generation;
368 	rc = spdk_scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT,
369 				      SPDK_SCSI_PR_WRITE_EXCLUSIVE,
370 				      0xb, 0xb);
371 	SPDK_CU_ASSERT_FATAL(rc == 0);
372 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE);
373 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xb);
374 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen);
375 
376 	/* Test Case: Host B preempts itself and remove registrants */
377 	task.status = 0;
378 	gen = g_lun.pr_generation;
379 	rc = spdk_scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT,
380 				      SPDK_SCSI_PR_WRITE_EXCLUSIVE,
381 				      0xb, 0xc);
382 	SPDK_CU_ASSERT_FATAL(rc == 0);
383 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE);
384 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xb);
385 	reg = spdk_scsi_pr_get_registrant(&g_lun, &g_i_port_c, &g_t_port_0);
386 	SPDK_CU_ASSERT_FATAL(reg == NULL);
387 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen);
388 
389 	ut_deinit_reservation_test();
390 }
391 
392 static void
393 test_reservation_preempt_all_regs(void)
394 {
395 	struct spdk_scsi_pr_registrant *reg;
396 	struct spdk_scsi_task task = {0};
397 	uint32_t gen;
398 	int rc;
399 
400 	task.lun = &g_lun;
401 	task.target_port = &g_t_port_0;
402 
403 	ut_init_reservation_test();
404 	test_build_registrants();
405 
406 	/* Test Case: No reservation yet, Host B removes Host C's registrant */
407 	task.initiator_port = &g_i_port_b;
408 	task.status = 0;
409 	gen = g_lun.pr_generation;
410 	rc = spdk_scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT,
411 				      SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY,
412 				      0xb, 0xc);
413 	SPDK_CU_ASSERT_FATAL(rc == 0);
414 	reg = spdk_scsi_pr_get_registrant(&g_lun, &g_i_port_c, &g_t_port_0);
415 	SPDK_CU_ASSERT_FATAL(reg == NULL);
416 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen);
417 
418 	task.initiator_port = &g_i_port_a;
419 	task.status = 0;
420 	gen = g_lun.pr_generation;
421 	/* Host A acquires the reservation */
422 	rc = spdk_scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS,
423 				      0xa, 0, 0, 0);
424 	SPDK_CU_ASSERT_FATAL(rc == 0);
425 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS);
426 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen);
427 
428 	/* Test Case: Host B removes Host A's registrant and preempt */
429 	task.initiator_port = &g_i_port_b;
430 	task.status = 0;
431 	gen = g_lun.pr_generation;
432 	rc = spdk_scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT,
433 				      SPDK_SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS,
434 				      0xb, 0x0);
435 	SPDK_CU_ASSERT_FATAL(rc == 0);
436 	reg = spdk_scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0);
437 	SPDK_CU_ASSERT_FATAL(reg == NULL);
438 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS);
439 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen);
440 
441 	ut_deinit_reservation_test();
442 }
443 
444 static void
445 test_reservation_cmds_conflict(void)
446 {
447 	struct spdk_scsi_pr_registrant *reg;
448 	struct spdk_scsi_task task = {0};
449 	uint8_t cdb[32];
450 	int rc;
451 
452 	task.lun = &g_lun;
453 	task.target_port = &g_t_port_0;
454 	task.cdb = cdb;
455 
456 	ut_init_reservation_test();
457 	test_build_registrants();
458 
459 	/* Host A acquires the reservation */
460 	task.initiator_port = &g_i_port_a;
461 	rc = spdk_scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY,
462 				      0xa, 0, 0, 0);
463 	SPDK_CU_ASSERT_FATAL(rc == 0);
464 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY);
465 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa);
466 
467 	/* Remove Host B registrant */
468 	task.initiator_port = &g_i_port_b;
469 	task.status = 0;
470 	rc = spdk_scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER,
471 				       0xb, 0, 0, 0, 0);
472 	SPDK_CU_ASSERT_FATAL(rc == 0);
473 	reg = spdk_scsi_pr_get_registrant(&g_lun, &g_i_port_b, &g_t_port_0);
474 	SPDK_CU_ASSERT_FATAL(reg == NULL);
475 
476 	/* Test Case: Host B sends Read/Write commands,
477 	 * reservation conflict is expected.
478 	 */
479 	task.cdb[0] = SPDK_SBC_READ_10;
480 	task.status = 0;
481 	rc = spdk_scsi_pr_check(&task);
482 	SPDK_CU_ASSERT_FATAL(rc == 0);
483 	task.cdb[0] = SPDK_SBC_WRITE_10;
484 	task.status = 0;
485 	rc = spdk_scsi_pr_check(&task);
486 	SPDK_CU_ASSERT_FATAL(rc < 0);
487 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT);
488 
489 	/* Test Case: Host C sends Read/Write commands */
490 	task.initiator_port = &g_i_port_c;
491 	task.cdb[0] = SPDK_SBC_READ_10;
492 	task.status = 0;
493 	rc = spdk_scsi_pr_check(&task);
494 	SPDK_CU_ASSERT_FATAL(rc == 0);
495 	task.cdb[0] = SPDK_SBC_WRITE_10;
496 	task.status = 0;
497 	rc = spdk_scsi_pr_check(&task);
498 	SPDK_CU_ASSERT_FATAL(rc == 0);
499 
500 	/* Host A preempts itself with SPDK_SCSI_PR_EXCLUSIVE_ACCESS */
501 	task.initiator_port = &g_i_port_a;
502 	rc = spdk_scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT,
503 				      SPDK_SCSI_PR_EXCLUSIVE_ACCESS,
504 				      0xa, 0xa);
505 	SPDK_CU_ASSERT_FATAL(rc == 0);
506 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_EXCLUSIVE_ACCESS);
507 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa);
508 
509 	/* Test Case: Host C sends Read/Write commands */
510 	task.initiator_port = &g_i_port_c;
511 	task.cdb[0] = SPDK_SBC_READ_10;
512 	task.status = 0;
513 	rc = spdk_scsi_pr_check(&task);
514 	SPDK_CU_ASSERT_FATAL(rc < 0);
515 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT);
516 	task.cdb[0] = SPDK_SBC_WRITE_10;
517 	task.status = 0;
518 	rc = spdk_scsi_pr_check(&task);
519 	SPDK_CU_ASSERT_FATAL(rc < 0);
520 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT);
521 
522 	/* Test Case: Host B sends Read/Write commands */
523 	task.initiator_port = &g_i_port_b;
524 	task.cdb[0] = SPDK_SBC_READ_10;
525 	task.status = 0;
526 	rc = spdk_scsi_pr_check(&task);
527 	SPDK_CU_ASSERT_FATAL(rc < 0);
528 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT);
529 	task.cdb[0] = SPDK_SBC_WRITE_10;
530 	task.status = 0;
531 	rc = spdk_scsi_pr_check(&task);
532 	SPDK_CU_ASSERT_FATAL(rc < 0);
533 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT);
534 
535 	ut_deinit_reservation_test();
536 }
537 
538 int
539 main(int argc, char **argv)
540 {
541 	CU_pSuite	suite = NULL;
542 	unsigned int	num_failures;
543 
544 	if (CU_initialize_registry() != CUE_SUCCESS) {
545 		return CU_get_error();
546 	}
547 
548 	suite = CU_add_suite("reservation_suite", NULL, NULL);
549 	if (suite == NULL) {
550 		CU_cleanup_registry();
551 		return CU_get_error();
552 	}
553 
554 	if (CU_add_test(suite, "register", test_reservation_register) == NULL ||
555 	    CU_add_test(suite, "reserve", test_reservation_reserve) == NULL ||
556 	    CU_add_test(suite, "preempt", test_reservation_preempt_non_all_regs) == NULL ||
557 	    CU_add_test(suite, "preempt all regs", test_reservation_preempt_all_regs) == NULL ||
558 	    CU_add_test(suite, "conflict", test_reservation_cmds_conflict) == NULL) {
559 		CU_cleanup_registry();
560 		return CU_get_error();
561 	}
562 
563 	CU_basic_set_mode(CU_BRM_VERBOSE);
564 	CU_basic_run_tests();
565 	num_failures = CU_get_number_of_failures();
566 	CU_cleanup_registry();
567 	return num_failures;
568 
569 }
570