1 /******************************************************************************* 2 * This file contains the iSCSI Target DataIN value generation functions. 3 * 4 * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. 5 * 6 * Licensed to the Linux Foundation under the General Public License (GPL) version 2. 7 * 8 * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 ******************************************************************************/ 20 21 #include <scsi/iscsi_proto.h> 22 23 #include "iscsi_target_core.h" 24 #include "iscsi_target_seq_pdu_list.h" 25 #include "iscsi_target_erl1.h" 26 #include "iscsi_target_util.h" 27 #include "iscsi_target.h" 28 #include "iscsi_target_datain_values.h" 29 30 struct iscsi_datain_req *iscsit_allocate_datain_req(void) 31 { 32 struct iscsi_datain_req *dr; 33 34 dr = kmem_cache_zalloc(lio_dr_cache, GFP_ATOMIC); 35 if (!dr) { 36 pr_err("Unable to allocate memory for" 37 " struct iscsi_datain_req\n"); 38 return NULL; 39 } 40 INIT_LIST_HEAD(&dr->dr_list); 41 42 return dr; 43 } 44 45 void iscsit_attach_datain_req(struct iscsi_cmd *cmd, struct iscsi_datain_req *dr) 46 { 47 spin_lock(&cmd->datain_lock); 48 list_add_tail(&dr->dr_list, &cmd->datain_list); 49 spin_unlock(&cmd->datain_lock); 50 } 51 52 void iscsit_free_datain_req(struct iscsi_cmd *cmd, struct iscsi_datain_req *dr) 53 { 54 spin_lock(&cmd->datain_lock); 55 list_del(&dr->dr_list); 56 spin_unlock(&cmd->datain_lock); 57 58 kmem_cache_free(lio_dr_cache, dr); 59 } 60 61 void iscsit_free_all_datain_reqs(struct iscsi_cmd *cmd) 62 { 63 struct iscsi_datain_req *dr, *dr_tmp; 64 65 spin_lock(&cmd->datain_lock); 66 list_for_each_entry_safe(dr, dr_tmp, &cmd->datain_list, dr_list) { 67 list_del(&dr->dr_list); 68 kmem_cache_free(lio_dr_cache, dr); 69 } 70 spin_unlock(&cmd->datain_lock); 71 } 72 73 struct iscsi_datain_req *iscsit_get_datain_req(struct iscsi_cmd *cmd) 74 { 75 struct iscsi_datain_req *dr; 76 77 if (list_empty(&cmd->datain_list)) { 78 pr_err("cmd->datain_list is empty for ITT:" 79 " 0x%08x\n", cmd->init_task_tag); 80 return NULL; 81 } 82 list_for_each_entry(dr, &cmd->datain_list, dr_list) 83 break; 84 85 return dr; 86 } 87 88 /* 89 * For Normal and Recovery DataSequenceInOrder=Yes and DataPDUInOrder=Yes. 90 */ 91 static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_yes( 92 struct iscsi_cmd *cmd, 93 struct iscsi_datain *datain) 94 { 95 u32 next_burst_len, read_data_done, read_data_left; 96 struct iscsi_conn *conn = cmd->conn; 97 struct iscsi_datain_req *dr; 98 99 dr = iscsit_get_datain_req(cmd); 100 if (!dr) 101 return NULL; 102 103 if (dr->recovery && dr->generate_recovery_values) { 104 if (iscsit_create_recovery_datain_values_datasequenceinorder_yes( 105 cmd, dr) < 0) 106 return NULL; 107 108 dr->generate_recovery_values = 0; 109 } 110 111 next_burst_len = (!dr->recovery) ? 112 cmd->next_burst_len : dr->next_burst_len; 113 read_data_done = (!dr->recovery) ? 114 cmd->read_data_done : dr->read_data_done; 115 116 read_data_left = (cmd->data_length - read_data_done); 117 if (!read_data_left) { 118 pr_err("ITT: 0x%08x read_data_left is zero!\n", 119 cmd->init_task_tag); 120 return NULL; 121 } 122 123 if ((read_data_left <= conn->conn_ops->MaxRecvDataSegmentLength) && 124 (read_data_left <= (conn->sess->sess_ops->MaxBurstLength - 125 next_burst_len))) { 126 datain->length = read_data_left; 127 128 datain->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS); 129 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) 130 datain->flags |= ISCSI_FLAG_DATA_ACK; 131 } else { 132 if ((next_burst_len + 133 conn->conn_ops->MaxRecvDataSegmentLength) < 134 conn->sess->sess_ops->MaxBurstLength) { 135 datain->length = 136 conn->conn_ops->MaxRecvDataSegmentLength; 137 next_burst_len += datain->length; 138 } else { 139 datain->length = (conn->sess->sess_ops->MaxBurstLength - 140 next_burst_len); 141 next_burst_len = 0; 142 143 datain->flags |= ISCSI_FLAG_CMD_FINAL; 144 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) 145 datain->flags |= ISCSI_FLAG_DATA_ACK; 146 } 147 } 148 149 datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++; 150 datain->offset = read_data_done; 151 152 if (!dr->recovery) { 153 cmd->next_burst_len = next_burst_len; 154 cmd->read_data_done += datain->length; 155 } else { 156 dr->next_burst_len = next_burst_len; 157 dr->read_data_done += datain->length; 158 } 159 160 if (!dr->recovery) { 161 if (datain->flags & ISCSI_FLAG_DATA_STATUS) 162 dr->dr_complete = DATAIN_COMPLETE_NORMAL; 163 164 return dr; 165 } 166 167 if (!dr->runlength) { 168 if (datain->flags & ISCSI_FLAG_DATA_STATUS) { 169 dr->dr_complete = 170 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? 171 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : 172 DATAIN_COMPLETE_CONNECTION_RECOVERY; 173 } 174 } else { 175 if ((dr->begrun + dr->runlength) == dr->data_sn) { 176 dr->dr_complete = 177 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? 178 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : 179 DATAIN_COMPLETE_CONNECTION_RECOVERY; 180 } 181 } 182 183 return dr; 184 } 185 186 /* 187 * For Normal and Recovery DataSequenceInOrder=No and DataPDUInOrder=Yes. 188 */ 189 static struct iscsi_datain_req *iscsit_set_datain_values_no_and_yes( 190 struct iscsi_cmd *cmd, 191 struct iscsi_datain *datain) 192 { 193 u32 offset, read_data_done, read_data_left, seq_send_order; 194 struct iscsi_conn *conn = cmd->conn; 195 struct iscsi_datain_req *dr; 196 struct iscsi_seq *seq; 197 198 dr = iscsit_get_datain_req(cmd); 199 if (!dr) 200 return NULL; 201 202 if (dr->recovery && dr->generate_recovery_values) { 203 if (iscsit_create_recovery_datain_values_datasequenceinorder_no( 204 cmd, dr) < 0) 205 return NULL; 206 207 dr->generate_recovery_values = 0; 208 } 209 210 read_data_done = (!dr->recovery) ? 211 cmd->read_data_done : dr->read_data_done; 212 seq_send_order = (!dr->recovery) ? 213 cmd->seq_send_order : dr->seq_send_order; 214 215 read_data_left = (cmd->data_length - read_data_done); 216 if (!read_data_left) { 217 pr_err("ITT: 0x%08x read_data_left is zero!\n", 218 cmd->init_task_tag); 219 return NULL; 220 } 221 222 seq = iscsit_get_seq_holder_for_datain(cmd, seq_send_order); 223 if (!seq) 224 return NULL; 225 226 seq->sent = 1; 227 228 if (!dr->recovery && !seq->next_burst_len) 229 seq->first_datasn = cmd->data_sn; 230 231 offset = (seq->offset + seq->next_burst_len); 232 233 if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >= 234 cmd->data_length) { 235 datain->length = (cmd->data_length - offset); 236 datain->offset = offset; 237 238 datain->flags |= ISCSI_FLAG_CMD_FINAL; 239 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) 240 datain->flags |= ISCSI_FLAG_DATA_ACK; 241 242 seq->next_burst_len = 0; 243 seq_send_order++; 244 } else { 245 if ((seq->next_burst_len + 246 conn->conn_ops->MaxRecvDataSegmentLength) < 247 conn->sess->sess_ops->MaxBurstLength) { 248 datain->length = 249 conn->conn_ops->MaxRecvDataSegmentLength; 250 datain->offset = (seq->offset + seq->next_burst_len); 251 252 seq->next_burst_len += datain->length; 253 } else { 254 datain->length = (conn->sess->sess_ops->MaxBurstLength - 255 seq->next_burst_len); 256 datain->offset = (seq->offset + seq->next_burst_len); 257 258 datain->flags |= ISCSI_FLAG_CMD_FINAL; 259 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) 260 datain->flags |= ISCSI_FLAG_DATA_ACK; 261 262 seq->next_burst_len = 0; 263 seq_send_order++; 264 } 265 } 266 267 if ((read_data_done + datain->length) == cmd->data_length) 268 datain->flags |= ISCSI_FLAG_DATA_STATUS; 269 270 datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++; 271 if (!dr->recovery) { 272 cmd->seq_send_order = seq_send_order; 273 cmd->read_data_done += datain->length; 274 } else { 275 dr->seq_send_order = seq_send_order; 276 dr->read_data_done += datain->length; 277 } 278 279 if (!dr->recovery) { 280 if (datain->flags & ISCSI_FLAG_CMD_FINAL) 281 seq->last_datasn = datain->data_sn; 282 if (datain->flags & ISCSI_FLAG_DATA_STATUS) 283 dr->dr_complete = DATAIN_COMPLETE_NORMAL; 284 285 return dr; 286 } 287 288 if (!dr->runlength) { 289 if (datain->flags & ISCSI_FLAG_DATA_STATUS) { 290 dr->dr_complete = 291 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? 292 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : 293 DATAIN_COMPLETE_CONNECTION_RECOVERY; 294 } 295 } else { 296 if ((dr->begrun + dr->runlength) == dr->data_sn) { 297 dr->dr_complete = 298 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? 299 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : 300 DATAIN_COMPLETE_CONNECTION_RECOVERY; 301 } 302 } 303 304 return dr; 305 } 306 307 /* 308 * For Normal and Recovery DataSequenceInOrder=Yes and DataPDUInOrder=No. 309 */ 310 static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_no( 311 struct iscsi_cmd *cmd, 312 struct iscsi_datain *datain) 313 { 314 u32 next_burst_len, read_data_done, read_data_left; 315 struct iscsi_conn *conn = cmd->conn; 316 struct iscsi_datain_req *dr; 317 struct iscsi_pdu *pdu; 318 319 dr = iscsit_get_datain_req(cmd); 320 if (!dr) 321 return NULL; 322 323 if (dr->recovery && dr->generate_recovery_values) { 324 if (iscsit_create_recovery_datain_values_datasequenceinorder_yes( 325 cmd, dr) < 0) 326 return NULL; 327 328 dr->generate_recovery_values = 0; 329 } 330 331 next_burst_len = (!dr->recovery) ? 332 cmd->next_burst_len : dr->next_burst_len; 333 read_data_done = (!dr->recovery) ? 334 cmd->read_data_done : dr->read_data_done; 335 336 read_data_left = (cmd->data_length - read_data_done); 337 if (!read_data_left) { 338 pr_err("ITT: 0x%08x read_data_left is zero!\n", 339 cmd->init_task_tag); 340 return dr; 341 } 342 343 pdu = iscsit_get_pdu_holder_for_seq(cmd, NULL); 344 if (!pdu) 345 return dr; 346 347 if ((read_data_done + pdu->length) == cmd->data_length) { 348 pdu->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS); 349 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) 350 pdu->flags |= ISCSI_FLAG_DATA_ACK; 351 352 next_burst_len = 0; 353 } else { 354 if ((next_burst_len + conn->conn_ops->MaxRecvDataSegmentLength) < 355 conn->sess->sess_ops->MaxBurstLength) 356 next_burst_len += pdu->length; 357 else { 358 pdu->flags |= ISCSI_FLAG_CMD_FINAL; 359 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) 360 pdu->flags |= ISCSI_FLAG_DATA_ACK; 361 362 next_burst_len = 0; 363 } 364 } 365 366 pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++; 367 if (!dr->recovery) { 368 cmd->next_burst_len = next_burst_len; 369 cmd->read_data_done += pdu->length; 370 } else { 371 dr->next_burst_len = next_burst_len; 372 dr->read_data_done += pdu->length; 373 } 374 375 datain->flags = pdu->flags; 376 datain->length = pdu->length; 377 datain->offset = pdu->offset; 378 datain->data_sn = pdu->data_sn; 379 380 if (!dr->recovery) { 381 if (datain->flags & ISCSI_FLAG_DATA_STATUS) 382 dr->dr_complete = DATAIN_COMPLETE_NORMAL; 383 384 return dr; 385 } 386 387 if (!dr->runlength) { 388 if (datain->flags & ISCSI_FLAG_DATA_STATUS) { 389 dr->dr_complete = 390 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? 391 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : 392 DATAIN_COMPLETE_CONNECTION_RECOVERY; 393 } 394 } else { 395 if ((dr->begrun + dr->runlength) == dr->data_sn) { 396 dr->dr_complete = 397 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? 398 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : 399 DATAIN_COMPLETE_CONNECTION_RECOVERY; 400 } 401 } 402 403 return dr; 404 } 405 406 /* 407 * For Normal and Recovery DataSequenceInOrder=No and DataPDUInOrder=No. 408 */ 409 static struct iscsi_datain_req *iscsit_set_datain_values_no_and_no( 410 struct iscsi_cmd *cmd, 411 struct iscsi_datain *datain) 412 { 413 u32 read_data_done, read_data_left, seq_send_order; 414 struct iscsi_conn *conn = cmd->conn; 415 struct iscsi_datain_req *dr; 416 struct iscsi_pdu *pdu; 417 struct iscsi_seq *seq = NULL; 418 419 dr = iscsit_get_datain_req(cmd); 420 if (!dr) 421 return NULL; 422 423 if (dr->recovery && dr->generate_recovery_values) { 424 if (iscsit_create_recovery_datain_values_datasequenceinorder_no( 425 cmd, dr) < 0) 426 return NULL; 427 428 dr->generate_recovery_values = 0; 429 } 430 431 read_data_done = (!dr->recovery) ? 432 cmd->read_data_done : dr->read_data_done; 433 seq_send_order = (!dr->recovery) ? 434 cmd->seq_send_order : dr->seq_send_order; 435 436 read_data_left = (cmd->data_length - read_data_done); 437 if (!read_data_left) { 438 pr_err("ITT: 0x%08x read_data_left is zero!\n", 439 cmd->init_task_tag); 440 return NULL; 441 } 442 443 seq = iscsit_get_seq_holder_for_datain(cmd, seq_send_order); 444 if (!seq) 445 return NULL; 446 447 seq->sent = 1; 448 449 if (!dr->recovery && !seq->next_burst_len) 450 seq->first_datasn = cmd->data_sn; 451 452 pdu = iscsit_get_pdu_holder_for_seq(cmd, seq); 453 if (!pdu) 454 return NULL; 455 456 if (seq->pdu_send_order == seq->pdu_count) { 457 pdu->flags |= ISCSI_FLAG_CMD_FINAL; 458 if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) 459 pdu->flags |= ISCSI_FLAG_DATA_ACK; 460 461 seq->next_burst_len = 0; 462 seq_send_order++; 463 } else 464 seq->next_burst_len += pdu->length; 465 466 if ((read_data_done + pdu->length) == cmd->data_length) 467 pdu->flags |= ISCSI_FLAG_DATA_STATUS; 468 469 pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++; 470 if (!dr->recovery) { 471 cmd->seq_send_order = seq_send_order; 472 cmd->read_data_done += pdu->length; 473 } else { 474 dr->seq_send_order = seq_send_order; 475 dr->read_data_done += pdu->length; 476 } 477 478 datain->flags = pdu->flags; 479 datain->length = pdu->length; 480 datain->offset = pdu->offset; 481 datain->data_sn = pdu->data_sn; 482 483 if (!dr->recovery) { 484 if (datain->flags & ISCSI_FLAG_CMD_FINAL) 485 seq->last_datasn = datain->data_sn; 486 if (datain->flags & ISCSI_FLAG_DATA_STATUS) 487 dr->dr_complete = DATAIN_COMPLETE_NORMAL; 488 489 return dr; 490 } 491 492 if (!dr->runlength) { 493 if (datain->flags & ISCSI_FLAG_DATA_STATUS) { 494 dr->dr_complete = 495 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? 496 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : 497 DATAIN_COMPLETE_CONNECTION_RECOVERY; 498 } 499 } else { 500 if ((dr->begrun + dr->runlength) == dr->data_sn) { 501 dr->dr_complete = 502 (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? 503 DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : 504 DATAIN_COMPLETE_CONNECTION_RECOVERY; 505 } 506 } 507 508 return dr; 509 } 510 511 struct iscsi_datain_req *iscsit_get_datain_values( 512 struct iscsi_cmd *cmd, 513 struct iscsi_datain *datain) 514 { 515 struct iscsi_conn *conn = cmd->conn; 516 517 if (conn->sess->sess_ops->DataSequenceInOrder && 518 conn->sess->sess_ops->DataPDUInOrder) 519 return iscsit_set_datain_values_yes_and_yes(cmd, datain); 520 else if (!conn->sess->sess_ops->DataSequenceInOrder && 521 conn->sess->sess_ops->DataPDUInOrder) 522 return iscsit_set_datain_values_no_and_yes(cmd, datain); 523 else if (conn->sess->sess_ops->DataSequenceInOrder && 524 !conn->sess->sess_ops->DataPDUInOrder) 525 return iscsit_set_datain_values_yes_and_no(cmd, datain); 526 else if (!conn->sess->sess_ops->DataSequenceInOrder && 527 !conn->sess->sess_ops->DataPDUInOrder) 528 return iscsit_set_datain_values_no_and_no(cmd, datain); 529 530 return NULL; 531 } 532