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