xref: /spdk/test/unit/lib/scsi/scsi_pr.c/scsi_pr_ut.c (revision b30d57cdad6d2bc75cc1e4e2ebbcebcb0d98dcfa)
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)
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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 static void
539 test_scsi2_reserve_release(void)
540 {
541 	struct spdk_scsi_task task = {0};
542 	uint8_t cdb[32] = {};
543 	int rc;
544 
545 	task.lun = &g_lun;
546 	task.target_port = &g_t_port_0;
547 	task.cdb = cdb;
548 
549 	ut_init_reservation_test();
550 
551 	/* Test Case: SPC2 RESERVE from Host A */
552 	task.initiator_port = &g_i_port_a;
553 	task.cdb[0] = SPDK_SPC2_RESERVE_10;
554 	rc = scsi2_reserve(&task, task.cdb);
555 	SPDK_CU_ASSERT_FATAL(rc == 0);
556 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder != NULL);
557 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.flags == SCSI_SPC2_RESERVE);
558 
559 	/* Test Case: READ command from Host B */
560 	task.initiator_port = &g_i_port_b;
561 	task.cdb[0] = SPDK_SBC_READ_10;
562 	task.status = 0;
563 	rc = scsi2_reserve_check(&task);
564 	SPDK_CU_ASSERT_FATAL(rc < 0);
565 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT);
566 
567 	/* Test Case: SPDK_SPC2_RELEASE10 command from Host B */
568 	task.initiator_port = &g_i_port_b;
569 	task.cdb[0] = SPDK_SPC2_RELEASE_10;
570 	task.status = 0;
571 	rc = scsi2_reserve_check(&task);
572 	SPDK_CU_ASSERT_FATAL(rc == 0);
573 
574 	rc = scsi2_release(&task);
575 	SPDK_CU_ASSERT_FATAL(rc == 0);
576 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder == NULL);
577 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.flags == 0);
578 
579 	/* Test Case: SPC2 RESERVE from Host B */
580 	task.initiator_port = &g_i_port_b;
581 	task.cdb[0] = SPDK_SPC2_RESERVE_10;
582 	rc = scsi2_reserve(&task, task.cdb);
583 	SPDK_CU_ASSERT_FATAL(rc == 0);
584 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder != NULL);
585 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.flags == SCSI_SPC2_RESERVE);
586 
587 	/* Test Case: READ command from Host B */
588 	task.initiator_port = &g_i_port_b;
589 	task.cdb[0] = SPDK_SBC_READ_10;
590 	rc = scsi2_reserve_check(&task);
591 	SPDK_CU_ASSERT_FATAL(rc == 0);
592 
593 	/* Test Case: SPDK_SPC2_RELEASE10 command from Host A */
594 	task.initiator_port = &g_i_port_a;
595 	task.cdb[0] = SPDK_SPC2_RELEASE_10;
596 
597 	rc = scsi2_release(&task);
598 	SPDK_CU_ASSERT_FATAL(rc == 0);
599 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder == NULL);
600 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.flags == 0);
601 
602 	ut_deinit_reservation_test();
603 }
604 
605 static void
606 test_pr_with_scsi2_reserve_release(void)
607 {
608 	struct spdk_scsi_task task = {0};
609 	uint8_t cdb[32] = {};
610 	int rc;
611 
612 	task.lun = &g_lun;
613 	task.target_port = &g_t_port_0;
614 	task.cdb = cdb;
615 
616 	ut_init_reservation_test();
617 	test_build_registrants();
618 
619 	task.initiator_port = &g_i_port_a;
620 	task.status = 0;
621 	/* Test Case: Host A acquires the reservation */
622 	rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY,
623 				 0xa, 0, 0, 0);
624 	SPDK_CU_ASSERT_FATAL(rc == 0);
625 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY);
626 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa);
627 
628 	/* Test Case: SPDK_SPC2_RESERVE_10 command from Host B */
629 	task.initiator_port = &g_i_port_b;
630 	task.cdb[0] = SPDK_SPC2_RESERVE_10;
631 	/* SPC2 RESERVE/RELEASE will pass to scsi2_reserve/release */
632 	rc = scsi_pr_check(&task);
633 	SPDK_CU_ASSERT_FATAL(rc == 0);
634 
635 	/* do nothing with PR but have good status */
636 	rc = scsi2_reserve(&task, task.cdb);
637 	SPDK_CU_ASSERT_FATAL(rc == 0);
638 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder != NULL);
639 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY);
640 
641 	rc = scsi2_release(&task);
642 	SPDK_CU_ASSERT_FATAL(rc == 0);
643 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder != NULL);
644 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY);
645 
646 	ut_deinit_reservation_test();
647 }
648 
649 int
650 main(int argc, char **argv)
651 {
652 	CU_pSuite	suite = NULL;
653 	unsigned int	num_failures;
654 
655 	CU_set_error_action(CUEA_ABORT);
656 	CU_initialize_registry();
657 
658 	suite = CU_add_suite("reservation_suite", NULL, NULL);
659 	CU_ADD_TEST(suite, test_reservation_register);
660 	CU_ADD_TEST(suite, test_reservation_reserve);
661 	CU_ADD_TEST(suite, test_reservation_preempt_non_all_regs);
662 	CU_ADD_TEST(suite, test_reservation_preempt_all_regs);
663 	CU_ADD_TEST(suite, test_reservation_cmds_conflict);
664 	CU_ADD_TEST(suite, test_scsi2_reserve_release);
665 	CU_ADD_TEST(suite, test_pr_with_scsi2_reserve_release);
666 
667 	CU_basic_set_mode(CU_BRM_VERBOSE);
668 	CU_basic_run_tests();
669 	num_failures = CU_get_number_of_failures();
670 	CU_cleanup_registry();
671 	return num_failures;
672 
673 }
674