1 /*
2    Copyright (C) 2013 Ronnie Sahlberg <ronniesahlberg@gmail.com>
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 
20 #include <CUnit/CUnit.h>
21 
22 #include "iscsi.h"
23 #include "scsi-lowlevel.h"
24 #include "iscsi-support.h"
25 #include "iscsi-test-cu.h"
26 
27 
28 void
test_writesame16_unmap(void)29 test_writesame16_unmap(void)
30 {
31         unsigned int i;
32 
33         CHECK_FOR_DATALOSS;
34         CHECK_FOR_THIN_PROVISIONING;
35         CHECK_FOR_LBPWS;
36         CHECK_FOR_SBC;
37 
38         logging(LOG_VERBOSE, LOG_BLANK_LINE);
39         logging(LOG_VERBOSE, "Test WRITESAME16 of 1-256 blocks at the start of the LUN");
40         for (i = 1; i <= 256; i++) {
41                 logging(LOG_VERBOSE, "Write %d blocks of 0xFF", i);
42                 memset(scratch, 0xff, i * block_size);
43                 WRITE16(sd, 0, i * block_size, block_size,
44                         0, 0, 0, 0, 0, scratch,
45                         EXPECT_STATUS_GOOD);
46 
47                 logging(LOG_VERBOSE, "Unmap %d blocks using WRITESAME16", i);
48                 memset(scratch, 0, block_size);
49                 WRITESAME16(sd, 0, block_size, i, 0, 1, 0, 0, scratch,
50                             EXPECT_STATUS_GOOD);
51 
52                 if (rc16->lbprz) {
53                         logging(LOG_VERBOSE, "LBPRZ is set. Read the unmapped "
54                                 "blocks back and verify they are all zero");
55                         logging(LOG_VERBOSE, "Read %d blocks and verify they "
56                                 "are now zero", i);
57                         READ16(sd, NULL, 0, i * block_size, block_size,
58                                0, 0, 0, 0, 0, scratch,
59                                EXPECT_STATUS_GOOD);
60                         ALL_ZERO(scratch, i * block_size);
61                 } else {
62                         logging(LOG_VERBOSE, "LBPRZ is clear. Skip the read "
63                                 "and verify zero test");
64                 }
65         }
66 
67 
68         logging(LOG_VERBOSE, "Test WRITESAME16 of 1-256 blocks at the end of the LUN");
69         for (i = 1; i <= 256; i++) {
70                 logging(LOG_VERBOSE, "Write %d blocks of 0xFF", i);
71                 memset(scratch, 0xff, i * block_size);
72                 WRITE16(sd, num_blocks - i,
73                         i * block_size, block_size, 0, 0, 0, 0, 0, scratch,
74                         EXPECT_STATUS_GOOD);
75 
76                 logging(LOG_VERBOSE, "Unmap %d blocks using WRITESAME16", i);
77                 memset(scratch, 0, block_size);
78                 WRITESAME16(sd, num_blocks - i,
79                             block_size, i, 0, 1, 0, 0, scratch,
80                             EXPECT_STATUS_GOOD);
81 
82                 if (rc16->lbprz) {
83                         logging(LOG_VERBOSE, "LBPRZ is set. Read the unmapped "
84                                 "blocks back and verify they are all zero");
85                         logging(LOG_VERBOSE, "Read %d blocks and verify they "
86                                 "are now zero", i);
87                         READ16(sd, NULL, num_blocks - i,
88                                i * block_size, block_size,
89                                0, 0, 0, 0, 0, scratch,
90                                EXPECT_STATUS_GOOD);
91                         ALL_ZERO(scratch, i * block_size);
92                 } else {
93                         logging(LOG_VERBOSE, "LBPRZ is clear. Skip the read "
94                                 "and verify zero test");
95                 }
96         }
97 
98         logging(LOG_VERBOSE, "Verify that WRITESAME16 ANCHOR==1 + UNMAP==0 is invalid");
99         WRITESAME16(sd, 0, block_size, 1, 1, 0, 0, 0, scratch,
100                     EXPECT_INVALID_FIELD_IN_CDB);
101 
102         if (inq_lbp->anc_sup) {
103                 logging(LOG_VERBOSE, "Test WRITESAME16 ANCHOR==1 + UNMAP==0");
104                 memset(scratch, 0, block_size);
105                 WRITESAME16(sd, 0, block_size, 1, 1, 1, 0, 0, scratch,
106                             EXPECT_STATUS_GOOD);
107         } else {
108                 logging(LOG_VERBOSE, "Test WRITESAME16 ANCHOR==1 + UNMAP==0 no ANC_SUP so expecting to fail");
109                 WRITESAME16(sd, 0, block_size, 1, 1, 1, 0, 0, scratch,
110                             EXPECT_INVALID_FIELD_IN_CDB);
111         }
112 
113         if (inq_bl == NULL) {
114                 logging(LOG_VERBOSE, "[FAILED] WRITESAME16 works but "
115                         "BlockLimits VPD is missing.");
116                 CU_FAIL("[FAILED] WRITESAME16 works but "
117                         "BlockLimits VPD is missing.");
118                 return;
119         }
120 
121         i = 256;
122         if (i <= num_blocks
123             && (inq_bl->max_ws_len == 0 || inq_bl->max_ws_len >= i)) {
124                 logging(LOG_VERBOSE, "Block Limits VPD page reports MAX_WS_LEN "
125                         "as either 0 (==no limit) or >= %d. Test Unmapping "
126                         "%d blocks to verify that it can handle 2-byte "
127                         "lengths", i, i);
128 
129                 logging(LOG_VERBOSE, "Write %d blocks of 0xFF", i);
130                 memset(scratch, 0xff, i * block_size);
131                 WRITE16(sd, 0,
132                         i * block_size, block_size, 0, 0, 0, 0, 0, scratch,
133                         EXPECT_STATUS_GOOD);
134 
135                 logging(LOG_VERBOSE, "Unmap %d blocks using WRITESAME16", i);
136                 memset(scratch, 0, block_size);
137                 WRITESAME16(sd, 0, block_size, i, 0, 1, 0, 0, scratch,
138                             EXPECT_STATUS_GOOD);
139 
140                 if (rc16->lbprz) {
141                         logging(LOG_VERBOSE, "LBPRZ is set. Read the unmapped "
142                                 "blocks back and verify they are all zero");
143 
144                         logging(LOG_VERBOSE, "Read %d blocks and verify they "
145                                 "are now zero", i);
146                         READ16(sd, NULL, 0, i * block_size, block_size,
147                                0, 0, 0, 0, 0, scratch,
148                                EXPECT_STATUS_GOOD);
149                         ALL_ZERO(scratch, i * block_size);
150                 } else {
151                         logging(LOG_VERBOSE, "LBPRZ is clear. Skip the read "
152                                 "and verify zero test");
153                 }
154         } else if (i <= num_blocks) {
155                 logging(LOG_VERBOSE, "Block Limits VPD page reports MAX_WS_LEN "
156                         "as <256. Verify that a 256 block unmap fails with "
157                         "INVALID_FIELD_IN_CDB.");
158 
159                 logging(LOG_VERBOSE, "Unmap %d blocks using WRITESAME16", i);
160                 WRITESAME16(sd, 0, block_size, i, 0, 1, 0, 0, scratch,
161                             EXPECT_INVALID_FIELD_IN_CDB);
162         }
163 
164 
165         i = 65536;
166         if (i <= num_blocks
167             && (inq_bl->max_ws_len == 0 || inq_bl->max_ws_len >= i)) {
168                 logging(LOG_VERBOSE, "Block Limits VPD page reports MAX_WS_LEN "
169                         "as either 0 (==no limit) or >= %d. Test Unmapping "
170                         "%d blocks to verify that it can handle 4-byte "
171                         "lengths", i, i);
172 
173                 logging(LOG_VERBOSE, "Write %d blocks of 0xFF", i);
174                 memset(scratch, 0xff, i * block_size);
175                 WRITE16(sd, 0,
176                         i * block_size, block_size, 0, 0, 0, 0, 0, scratch,
177                         EXPECT_STATUS_GOOD);
178 
179                 logging(LOG_VERBOSE, "Unmap %d blocks using WRITESAME16", i);
180                 memset(scratch, 0, block_size);
181                 WRITESAME16(sd, 0, block_size, i, 0, 1, 0, 0, scratch,
182                             EXPECT_STATUS_GOOD);
183 
184                 if (rc16->lbprz) {
185                         logging(LOG_VERBOSE, "LBPRZ is set. Read the unmapped "
186                                 "blocks back and verify they are all zero");
187 
188                         logging(LOG_VERBOSE, "Read %d blocks and verify they "
189                                 "are now zero", i);
190                         READ16(sd, NULL, 0, i * block_size, block_size,
191                                0, 0, 0, 0, 0, scratch,
192                                EXPECT_STATUS_GOOD);
193                         ALL_ZERO(scratch, i * block_size);
194                 } else {
195                         logging(LOG_VERBOSE, "LBPRZ is clear. Skip the read "
196                                 "and verify zero test");
197                 }
198         } else if (i <= num_blocks) {
199                 logging(LOG_VERBOSE, "Block Limits VPD page reports MAX_WS_LEN "
200                         "as <256. Verify that a 256 block unmap fails with "
201                         "INVALID_FIELD_IN_CDB.");
202 
203                 logging(LOG_VERBOSE, "Unmap %d blocks using WRITESAME16", i);
204                 WRITESAME16(sd, 0, block_size, i, 0, 1, 0, 0, scratch,
205                             EXPECT_INVALID_FIELD_IN_CDB);
206         }
207 }
208