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