xref: /spdk/test/unit/lib/scsi/scsi_pr.c/scsi_pr_ut.c (revision 60982c759db49b4f4579f16e3b24df0725ba4b94)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2019 Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #include "spdk/stdinc.h"
7 
8 #include "scsi/port.c"
9 #include "scsi/scsi_pr.c"
10 
11 #include "spdk_internal/cunit.h"
12 
13 #include "spdk_internal/mock.h"
14 
15 SPDK_LOG_REGISTER_COMPONENT(scsi)
16 
17 void
18 spdk_scsi_task_set_status(struct spdk_scsi_task *task, int sc, int sk,
19 			  int asc, int ascq)
20 {
21 	task->status = sc;
22 }
23 
24 /*
25  * Reservation Unit Test Configuration
26  *
27  *  --------      --------      -------
28  * | Host A |    | Host B |    | Host C|
29  *  --------      --------      -------
30  *     |             |             |
31  *   ------        ------        ------
32  *  |Port A|      |Port B|      |Port C|
33  *   ------        ------        ------
34  *      \            |             /
35  *       \           |            /
36  *        \          |           /
37  *        ------------------------
38  *       |  Target Node 1 Port 0  |
39  *        ------------------------
40  *                   |
41  *   ----------------------------------
42  *  |           Target Node            |
43  *   ----------------------------------
44  *                  |
45  *                -----
46  *               |LUN 0|
47  *                -----
48  *
49  */
50 
51 static struct spdk_scsi_lun g_lun;
52 static struct spdk_scsi_port g_i_port_a;
53 static struct spdk_scsi_port g_i_port_b;
54 static struct spdk_scsi_port g_i_port_c;
55 static struct spdk_scsi_port g_t_port_0;
56 
57 static void
58 ut_lun_deinit(void)
59 {
60 	struct spdk_scsi_pr_registrant *reg, *tmp;
61 
62 	TAILQ_FOREACH_SAFE(reg, &g_lun.reg_head, link, tmp) {
63 		TAILQ_REMOVE(&g_lun.reg_head, reg, link);
64 		free(reg);
65 	}
66 	g_lun.reservation.rtype = 0;
67 	g_lun.reservation.crkey = 0;
68 	g_lun.reservation.holder = NULL;
69 	g_lun.pr_generation = 0;
70 }
71 
72 static void
73 ut_port_init(void)
74 {
75 	int rc;
76 
77 	/* g_i_port_a */
78 	rc = scsi_port_construct(&g_i_port_a, 0xa, 0,
79 				 "iqn.2016-06.io.spdk:fe5aacf7420a,i,0x00023d00000a");
80 	SPDK_CU_ASSERT_FATAL(rc == 0);
81 	spdk_scsi_port_set_iscsi_transport_id(&g_i_port_a,
82 					      "iqn.2016-06.io.spdk:fe5aacf7420a", 0x00023d00000a);
83 	/* g_i_port_b */
84 	rc = scsi_port_construct(&g_i_port_b, 0xb, 0,
85 				 "iqn.2016-06.io.spdk:fe5aacf7420b,i,0x00023d00000b");
86 	SPDK_CU_ASSERT_FATAL(rc == 0);
87 	spdk_scsi_port_set_iscsi_transport_id(&g_i_port_b,
88 					      "iqn.2016-06.io.spdk:fe5aacf7420b", 0x00023d00000b);
89 	/* g_i_port_c */
90 	rc = scsi_port_construct(&g_i_port_c, 0xc, 0,
91 				 "iqn.2016-06.io.spdk:fe5aacf7420c,i,0x00023d00000c");
92 	SPDK_CU_ASSERT_FATAL(rc == 0);
93 	spdk_scsi_port_set_iscsi_transport_id(&g_i_port_c,
94 					      "iqn.2016-06.io.spdk:fe5aacf7420c", 0x00023d00000c);
95 	/* g_t_port_0 */
96 	rc = scsi_port_construct(&g_t_port_0, 0x0, 1,
97 				 "iqn.2016-06.io.spdk:fe5aacf74200,t,0x00023d000000");
98 	SPDK_CU_ASSERT_FATAL(rc == 0);
99 	spdk_scsi_port_set_iscsi_transport_id(&g_t_port_0,
100 					      "iqn.2016-06.io.spdk:fe5aacf74200", 0x00023d000000);
101 }
102 
103 static void
104 ut_lun_init(void)
105 {
106 	TAILQ_INIT(&g_lun.reg_head);
107 }
108 
109 static void
110 ut_init_reservation_test(void)
111 {
112 	ut_lun_init();
113 	ut_port_init();
114 	ut_lun_init();
115 }
116 
117 static void
118 ut_deinit_reservation_test(void)
119 {
120 	ut_lun_deinit();
121 }
122 
123 /* Host A: register with key 0xa.
124  * Host B: register with key 0xb.
125  * Host C: register with key 0xc.
126  */
127 static void
128 test_build_registrants(void)
129 {
130 	struct spdk_scsi_pr_registrant *reg;
131 	struct spdk_scsi_task task = {0};
132 	uint32_t gen;
133 	int rc;
134 
135 	task.lun = &g_lun;
136 	task.target_port = &g_t_port_0;
137 
138 	gen = g_lun.pr_generation;
139 
140 	/* I_T nexus: Initiator Port A to Target Port 0 */
141 	task.initiator_port = &g_i_port_a;
142 	/* Test Case: Host A registers with a new key */
143 	task.status = 0;
144 	rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER,
145 				  0x0, 0xa1, 0, 0, 0);
146 	SPDK_CU_ASSERT_FATAL(rc == 0);
147 	reg = scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0);
148 	SPDK_CU_ASSERT_FATAL(reg != NULL);
149 	SPDK_CU_ASSERT_FATAL(reg->rkey == 0xa1);
150 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1);
151 
152 	/* Test Case: Host A replaces with a new key */
153 	task.status = 0;
154 	rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER,
155 				  0xa1, 0xa, 0, 0, 0);
156 	SPDK_CU_ASSERT_FATAL(rc == 0);
157 	reg = scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0);
158 	SPDK_CU_ASSERT_FATAL(reg != NULL);
159 	SPDK_CU_ASSERT_FATAL(reg->rkey == 0xa);
160 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 2);
161 
162 	/* Test Case: Host A replaces with a new key, reservation conflict is expected */
163 	task.status = 0;
164 	rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER,
165 				  0xa1, 0xdead, 0, 0, 0);
166 	SPDK_CU_ASSERT_FATAL(rc < 0);
167 	reg = scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0);
168 	SPDK_CU_ASSERT_FATAL(reg != NULL);
169 	SPDK_CU_ASSERT_FATAL(reg->rkey == 0xa);
170 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 2);
171 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT);
172 
173 	/* I_T nexus: Initiator Port B to Target Port 0 */
174 	task.initiator_port = &g_i_port_b;
175 	/* Test Case: Host B registers with a new key */
176 	task.status = 0;
177 	rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER,
178 				  0x0, 0xb, 0, 0, 0);
179 	SPDK_CU_ASSERT_FATAL(rc == 0);
180 	reg = scsi_pr_get_registrant(&g_lun, &g_i_port_b, &g_t_port_0);
181 	SPDK_CU_ASSERT_FATAL(reg != NULL);
182 	SPDK_CU_ASSERT_FATAL(reg->rkey == 0xb);
183 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 3);
184 
185 	/* I_T nexus: Initiator Port C to Target Port 0 */
186 	task.initiator_port = &g_i_port_c;
187 	/* Test Case: Host C registers with a new key */
188 	task.status = 0;
189 	rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER,
190 				  0x0, 0xc, 0, 0, 0);
191 	SPDK_CU_ASSERT_FATAL(rc == 0);
192 	reg = scsi_pr_get_registrant(&g_lun, &g_i_port_c, &g_t_port_0);
193 	SPDK_CU_ASSERT_FATAL(reg != NULL);
194 	SPDK_CU_ASSERT_FATAL(reg->rkey == 0xc);
195 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 4);
196 }
197 
198 static void
199 test_reservation_register(void)
200 {
201 	ut_init_reservation_test();
202 
203 	test_build_registrants();
204 
205 	ut_deinit_reservation_test();
206 }
207 
208 static void
209 test_reservation_reserve(void)
210 {
211 	struct spdk_scsi_pr_registrant *reg;
212 	struct spdk_scsi_task task = {0};
213 	uint32_t gen;
214 	int rc;
215 
216 	task.lun = &g_lun;
217 	task.target_port = &g_t_port_0;
218 
219 	ut_init_reservation_test();
220 	/* Test Case: call Release without a reservation */
221 	rc = scsi2_release(&task);
222 	CU_ASSERT(rc == -EINVAL);
223 	CU_ASSERT(task.status == SPDK_SCSI_STATUS_CHECK_CONDITION);
224 
225 	test_build_registrants();
226 
227 	gen = g_lun.pr_generation;
228 
229 	task.initiator_port = &g_i_port_a;
230 	task.status = 0;
231 	/* Test Case: Host A acquires the reservation */
232 	rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE,
233 				 0xa, 0, 0, 0);
234 	SPDK_CU_ASSERT_FATAL(rc == 0);
235 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE);
236 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa);
237 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen);
238 
239 	/* Test Case: Host B acquires the reservation, reservation
240 	 * conflict is expected.
241 	 */
242 	task.initiator_port = &g_i_port_b;
243 	task.status = 0;
244 	rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE,
245 				 0xb, 0, 0, 0);
246 	SPDK_CU_ASSERT_FATAL(rc < 0);
247 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT);
248 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE);
249 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa);
250 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen);
251 
252 	/* Test Case: Host A unregister with reservation */
253 	task.initiator_port = &g_i_port_a;
254 	task.status = 0;
255 	rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER,
256 				  0xa, 0, 0, 0, 0);
257 	SPDK_CU_ASSERT_FATAL(rc == 0);
258 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == 0);
259 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0);
260 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1);
261 	reg = scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0);
262 	SPDK_CU_ASSERT_FATAL(reg == NULL);
263 
264 	/* Test Case: Host B acquires the reservation */
265 	task.initiator_port = &g_i_port_b;
266 	task.status = 0;
267 	rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS,
268 				 0xb, 0, 0, 0);
269 	SPDK_CU_ASSERT_FATAL(rc == 0);
270 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS);
271 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1);
272 
273 	/* Test Case: Host C acquires the reservation with invalid type */
274 	task.initiator_port = &g_i_port_c;
275 	task.status = 0;
276 	rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE,
277 				 0xc, 0, 0, 0);
278 	SPDK_CU_ASSERT_FATAL(rc < 0);
279 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT);
280 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS);
281 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1);
282 
283 	/* Test Case: Host C acquires the reservation, all registrants type */
284 	task.status = 0;
285 	rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS,
286 				 0xc, 0, 0, 0);
287 	SPDK_CU_ASSERT_FATAL(rc == 0);
288 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS);
289 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1);
290 
291 	ut_deinit_reservation_test();
292 }
293 
294 static void
295 test_reservation_preempt_non_all_regs(void)
296 {
297 	struct spdk_scsi_pr_registrant *reg;
298 	struct spdk_scsi_task task = {0};
299 	uint32_t gen;
300 	int rc;
301 
302 	task.lun = &g_lun;
303 	task.target_port = &g_t_port_0;
304 
305 	ut_init_reservation_test();
306 	test_build_registrants();
307 
308 	task.initiator_port = &g_i_port_a;
309 	task.status = 0;
310 	gen = g_lun.pr_generation;
311 	/* Host A acquires the reservation */
312 	rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY,
313 				 0xa, 0, 0, 0);
314 	SPDK_CU_ASSERT_FATAL(rc == 0);
315 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY);
316 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa);
317 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen);
318 
319 	/* Test Case: Host B preempts Host A, Check condition is expected
320 	 * for zeroed service action reservation key */
321 	task.initiator_port = &g_i_port_b;
322 	task.status = 0;
323 	rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT,
324 				 SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY,
325 				 0xb, 0);
326 	SPDK_CU_ASSERT_FATAL(rc < 0);
327 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_CHECK_CONDITION);
328 
329 	/* Test Case: Host B preempts Host A, Host A is unregistered */
330 	task.status = 0;
331 	gen = g_lun.pr_generation;
332 	rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT,
333 				 SPDK_SCSI_PR_WRITE_EXCLUSIVE,
334 				 0xb, 0xa);
335 	SPDK_CU_ASSERT_FATAL(rc == 0);
336 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE);
337 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xb);
338 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen);
339 	reg = scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0);
340 	SPDK_CU_ASSERT_FATAL(reg == NULL);
341 
342 	/* Test Case: Host B preempts itself */
343 	task.status = 0;
344 	gen = g_lun.pr_generation;
345 	rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT,
346 				 SPDK_SCSI_PR_WRITE_EXCLUSIVE,
347 				 0xb, 0xb);
348 	SPDK_CU_ASSERT_FATAL(rc == 0);
349 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE);
350 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xb);
351 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen);
352 
353 	/* Test Case: Host B preempts itself and remove registrants */
354 	task.status = 0;
355 	gen = g_lun.pr_generation;
356 	rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT,
357 				 SPDK_SCSI_PR_WRITE_EXCLUSIVE,
358 				 0xb, 0xc);
359 	SPDK_CU_ASSERT_FATAL(rc == 0);
360 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE);
361 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xb);
362 	reg = scsi_pr_get_registrant(&g_lun, &g_i_port_c, &g_t_port_0);
363 	SPDK_CU_ASSERT_FATAL(reg == NULL);
364 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen);
365 
366 	ut_deinit_reservation_test();
367 }
368 
369 static void
370 test_reservation_preempt_all_regs(void)
371 {
372 	struct spdk_scsi_pr_registrant *reg;
373 	struct spdk_scsi_task task = {0};
374 	uint32_t gen;
375 	int rc;
376 
377 	task.lun = &g_lun;
378 	task.target_port = &g_t_port_0;
379 
380 	ut_init_reservation_test();
381 	test_build_registrants();
382 
383 	/* Test Case: No reservation yet, Host B removes Host C's registrant */
384 	task.initiator_port = &g_i_port_b;
385 	task.status = 0;
386 	gen = g_lun.pr_generation;
387 	rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT,
388 				 SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY,
389 				 0xb, 0xc);
390 	SPDK_CU_ASSERT_FATAL(rc == 0);
391 	reg = scsi_pr_get_registrant(&g_lun, &g_i_port_c, &g_t_port_0);
392 	SPDK_CU_ASSERT_FATAL(reg == NULL);
393 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen);
394 
395 	task.initiator_port = &g_i_port_a;
396 	task.status = 0;
397 	gen = g_lun.pr_generation;
398 	/* Host A acquires the reservation */
399 	rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS,
400 				 0xa, 0, 0, 0);
401 	SPDK_CU_ASSERT_FATAL(rc == 0);
402 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS);
403 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen);
404 
405 	/* Test Case: Host B removes Host A's registrant and preempt */
406 	task.initiator_port = &g_i_port_b;
407 	task.status = 0;
408 	gen = g_lun.pr_generation;
409 	rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT,
410 				 SPDK_SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS,
411 				 0xb, 0x0);
412 	SPDK_CU_ASSERT_FATAL(rc == 0);
413 	reg = scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0);
414 	SPDK_CU_ASSERT_FATAL(reg == NULL);
415 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS);
416 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen);
417 
418 	ut_deinit_reservation_test();
419 }
420 
421 static void
422 test_reservation_cmds_conflict(void)
423 {
424 	struct spdk_scsi_pr_registrant *reg;
425 	struct spdk_scsi_task task = {0};
426 	uint8_t cdb[32];
427 	int rc;
428 
429 	task.lun = &g_lun;
430 	task.target_port = &g_t_port_0;
431 	task.cdb = cdb;
432 
433 	ut_init_reservation_test();
434 	test_build_registrants();
435 
436 	/* Host A acquires the reservation */
437 	task.initiator_port = &g_i_port_a;
438 	rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY,
439 				 0xa, 0, 0, 0);
440 	SPDK_CU_ASSERT_FATAL(rc == 0);
441 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY);
442 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa);
443 
444 	/* Remove Host B registrant */
445 	task.initiator_port = &g_i_port_b;
446 	task.status = 0;
447 	rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER,
448 				  0xb, 0, 0, 0, 0);
449 	SPDK_CU_ASSERT_FATAL(rc == 0);
450 	reg = scsi_pr_get_registrant(&g_lun, &g_i_port_b, &g_t_port_0);
451 	SPDK_CU_ASSERT_FATAL(reg == NULL);
452 
453 	/* Test Case: Host B sends Read/Write commands,
454 	 * reservation conflict is expected.
455 	 */
456 	task.cdb[0] = SPDK_SBC_READ_10;
457 	task.status = 0;
458 	rc = scsi_pr_check(&task);
459 	SPDK_CU_ASSERT_FATAL(rc == 0);
460 	task.cdb[0] = SPDK_SBC_WRITE_10;
461 	task.status = 0;
462 	rc = scsi_pr_check(&task);
463 	SPDK_CU_ASSERT_FATAL(rc < 0);
464 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT);
465 
466 	/* Test Case: Host C sends Read/Write commands */
467 	task.initiator_port = &g_i_port_c;
468 	task.cdb[0] = SPDK_SBC_READ_10;
469 	task.status = 0;
470 	rc = scsi_pr_check(&task);
471 	SPDK_CU_ASSERT_FATAL(rc == 0);
472 	task.cdb[0] = SPDK_SBC_WRITE_10;
473 	task.status = 0;
474 	rc = scsi_pr_check(&task);
475 	SPDK_CU_ASSERT_FATAL(rc == 0);
476 
477 	/* Host A preempts itself with SPDK_SCSI_PR_EXCLUSIVE_ACCESS */
478 	task.initiator_port = &g_i_port_a;
479 	rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT,
480 				 SPDK_SCSI_PR_EXCLUSIVE_ACCESS,
481 				 0xa, 0xa);
482 	SPDK_CU_ASSERT_FATAL(rc == 0);
483 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_EXCLUSIVE_ACCESS);
484 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa);
485 
486 	/* Test Case: Host C sends Read/Write commands */
487 	task.initiator_port = &g_i_port_c;
488 	task.cdb[0] = SPDK_SBC_READ_10;
489 	task.status = 0;
490 	rc = scsi_pr_check(&task);
491 	SPDK_CU_ASSERT_FATAL(rc < 0);
492 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT);
493 	task.cdb[0] = SPDK_SBC_WRITE_10;
494 	task.status = 0;
495 	rc = scsi_pr_check(&task);
496 	SPDK_CU_ASSERT_FATAL(rc < 0);
497 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT);
498 
499 	/* Test Case: Host B sends Read/Write commands */
500 	task.initiator_port = &g_i_port_b;
501 	task.cdb[0] = SPDK_SBC_READ_10;
502 	task.status = 0;
503 	rc = scsi_pr_check(&task);
504 	SPDK_CU_ASSERT_FATAL(rc < 0);
505 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT);
506 	task.cdb[0] = SPDK_SBC_WRITE_10;
507 	task.status = 0;
508 	rc = scsi_pr_check(&task);
509 	SPDK_CU_ASSERT_FATAL(rc < 0);
510 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT);
511 
512 	ut_deinit_reservation_test();
513 }
514 
515 static void
516 test_scsi2_reserve_release(void)
517 {
518 	struct spdk_scsi_task task = {0};
519 	uint8_t cdb[32] = {};
520 	int rc;
521 
522 	task.lun = &g_lun;
523 	task.target_port = &g_t_port_0;
524 	task.cdb = cdb;
525 
526 	ut_init_reservation_test();
527 
528 	/* Test Case: SPC2 RESERVE from Host A */
529 	task.initiator_port = &g_i_port_a;
530 	task.cdb[0] = SPDK_SPC2_RESERVE_10;
531 	rc = scsi2_reserve(&task, task.cdb);
532 	SPDK_CU_ASSERT_FATAL(rc == 0);
533 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder != NULL);
534 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.flags == SCSI_SPC2_RESERVE);
535 
536 	/* Test Case: READ command from Host B */
537 	task.initiator_port = &g_i_port_b;
538 	task.cdb[0] = SPDK_SBC_READ_10;
539 	task.status = 0;
540 	rc = scsi2_reserve_check(&task);
541 	SPDK_CU_ASSERT_FATAL(rc < 0);
542 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT);
543 
544 	/* Test Case: SPDK_SPC2_RELEASE10 command from Host B */
545 	task.initiator_port = &g_i_port_b;
546 	task.cdb[0] = SPDK_SPC2_RELEASE_10;
547 	task.status = 0;
548 	rc = scsi2_reserve_check(&task);
549 	SPDK_CU_ASSERT_FATAL(rc == 0);
550 
551 	rc = scsi2_release(&task);
552 	SPDK_CU_ASSERT_FATAL(rc == 0);
553 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder == NULL);
554 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.flags == 0);
555 
556 	/* Test Case: SPC2 RESERVE from Host B */
557 	task.initiator_port = &g_i_port_b;
558 	task.cdb[0] = SPDK_SPC2_RESERVE_10;
559 	rc = scsi2_reserve(&task, task.cdb);
560 	SPDK_CU_ASSERT_FATAL(rc == 0);
561 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder != NULL);
562 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.flags == SCSI_SPC2_RESERVE);
563 
564 	/* Test Case: READ command from Host B */
565 	task.initiator_port = &g_i_port_b;
566 	task.cdb[0] = SPDK_SBC_READ_10;
567 	rc = scsi2_reserve_check(&task);
568 	SPDK_CU_ASSERT_FATAL(rc == 0);
569 
570 	/* Test Case: SPDK_SPC2_RELEASE10 command from Host A */
571 	task.initiator_port = &g_i_port_a;
572 	task.cdb[0] = SPDK_SPC2_RELEASE_10;
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 	ut_deinit_reservation_test();
580 }
581 
582 static void
583 test_pr_with_scsi2_reserve_release(void)
584 {
585 	struct spdk_scsi_task task = {0};
586 	uint8_t cdb[32] = {};
587 	int rc;
588 
589 	task.lun = &g_lun;
590 	task.target_port = &g_t_port_0;
591 	task.cdb = cdb;
592 
593 	ut_init_reservation_test();
594 	test_build_registrants();
595 
596 	task.initiator_port = &g_i_port_a;
597 	task.status = 0;
598 	/* Test Case: Host A acquires the reservation */
599 	rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY,
600 				 0xa, 0, 0, 0);
601 	SPDK_CU_ASSERT_FATAL(rc == 0);
602 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY);
603 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa);
604 
605 	/* Test Case: SPDK_SPC2_RESERVE_10 command from Host B */
606 	task.initiator_port = &g_i_port_b;
607 	task.cdb[0] = SPDK_SPC2_RESERVE_10;
608 	/* SPC2 RESERVE/RELEASE will pass to scsi2_reserve/release */
609 	rc = scsi_pr_check(&task);
610 	SPDK_CU_ASSERT_FATAL(rc == 0);
611 
612 	/* do nothing with PR but have good status */
613 	rc = scsi2_reserve(&task, task.cdb);
614 	SPDK_CU_ASSERT_FATAL(rc == 0);
615 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder != NULL);
616 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY);
617 
618 	rc = scsi2_release(&task);
619 	SPDK_CU_ASSERT_FATAL(rc == 0);
620 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder != NULL);
621 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY);
622 
623 	ut_deinit_reservation_test();
624 }
625 
626 int
627 main(int argc, char **argv)
628 {
629 	CU_pSuite	suite = NULL;
630 	unsigned int	num_failures;
631 
632 	CU_initialize_registry();
633 
634 	suite = CU_add_suite("reservation_suite", NULL, NULL);
635 	CU_ADD_TEST(suite, test_reservation_register);
636 	CU_ADD_TEST(suite, test_reservation_reserve);
637 	CU_ADD_TEST(suite, test_reservation_preempt_non_all_regs);
638 	CU_ADD_TEST(suite, test_reservation_preempt_all_regs);
639 	CU_ADD_TEST(suite, test_reservation_cmds_conflict);
640 	CU_ADD_TEST(suite, test_scsi2_reserve_release);
641 	CU_ADD_TEST(suite, test_pr_with_scsi2_reserve_release);
642 
643 	num_failures = spdk_ut_run_tests(argc, argv, NULL);
644 	CU_cleanup_registry();
645 	return num_failures;
646 
647 }
648