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
SPDK_LOG_REGISTER_COMPONENT(scsi)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
ut_lun_deinit(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
ut_port_init(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
ut_lun_init(void)104 ut_lun_init(void)
105 {
106 TAILQ_INIT(&g_lun.reg_head);
107 }
108
109 static void
ut_init_reservation_test(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
ut_deinit_reservation_test(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
test_build_registrants(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
test_reservation_register(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
test_all_registrant_reservation_reserve(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
test_all_registrant_reservation_access(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
test_reservation_reserve(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
test_reservation_preempt_non_all_regs(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
test_reservation_preempt_all_regs(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
test_reservation_cmds_conflict(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
test_scsi2_reserve_release(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
test_pr_with_scsi2_reserve_release(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
main(int argc,char ** argv)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