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