1 /*
2 Copyright (C) 2015 David Disseldorp
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <stdio.h>
19 #include <arpa/inet.h>
20
21 #include <CUnit/CUnit.h>
22
23 #include "iscsi.h"
24 #include "scsi-lowlevel.h"
25 #include "iscsi-support.h"
26 #include "iscsi-test-cu.h"
27
28 static struct test_prin_report_caps_types {
29 enum scsi_persistent_reservation_type_mask mask;
30 enum scsi_persistent_out_type op;
31 } report_caps_types_array[] = {
32 { SCSI_PR_TYPE_MASK_WR_EX_AR,
33 SCSI_PERSISTENT_RESERVE_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS },
34 { SCSI_PR_TYPE_MASK_EX_AC_RO,
35 SCSI_PERSISTENT_RESERVE_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY },
36 { SCSI_PR_TYPE_MASK_WR_EX_RO,
37 SCSI_PERSISTENT_RESERVE_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY },
38 { SCSI_PR_TYPE_MASK_EX_AC,
39 SCSI_PERSISTENT_RESERVE_TYPE_EXCLUSIVE_ACCESS },
40 { SCSI_PR_TYPE_MASK_WR_EX,
41 SCSI_PERSISTENT_RESERVE_TYPE_WRITE_EXCLUSIVE },
42 { SCSI_PR_TYPE_MASK_EX_AC_AR,
43 SCSI_PERSISTENT_RESERVE_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS },
44 { 0, 0 }
45 };
46
47 void
test_prin_report_caps_simple(void)48 test_prin_report_caps_simple(void)
49 {
50 int ret = 0;
51 const unsigned long long key = rand_key();
52 struct scsi_task *tsk;
53 struct scsi_persistent_reserve_in_report_capabilities *rcaps = NULL;
54 struct test_prin_report_caps_types *type;
55
56 CHECK_FOR_DATALOSS;
57
58 logging(LOG_VERBOSE, LOG_BLANK_LINE);
59 logging(LOG_VERBOSE,
60 "Test Persistent Reserve In REPORT CAPABILITIES works.");
61
62 /* register our reservation key with the target */
63 ret = prout_register_and_ignore(sd, key);
64 if (ret == -2) {
65 CU_PASS("PERSISTENT RESERVE OUT is not implemented.");
66 return;
67 }
68 CU_ASSERT_EQUAL(ret, 0);
69
70 ret = prin_report_caps(sd, &tsk, &rcaps);
71 CU_ASSERT_EQUAL(ret, 0);
72 CU_ASSERT_NOT_EQUAL(rcaps, NULL);
73
74 if (!rcaps)
75 return;
76
77 logging(LOG_VERBOSE,
78 "Checking PERSISTENT RESERVE IN REPORT CAPABILITIES fields.");
79 CU_ASSERT_EQUAL(rcaps->length, 8);
80 CU_ASSERT_TRUE(rcaps->allow_commands <= 5);
81 CU_ASSERT_EQUAL(rcaps->persistent_reservation_type_mask
82 & ~SCSI_PR_TYPE_MASK_ALL, 0);
83
84 for (type = &report_caps_types_array[0]; type->mask != 0; type++) {
85 if (!(rcaps->persistent_reservation_type_mask & type->mask)) {
86 logging(LOG_NORMAL,
87 "PERSISTENT RESERVE op 0x%x not supported",
88 type->op);
89 continue;
90 }
91
92 logging(LOG_VERBOSE,
93 "PERSISTENT RESERVE OUT op 0x%x supported, testing",
94 type->op);
95
96 /* reserve the target */
97 ret = prout_reserve(sd, key, type->op);
98 CU_ASSERT_EQUAL(ret, 0);
99
100 /* verify target reservation */
101 ret = prin_verify_reserved_as(sd,
102 pr_type_is_all_registrants(type->op) ? 0 : key,
103 type->op);
104 CU_ASSERT_EQUAL(0, ret);
105
106 /* release the target */
107 ret = prout_release(sd, key, type->op);
108 CU_ASSERT_EQUAL(ret, 0);
109 }
110
111 scsi_free_scsi_task(tsk);
112 rcaps = NULL; /* freed with tsk */
113
114 /* drop registration */
115 ret = prout_register_key(sd, 0, key);
116 CU_ASSERT_EQUAL(ret, 0);
117 }
118