xref: /spdk/test/unit/lib/scsi/scsi_pr.c/scsi_pr_ut.c (revision 8a6101458532c70e17ff48c2d48391f284a0fdd5)
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_all_registrant_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 
221 	test_build_registrants();
222 	gen = g_lun.pr_generation;
223 	/* Test Case: Host A takes all registrant reservation */
224 	task.initiator_port = &g_i_port_a;
225 	task.status = 0;
226 	rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS,
227 				 0xa, 0, 0, 0);
228 	SPDK_CU_ASSERT_FATAL(rc == 0);
229 	SPDK_CU_ASSERT_FATAL(task.status == 0);
230 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS);
231 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa);
232 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen);
233 
234 	/* Test case: Host A release reservation - which should pass to next inline -> Host B */
235 	task.initiator_port = &g_i_port_a;
236 	task.status = 0;
237 	rc = scsi_pr_out_release(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS, 0xa);
238 	SPDK_CU_ASSERT_FATAL(rc == 0);
239 	SPDK_CU_ASSERT_FATAL(task.status == 0);
240 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS);
241 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xb);
242 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen);
243 
244 	/* Test case: Host A unregister + Host C unregister: Host B left alone.
245 	 * Host B than releases reservation - lun should not have any reservation holder *
246 	 */
247 	task.initiator_port = &g_i_port_a;
248 	task.status = 0;
249 	rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER,
250 				  0xa, 0, 0, 0, 0);
251 	SPDK_CU_ASSERT_FATAL(rc == 0);
252 	SPDK_CU_ASSERT_FATAL(task.status == 0);
253 	reg = scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0);
254 	SPDK_CU_ASSERT_FATAL(reg == NULL);
255 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == ++gen);
256 
257 	task.initiator_port = &g_i_port_c;
258 	task.status = 0;
259 	rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER,
260 				  0xc, 0, 0, 0, 0);
261 	SPDK_CU_ASSERT_FATAL(rc == 0);
262 	SPDK_CU_ASSERT_FATAL(task.status == 0);
263 	reg = scsi_pr_get_registrant(&g_lun, &g_i_port_c, &g_t_port_0);
264 	SPDK_CU_ASSERT_FATAL(reg == NULL);
265 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == ++gen);
266 
267 	task.initiator_port = &g_i_port_b;
268 	task.status = 0;
269 	rc = scsi_pr_out_release(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS, 0xb);
270 	SPDK_CU_ASSERT_FATAL(rc == 0);
271 	SPDK_CU_ASSERT_FATAL(task.status == 0);
272 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == 0x0);
273 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0x0);
274 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder == NULL);
275 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen);
276 
277 	ut_deinit_reservation_test();
278 }
279 
280 static void
281 test_all_registrant_reservation_access(void)
282 {
283 	struct spdk_scsi_pr_registrant *reg;
284 	struct spdk_scsi_task task = {0};
285 	uint8_t cdb[32] = {0};
286 	uint32_t gen;
287 	int rc;
288 
289 	task.lun = &g_lun;
290 	task.target_port = &g_t_port_0;
291 	task.cdb = cdb;
292 
293 	ut_init_reservation_test();
294 
295 	test_build_registrants();
296 	gen = g_lun.pr_generation;
297 
298 	/* Test case: registered host A takes EXCLUSIVE_ACCESS_ALL_REGS reservation */
299 	task.initiator_port = &g_i_port_a;
300 	task.status = 0;
301 	rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS,
302 				 0xa, 0, 0, 0);
303 	SPDK_CU_ASSERT_FATAL(rc == 0);
304 	SPDK_CU_ASSERT_FATAL(task.status == 0);
305 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS);
306 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa);
307 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen);
308 
309 	/* Test case: registered host B tries getting read access */
310 	task.initiator_port = &g_i_port_b;
311 	task.status = 0;
312 	task.cdb[0] = SPDK_SBC_READ_6;
313 	rc = scsi_pr_check(&task);
314 	SPDK_CU_ASSERT_FATAL(rc == 0);
315 
316 	/* Test case: registered host B tries getting write access */
317 	task.initiator_port = &g_i_port_b;
318 	task.status = 0;
319 	task.cdb[0] = SPDK_SBC_WRITE_12;
320 	rc = scsi_pr_check(&task);
321 	SPDK_CU_ASSERT_FATAL(rc == 0);
322 
323 	/* Test case: B unregisters */
324 	task.initiator_port = &g_i_port_b;
325 	task.status = 0;
326 	rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER,
327 				  0xb, 0, 0, 0, 0);
328 	SPDK_CU_ASSERT_FATAL(rc == 0);
329 	SPDK_CU_ASSERT_FATAL(task.status == 0);
330 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == ++gen);
331 	reg = scsi_pr_get_registrant(&g_lun, &g_i_port_b, &g_t_port_0);
332 	SPDK_CU_ASSERT_FATAL(reg == NULL);
333 
334 	/* Test case: un register host B tries getting read access */
335 	task.initiator_port = &g_i_port_b;
336 	task.status = 0;
337 	task.cdb[0] = SPDK_SBC_READ_6;
338 	rc = scsi_pr_check(&task);
339 	SPDK_CU_ASSERT_FATAL(rc < 0);
340 
341 	/* Test case: un register host B tries getting write access */
342 	task.initiator_port = &g_i_port_b;
343 	task.status = 0;
344 	task.cdb[0] = SPDK_SBC_WRITE_12;
345 	rc = scsi_pr_check(&task);
346 	SPDK_CU_ASSERT_FATAL(rc < 0);
347 
348 	ut_deinit_reservation_test();
349 }
350 
351 static void
352 test_reservation_reserve(void)
353 {
354 	struct spdk_scsi_pr_registrant *reg;
355 	struct spdk_scsi_task task = {0};
356 	uint32_t gen;
357 	int rc;
358 
359 	task.lun = &g_lun;
360 	task.target_port = &g_t_port_0;
361 
362 	ut_init_reservation_test();
363 	/* Test Case: call Release without a reservation */
364 	rc = scsi2_release(&task);
365 	CU_ASSERT(rc == -EINVAL);
366 	CU_ASSERT(task.status == SPDK_SCSI_STATUS_CHECK_CONDITION);
367 
368 	test_build_registrants();
369 
370 	gen = g_lun.pr_generation;
371 
372 	task.initiator_port = &g_i_port_a;
373 	task.status = 0;
374 	/* Test Case: Host A acquires the reservation */
375 	rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE,
376 				 0xa, 0, 0, 0);
377 	SPDK_CU_ASSERT_FATAL(rc == 0);
378 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE);
379 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa);
380 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen);
381 
382 	/* Test Case: Host B acquires the reservation, reservation
383 	 * conflict is expected.
384 	 */
385 	task.initiator_port = &g_i_port_b;
386 	task.status = 0;
387 	rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE,
388 				 0xb, 0, 0, 0);
389 	SPDK_CU_ASSERT_FATAL(rc < 0);
390 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT);
391 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE);
392 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa);
393 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen);
394 
395 	/* Test Case: Host A unregister with reservation */
396 	task.initiator_port = &g_i_port_a;
397 	task.status = 0;
398 	rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER,
399 				  0xa, 0, 0, 0, 0);
400 	SPDK_CU_ASSERT_FATAL(rc == 0);
401 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == 0);
402 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0);
403 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1);
404 	reg = scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0);
405 	SPDK_CU_ASSERT_FATAL(reg == NULL);
406 
407 	/* Test Case: Host B acquires the reservation */
408 	task.initiator_port = &g_i_port_b;
409 	task.status = 0;
410 	rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS,
411 				 0xb, 0, 0, 0);
412 	SPDK_CU_ASSERT_FATAL(rc == 0);
413 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS);
414 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1);
415 
416 	/* Test Case: Host C acquires the reservation with invalid type */
417 	task.initiator_port = &g_i_port_c;
418 	task.status = 0;
419 	rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE,
420 				 0xc, 0, 0, 0);
421 	SPDK_CU_ASSERT_FATAL(rc < 0);
422 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT);
423 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS);
424 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1);
425 
426 	/* Test Case: Host C acquires the reservation, all registrants type */
427 	task.status = 0;
428 	rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS,
429 				 0xc, 0, 0, 0);
430 	SPDK_CU_ASSERT_FATAL(rc == 0);
431 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS);
432 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen + 1);
433 
434 	ut_deinit_reservation_test();
435 }
436 
437 static void
438 test_reservation_preempt_non_all_regs(void)
439 {
440 	struct spdk_scsi_pr_registrant *reg;
441 	struct spdk_scsi_task task = {0};
442 	uint32_t gen;
443 	int rc;
444 
445 	task.lun = &g_lun;
446 	task.target_port = &g_t_port_0;
447 
448 	ut_init_reservation_test();
449 	test_build_registrants();
450 
451 	task.initiator_port = &g_i_port_a;
452 	task.status = 0;
453 	gen = g_lun.pr_generation;
454 	/* Host A acquires the reservation */
455 	rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY,
456 				 0xa, 0, 0, 0);
457 	SPDK_CU_ASSERT_FATAL(rc == 0);
458 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY);
459 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa);
460 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen);
461 
462 	/* Test Case: Host B preempts Host A, Check condition is expected
463 	 * for zeroed service action reservation key */
464 	task.initiator_port = &g_i_port_b;
465 	task.status = 0;
466 	rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT,
467 				 SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY,
468 				 0xb, 0);
469 	SPDK_CU_ASSERT_FATAL(rc < 0);
470 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_CHECK_CONDITION);
471 
472 	/* Test Case: Host B preempts Host A, Host A is unregistered */
473 	task.status = 0;
474 	gen = g_lun.pr_generation;
475 	rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT,
476 				 SPDK_SCSI_PR_WRITE_EXCLUSIVE,
477 				 0xb, 0xa);
478 	SPDK_CU_ASSERT_FATAL(rc == 0);
479 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE);
480 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xb);
481 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen);
482 	reg = scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0);
483 	SPDK_CU_ASSERT_FATAL(reg == NULL);
484 
485 	/* Test Case: Host B preempts itself */
486 	task.status = 0;
487 	gen = g_lun.pr_generation;
488 	rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT,
489 				 SPDK_SCSI_PR_WRITE_EXCLUSIVE,
490 				 0xb, 0xb);
491 	SPDK_CU_ASSERT_FATAL(rc == 0);
492 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE);
493 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xb);
494 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen);
495 
496 	/* Test Case: Host B preempts itself and remove registrants */
497 	task.status = 0;
498 	gen = g_lun.pr_generation;
499 	rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT,
500 				 SPDK_SCSI_PR_WRITE_EXCLUSIVE,
501 				 0xb, 0xc);
502 	SPDK_CU_ASSERT_FATAL(rc == 0);
503 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE);
504 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xb);
505 	reg = scsi_pr_get_registrant(&g_lun, &g_i_port_c, &g_t_port_0);
506 	SPDK_CU_ASSERT_FATAL(reg == NULL);
507 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen);
508 
509 	ut_deinit_reservation_test();
510 }
511 
512 static void
513 test_reservation_preempt_all_regs(void)
514 {
515 	struct spdk_scsi_pr_registrant *reg;
516 	struct spdk_scsi_task task = {0};
517 	uint32_t gen;
518 	int rc;
519 
520 	task.lun = &g_lun;
521 	task.target_port = &g_t_port_0;
522 
523 	ut_init_reservation_test();
524 	test_build_registrants();
525 
526 	/* Test Case: No reservation yet, Host B removes Host C's registrant */
527 	task.initiator_port = &g_i_port_b;
528 	task.status = 0;
529 	gen = g_lun.pr_generation;
530 	rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT,
531 				 SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY,
532 				 0xb, 0xc);
533 	SPDK_CU_ASSERT_FATAL(rc == 0);
534 	reg = scsi_pr_get_registrant(&g_lun, &g_i_port_c, &g_t_port_0);
535 	SPDK_CU_ASSERT_FATAL(reg == NULL);
536 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen);
537 
538 	task.initiator_port = &g_i_port_a;
539 	task.status = 0;
540 	gen = g_lun.pr_generation;
541 	/* Host A acquires the reservation */
542 	rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS,
543 				 0xa, 0, 0, 0);
544 	SPDK_CU_ASSERT_FATAL(rc == 0);
545 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS);
546 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation == gen);
547 
548 	/* Test Case: Host B removes Host A's registrant and preempt */
549 	task.initiator_port = &g_i_port_b;
550 	task.status = 0;
551 	gen = g_lun.pr_generation;
552 	rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT,
553 				 SPDK_SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS,
554 				 0xb, 0x0);
555 	SPDK_CU_ASSERT_FATAL(rc == 0);
556 	reg = scsi_pr_get_registrant(&g_lun, &g_i_port_a, &g_t_port_0);
557 	SPDK_CU_ASSERT_FATAL(reg == NULL);
558 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS);
559 	SPDK_CU_ASSERT_FATAL(g_lun.pr_generation > gen);
560 
561 	ut_deinit_reservation_test();
562 }
563 
564 static void
565 test_reservation_cmds_conflict(void)
566 {
567 	struct spdk_scsi_pr_registrant *reg;
568 	struct spdk_scsi_task task = {0};
569 	uint8_t cdb[32];
570 	int rc;
571 
572 	task.lun = &g_lun;
573 	task.target_port = &g_t_port_0;
574 	task.cdb = cdb;
575 
576 	ut_init_reservation_test();
577 	test_build_registrants();
578 
579 	/* Host A acquires the reservation */
580 	task.initiator_port = &g_i_port_a;
581 	rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY,
582 				 0xa, 0, 0, 0);
583 	SPDK_CU_ASSERT_FATAL(rc == 0);
584 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY);
585 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa);
586 
587 	/* Remove Host B registrant */
588 	task.initiator_port = &g_i_port_b;
589 	task.status = 0;
590 	rc = scsi_pr_out_register(&task, SPDK_SCSI_PR_OUT_REGISTER,
591 				  0xb, 0, 0, 0, 0);
592 	SPDK_CU_ASSERT_FATAL(rc == 0);
593 	reg = scsi_pr_get_registrant(&g_lun, &g_i_port_b, &g_t_port_0);
594 	SPDK_CU_ASSERT_FATAL(reg == NULL);
595 
596 	/* Test Case: Host B sends Read/Write commands,
597 	 * reservation conflict is expected.
598 	 */
599 	task.cdb[0] = SPDK_SBC_READ_10;
600 	task.status = 0;
601 	rc = scsi_pr_check(&task);
602 	SPDK_CU_ASSERT_FATAL(rc == 0);
603 	task.cdb[0] = SPDK_SBC_WRITE_10;
604 	task.status = 0;
605 	rc = scsi_pr_check(&task);
606 	SPDK_CU_ASSERT_FATAL(rc < 0);
607 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT);
608 
609 	/* Test Case: Host C sends Read/Write commands */
610 	task.initiator_port = &g_i_port_c;
611 	task.cdb[0] = SPDK_SBC_READ_10;
612 	task.status = 0;
613 	rc = scsi_pr_check(&task);
614 	SPDK_CU_ASSERT_FATAL(rc == 0);
615 	task.cdb[0] = SPDK_SBC_WRITE_10;
616 	task.status = 0;
617 	rc = scsi_pr_check(&task);
618 	SPDK_CU_ASSERT_FATAL(rc == 0);
619 
620 	/* Host A preempts itself with SPDK_SCSI_PR_EXCLUSIVE_ACCESS */
621 	task.initiator_port = &g_i_port_a;
622 	rc = scsi_pr_out_preempt(&task, SPDK_SCSI_PR_OUT_PREEMPT,
623 				 SPDK_SCSI_PR_EXCLUSIVE_ACCESS,
624 				 0xa, 0xa);
625 	SPDK_CU_ASSERT_FATAL(rc == 0);
626 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_EXCLUSIVE_ACCESS);
627 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa);
628 
629 	/* Test Case: Host C sends Read/Write commands */
630 	task.initiator_port = &g_i_port_c;
631 	task.cdb[0] = SPDK_SBC_READ_10;
632 	task.status = 0;
633 	rc = scsi_pr_check(&task);
634 	SPDK_CU_ASSERT_FATAL(rc < 0);
635 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT);
636 	task.cdb[0] = SPDK_SBC_WRITE_10;
637 	task.status = 0;
638 	rc = scsi_pr_check(&task);
639 	SPDK_CU_ASSERT_FATAL(rc < 0);
640 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT);
641 
642 	/* Test Case: Host B sends Read/Write commands */
643 	task.initiator_port = &g_i_port_b;
644 	task.cdb[0] = SPDK_SBC_READ_10;
645 	task.status = 0;
646 	rc = scsi_pr_check(&task);
647 	SPDK_CU_ASSERT_FATAL(rc < 0);
648 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT);
649 	task.cdb[0] = SPDK_SBC_WRITE_10;
650 	task.status = 0;
651 	rc = scsi_pr_check(&task);
652 	SPDK_CU_ASSERT_FATAL(rc < 0);
653 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT);
654 
655 	ut_deinit_reservation_test();
656 }
657 
658 static void
659 test_scsi2_reserve_release(void)
660 {
661 	struct spdk_scsi_task task = {0};
662 	uint8_t cdb[32] = {};
663 	int rc;
664 
665 	task.lun = &g_lun;
666 	task.target_port = &g_t_port_0;
667 	task.cdb = cdb;
668 
669 	ut_init_reservation_test();
670 
671 	/* Test Case: SPC2 RESERVE from Host A */
672 	task.initiator_port = &g_i_port_a;
673 	task.cdb[0] = SPDK_SPC2_RESERVE_10;
674 	rc = scsi2_reserve(&task, task.cdb);
675 	SPDK_CU_ASSERT_FATAL(rc == 0);
676 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder != NULL);
677 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.flags == SCSI_SPC2_RESERVE);
678 
679 	/* Test Case: READ command from Host B */
680 	task.initiator_port = &g_i_port_b;
681 	task.cdb[0] = SPDK_SBC_READ_10;
682 	task.status = 0;
683 	rc = scsi2_reserve_check(&task);
684 	SPDK_CU_ASSERT_FATAL(rc < 0);
685 	SPDK_CU_ASSERT_FATAL(task.status == SPDK_SCSI_STATUS_RESERVATION_CONFLICT);
686 
687 	/* Test Case: SPDK_SPC2_RELEASE10 command from Host B */
688 	task.initiator_port = &g_i_port_b;
689 	task.cdb[0] = SPDK_SPC2_RELEASE_10;
690 	task.status = 0;
691 	rc = scsi2_reserve_check(&task);
692 	SPDK_CU_ASSERT_FATAL(rc == 0);
693 
694 	rc = scsi2_release(&task);
695 	SPDK_CU_ASSERT_FATAL(rc == 0);
696 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder == NULL);
697 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.flags == 0);
698 
699 	/* Test Case: SPC2 RESERVE from Host B */
700 	task.initiator_port = &g_i_port_b;
701 	task.cdb[0] = SPDK_SPC2_RESERVE_10;
702 	rc = scsi2_reserve(&task, task.cdb);
703 	SPDK_CU_ASSERT_FATAL(rc == 0);
704 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder != NULL);
705 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.flags == SCSI_SPC2_RESERVE);
706 
707 	/* Test Case: READ command from Host B */
708 	task.initiator_port = &g_i_port_b;
709 	task.cdb[0] = SPDK_SBC_READ_10;
710 	rc = scsi2_reserve_check(&task);
711 	SPDK_CU_ASSERT_FATAL(rc == 0);
712 
713 	/* Test Case: SPDK_SPC2_RELEASE10 command from Host A */
714 	task.initiator_port = &g_i_port_a;
715 	task.cdb[0] = SPDK_SPC2_RELEASE_10;
716 
717 	rc = scsi2_release(&task);
718 	SPDK_CU_ASSERT_FATAL(rc == 0);
719 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder == NULL);
720 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.flags == 0);
721 
722 	ut_deinit_reservation_test();
723 }
724 
725 static void
726 test_pr_with_scsi2_reserve_release(void)
727 {
728 	struct spdk_scsi_task task = {0};
729 	uint8_t cdb[32] = {};
730 	int rc;
731 
732 	task.lun = &g_lun;
733 	task.target_port = &g_t_port_0;
734 	task.cdb = cdb;
735 
736 	ut_init_reservation_test();
737 	test_build_registrants();
738 
739 	task.initiator_port = &g_i_port_a;
740 	task.status = 0;
741 	/* Test Case: Host A acquires the reservation */
742 	rc = scsi_pr_out_reserve(&task, SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY,
743 				 0xa, 0, 0, 0);
744 	SPDK_CU_ASSERT_FATAL(rc == 0);
745 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY);
746 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.crkey == 0xa);
747 
748 	/* Test Case: SPDK_SPC2_RESERVE_10 command from Host B */
749 	task.initiator_port = &g_i_port_b;
750 	task.cdb[0] = SPDK_SPC2_RESERVE_10;
751 	/* SPC2 RESERVE/RELEASE will pass to scsi2_reserve/release */
752 	rc = scsi_pr_check(&task);
753 	SPDK_CU_ASSERT_FATAL(rc == 0);
754 
755 	/* do nothing with PR but have good status */
756 	rc = scsi2_reserve(&task, task.cdb);
757 	SPDK_CU_ASSERT_FATAL(rc == 0);
758 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder != NULL);
759 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY);
760 
761 	rc = scsi2_release(&task);
762 	SPDK_CU_ASSERT_FATAL(rc == 0);
763 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.holder != NULL);
764 	SPDK_CU_ASSERT_FATAL(g_lun.reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY);
765 
766 	ut_deinit_reservation_test();
767 }
768 
769 int
770 main(int argc, char **argv)
771 {
772 	CU_pSuite	suite = NULL;
773 	unsigned int	num_failures;
774 
775 	CU_initialize_registry();
776 
777 	suite = CU_add_suite("reservation_suite", NULL, NULL);
778 	CU_ADD_TEST(suite, test_reservation_register);
779 	CU_ADD_TEST(suite, test_reservation_reserve);
780 	CU_ADD_TEST(suite, test_all_registrant_reservation_reserve);
781 	CU_ADD_TEST(suite, test_all_registrant_reservation_access);
782 	CU_ADD_TEST(suite, test_reservation_preempt_non_all_regs);
783 	CU_ADD_TEST(suite, test_reservation_preempt_all_regs);
784 	CU_ADD_TEST(suite, test_reservation_cmds_conflict);
785 	CU_ADD_TEST(suite, test_scsi2_reserve_release);
786 	CU_ADD_TEST(suite, test_pr_with_scsi2_reserve_release);
787 
788 	num_failures = spdk_ut_run_tests(argc, argv, NULL);
789 	CU_cleanup_registry();
790 	return num_failures;
791 
792 }
793