1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk/stdinc.h" 35 36 #include "common/lib/test_env.c" 37 #include "spdk_cunit.h" 38 39 #include "iscsi/conn.c" 40 41 #include "spdk_internal/mock.h" 42 43 SPDK_LOG_REGISTER_COMPONENT("iscsi", SPDK_LOG_ISCSI) 44 45 #define DMIN32(A,B) ((uint32_t) ((uint32_t)(A) > (uint32_t)(B) ? (uint32_t)(B) : (uint32_t)(A))) 46 47 struct spdk_iscsi_globals g_spdk_iscsi; 48 static TAILQ_HEAD(, spdk_iscsi_task) g_ut_read_tasks = TAILQ_HEAD_INITIALIZER(g_ut_read_tasks); 49 50 DEFINE_STUB(spdk_app_get_shm_id, int, (void), 0); 51 52 DEFINE_STUB(spdk_sock_getaddr, int, 53 (struct spdk_sock *sock, char *saddr, int slen, uint16_t *sport, 54 char *caddr, int clen, uint16_t *cport), 55 0); 56 57 int 58 spdk_sock_close(struct spdk_sock **sock) 59 { 60 *sock = NULL; 61 return 0; 62 } 63 64 DEFINE_STUB(spdk_sock_recv, ssize_t, 65 (struct spdk_sock *sock, void *buf, size_t len), 0); 66 67 DEFINE_STUB(spdk_sock_readv, ssize_t, 68 (struct spdk_sock *sock, struct iovec *iov, int iovcnt), 0); 69 70 DEFINE_STUB(spdk_sock_writev, ssize_t, 71 (struct spdk_sock *sock, struct iovec *iov, int iovcnt), 0); 72 73 DEFINE_STUB(spdk_sock_set_recvlowat, int, (struct spdk_sock *s, int nbytes), 0); 74 75 DEFINE_STUB(spdk_sock_set_recvbuf, int, (struct spdk_sock *sock, int sz), 0); 76 77 DEFINE_STUB(spdk_sock_set_sendbuf, int, (struct spdk_sock *sock, int sz), 0); 78 79 DEFINE_STUB(spdk_sock_group_add_sock, int, 80 (struct spdk_sock_group *group, struct spdk_sock *sock, 81 spdk_sock_cb cb_fn, void *cb_arg), 82 0); 83 84 DEFINE_STUB(spdk_sock_group_remove_sock, int, 85 (struct spdk_sock_group *group, struct spdk_sock *sock), 0); 86 87 DEFINE_STUB_V(spdk_scsi_task_put, (struct spdk_scsi_task *task)); 88 89 DEFINE_STUB(spdk_scsi_dev_get_lun, struct spdk_scsi_lun *, 90 (struct spdk_scsi_dev *dev, int lun_id), NULL); 91 92 DEFINE_STUB(spdk_scsi_dev_has_pending_tasks, bool, 93 (const struct spdk_scsi_dev *dev, const struct spdk_scsi_port *initiator_port), 94 true); 95 96 DEFINE_STUB(spdk_scsi_lun_open, int, 97 (struct spdk_scsi_lun *lun, spdk_scsi_lun_remove_cb_t hotremove_cb, 98 void *hotremove_ctx, struct spdk_scsi_lun_desc **desc), 99 0); 100 101 DEFINE_STUB_V(spdk_scsi_lun_close, (struct spdk_scsi_lun_desc *desc)); 102 103 DEFINE_STUB(spdk_scsi_lun_allocate_io_channel, int, 104 (struct spdk_scsi_lun_desc *desc), 0); 105 106 DEFINE_STUB_V(spdk_scsi_lun_free_io_channel, (struct spdk_scsi_lun_desc *desc)); 107 108 DEFINE_STUB(spdk_scsi_lun_get_id, int, (const struct spdk_scsi_lun *lun), 0); 109 110 DEFINE_STUB(spdk_scsi_port_get_name, const char *, 111 (const struct spdk_scsi_port *port), NULL); 112 113 void 114 spdk_scsi_task_copy_status(struct spdk_scsi_task *dst, 115 struct spdk_scsi_task *src) 116 { 117 dst->status = src->status; 118 } 119 120 DEFINE_STUB_V(spdk_put_pdu, (struct spdk_iscsi_pdu *pdu)); 121 122 DEFINE_STUB_V(spdk_iscsi_param_free, (struct iscsi_param *params)); 123 124 DEFINE_STUB(spdk_iscsi_conn_params_init, int, (struct iscsi_param **params), 0); 125 126 DEFINE_STUB_V(spdk_clear_all_transfer_task, 127 (struct spdk_iscsi_conn *conn, struct spdk_scsi_lun *lun, 128 struct spdk_iscsi_pdu *pdu)); 129 130 DEFINE_STUB(spdk_iscsi_build_iovs, int, 131 (struct spdk_iscsi_conn *conn, struct iovec *iov, int num_iovs, 132 struct spdk_iscsi_pdu *pdu, uint32_t *mapped_length), 133 0); 134 135 DEFINE_STUB(spdk_iscsi_is_deferred_free_pdu, bool, 136 (struct spdk_iscsi_pdu *pdu), false); 137 138 DEFINE_STUB_V(spdk_iscsi_task_response, 139 (struct spdk_iscsi_conn *conn, struct spdk_iscsi_task *task)); 140 141 DEFINE_STUB_V(spdk_iscsi_task_mgmt_response, 142 (struct spdk_iscsi_conn *conn, struct spdk_iscsi_task *task)); 143 144 DEFINE_STUB_V(spdk_iscsi_send_nopin, (struct spdk_iscsi_conn *conn)); 145 146 DEFINE_STUB_V(spdk_del_transfer_task, 147 (struct spdk_iscsi_conn *conn, uint32_t task_tag)); 148 149 DEFINE_STUB(spdk_iscsi_conn_handle_queued_datain_tasks, int, 150 (struct spdk_iscsi_conn *conn), 0); 151 152 DEFINE_STUB(spdk_iscsi_handle_incoming_pdus, int, (struct spdk_iscsi_conn *conn), 0); 153 154 DEFINE_STUB_V(spdk_free_sess, (struct spdk_iscsi_sess *sess)); 155 156 DEFINE_STUB(spdk_iscsi_tgt_node_cleanup_luns, int, 157 (struct spdk_iscsi_conn *conn, struct spdk_iscsi_tgt_node *target), 158 0); 159 160 DEFINE_STUB(spdk_iscsi_pdu_calc_header_digest, uint32_t, 161 (struct spdk_iscsi_pdu *pdu), 0); 162 163 DEFINE_STUB(spdk_iscsi_pdu_calc_data_digest, uint32_t, 164 (struct spdk_iscsi_pdu *pdu), 0); 165 166 DEFINE_STUB_V(spdk_shutdown_iscsi_conns_done, (void)); 167 168 static struct spdk_iscsi_task * 169 ut_conn_task_get(struct spdk_iscsi_task *parent) 170 { 171 struct spdk_iscsi_task *task; 172 173 task = calloc(1, sizeof(*task)); 174 SPDK_CU_ASSERT_FATAL(task != NULL); 175 176 if (parent) { 177 task->parent = parent; 178 } 179 return task; 180 } 181 182 static void 183 ut_conn_create_read_tasks(int transfer_len) 184 { 185 struct spdk_iscsi_task *task, *subtask; 186 int32_t remaining_size = 0; 187 188 task = ut_conn_task_get(NULL); 189 190 task->scsi.transfer_len = transfer_len; 191 task->scsi.offset = 0; 192 task->scsi.length = DMIN32(SPDK_BDEV_LARGE_BUF_MAX_SIZE, task->scsi.transfer_len); 193 task->scsi.status = SPDK_SCSI_STATUS_GOOD; 194 195 remaining_size = task->scsi.transfer_len - task->scsi.length; 196 task->current_datain_offset = 0; 197 198 if (remaining_size == 0) { 199 TAILQ_INSERT_TAIL(&g_ut_read_tasks, task, link); 200 return; 201 } 202 203 while (1) { 204 if (task->current_datain_offset == 0) { 205 task->current_datain_offset = task->scsi.length; 206 TAILQ_INSERT_TAIL(&g_ut_read_tasks, task, link); 207 continue; 208 } 209 210 if (task->current_datain_offset < task->scsi.transfer_len) { 211 remaining_size = task->scsi.transfer_len - task->current_datain_offset; 212 213 subtask = ut_conn_task_get(task); 214 215 subtask->scsi.offset = task->current_datain_offset; 216 subtask->scsi.length = DMIN32(SPDK_BDEV_LARGE_BUF_MAX_SIZE, remaining_size); 217 subtask->scsi.status = SPDK_SCSI_STATUS_GOOD; 218 219 task->current_datain_offset += subtask->scsi.length; 220 221 TAILQ_INSERT_TAIL(&g_ut_read_tasks, subtask, link); 222 } 223 224 if (task->current_datain_offset == task->scsi.transfer_len) { 225 break; 226 } 227 } 228 } 229 230 static void 231 read_task_split_in_order_case(void) 232 { 233 struct spdk_iscsi_task *primary, *task, *tmp; 234 235 ut_conn_create_read_tasks(SPDK_BDEV_LARGE_BUF_MAX_SIZE * 8); 236 237 TAILQ_FOREACH(task, &g_ut_read_tasks, link) { 238 primary = spdk_iscsi_task_get_primary(task); 239 process_read_task_completion(NULL, task, primary); 240 } 241 242 primary = TAILQ_FIRST(&g_ut_read_tasks); 243 SPDK_CU_ASSERT_FATAL(primary != NULL); 244 245 if (primary != NULL) { 246 CU_ASSERT(primary->bytes_completed == primary->scsi.transfer_len); 247 } 248 249 TAILQ_FOREACH_SAFE(task, &g_ut_read_tasks, link, tmp) { 250 TAILQ_REMOVE(&g_ut_read_tasks, task, link); 251 free(task); 252 } 253 254 CU_ASSERT(TAILQ_EMPTY(&g_ut_read_tasks)); 255 } 256 257 static void 258 propagate_scsi_error_status_for_split_read_tasks(void) 259 { 260 struct spdk_iscsi_task primary, task1, task2, task3, task4, task5, task6; 261 262 memset(&primary, 0, sizeof(struct spdk_iscsi_task)); 263 primary.scsi.length = 512; 264 primary.scsi.status = SPDK_SCSI_STATUS_GOOD; 265 primary.rsp_scsi_status = SPDK_SCSI_STATUS_GOOD; 266 TAILQ_INIT(&primary.subtask_list); 267 268 memset(&task1, 0, sizeof(struct spdk_iscsi_task)); 269 task1.scsi.offset = 512; 270 task1.scsi.length = 512; 271 task1.scsi.status = SPDK_SCSI_STATUS_GOOD; 272 273 memset(&task2, 0, sizeof(struct spdk_iscsi_task)); 274 task2.scsi.offset = 512 * 2; 275 task2.scsi.length = 512; 276 task2.scsi.status = SPDK_SCSI_STATUS_CHECK_CONDITION; 277 278 memset(&task3, 0, sizeof(struct spdk_iscsi_task)); 279 task3.scsi.offset = 512 * 3; 280 task3.scsi.length = 512; 281 task3.scsi.status = SPDK_SCSI_STATUS_GOOD; 282 283 memset(&task4, 0, sizeof(struct spdk_iscsi_task)); 284 task4.scsi.offset = 512 * 4; 285 task4.scsi.length = 512; 286 task4.scsi.status = SPDK_SCSI_STATUS_GOOD; 287 288 memset(&task5, 0, sizeof(struct spdk_iscsi_task)); 289 task5.scsi.offset = 512 * 5; 290 task5.scsi.length = 512; 291 task5.scsi.status = SPDK_SCSI_STATUS_GOOD; 292 293 memset(&task6, 0, sizeof(struct spdk_iscsi_task)); 294 task6.scsi.offset = 512 * 6; 295 task6.scsi.length = 512; 296 task6.scsi.status = SPDK_SCSI_STATUS_GOOD; 297 298 /* task2 has check condition status, and verify if the check condition 299 * status is propagated to remaining tasks correctly when these tasks complete 300 * by the following order, task4, task3, task2, task1, primary, task5, and task6. 301 */ 302 process_read_task_completion(NULL, &task4, &primary); 303 process_read_task_completion(NULL, &task3, &primary); 304 process_read_task_completion(NULL, &task2, &primary); 305 process_read_task_completion(NULL, &task1, &primary); 306 process_read_task_completion(NULL, &primary, &primary); 307 process_read_task_completion(NULL, &task5, &primary); 308 process_read_task_completion(NULL, &task6, &primary); 309 310 CU_ASSERT(primary.scsi.status == SPDK_SCSI_STATUS_CHECK_CONDITION); 311 CU_ASSERT(task1.scsi.status == SPDK_SCSI_STATUS_CHECK_CONDITION); 312 CU_ASSERT(task2.scsi.status == SPDK_SCSI_STATUS_CHECK_CONDITION); 313 CU_ASSERT(task3.scsi.status == SPDK_SCSI_STATUS_CHECK_CONDITION); 314 CU_ASSERT(task4.scsi.status == SPDK_SCSI_STATUS_CHECK_CONDITION); 315 CU_ASSERT(task5.scsi.status == SPDK_SCSI_STATUS_CHECK_CONDITION); 316 CU_ASSERT(task6.scsi.status == SPDK_SCSI_STATUS_CHECK_CONDITION); 317 CU_ASSERT(TAILQ_EMPTY(&primary.subtask_list)); 318 } 319 320 int 321 main(int argc, char **argv) 322 { 323 CU_pSuite suite = NULL; 324 unsigned int num_failures; 325 326 if (CU_initialize_registry() != CUE_SUCCESS) { 327 return CU_get_error(); 328 } 329 330 suite = CU_add_suite("conn_suite", NULL, NULL); 331 if (suite == NULL) { 332 CU_cleanup_registry(); 333 return CU_get_error(); 334 } 335 336 if ( 337 CU_add_test(suite, "read task split in order", read_task_split_in_order_case) == NULL || 338 CU_add_test(suite, "propagate_scsi_error_status_for_split_read_tasks", 339 propagate_scsi_error_status_for_split_read_tasks) == NULL 340 ) { 341 CU_cleanup_registry(); 342 return CU_get_error(); 343 } 344 345 CU_basic_set_mode(CU_BRM_VERBOSE); 346 CU_basic_run_tests(); 347 num_failures = CU_get_number_of_failures(); 348 CU_cleanup_registry(); 349 return num_failures; 350 } 351