937 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/******************************************************************************3 * This file contains error recovery level zero functions used by4 * the iSCSI Target driver.5 *6 * (c) Copyright 2007-2013 Datera, Inc.7 *8 * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>9 *10 ******************************************************************************/11 12#include <linux/sched/signal.h>13 14#include <scsi/iscsi_proto.h>15#include <target/target_core_base.h>16#include <target/target_core_fabric.h>17 18#include <target/iscsi/iscsi_target_core.h>19#include "iscsi_target_seq_pdu_list.h"20#include "iscsi_target_erl0.h"21#include "iscsi_target_erl1.h"22#include "iscsi_target_erl2.h"23#include "iscsi_target_util.h"24#include "iscsi_target.h"25 26/*27 * Used to set values in struct iscsit_cmd that iscsit_dataout_check_sequence()28 * checks against to determine a PDU's Offset+Length is within the current29 * DataOUT Sequence. Used for DataSequenceInOrder=Yes only.30 */31void iscsit_set_dataout_sequence_values(32 struct iscsit_cmd *cmd)33{34 struct iscsit_conn *conn = cmd->conn;35 /*36 * Still set seq_start_offset and seq_end_offset for Unsolicited37 * DataOUT, even if DataSequenceInOrder=No.38 */39 if (cmd->unsolicited_data) {40 cmd->seq_start_offset = cmd->write_data_done;41 cmd->seq_end_offset = min(cmd->se_cmd.data_length,42 conn->sess->sess_ops->FirstBurstLength);43 return;44 }45 46 if (!conn->sess->sess_ops->DataSequenceInOrder)47 return;48 49 if (!cmd->seq_start_offset && !cmd->seq_end_offset) {50 cmd->seq_start_offset = cmd->write_data_done;51 cmd->seq_end_offset = (cmd->se_cmd.data_length >52 conn->sess->sess_ops->MaxBurstLength) ?53 (cmd->write_data_done +54 conn->sess->sess_ops->MaxBurstLength) : cmd->se_cmd.data_length;55 } else {56 cmd->seq_start_offset = cmd->seq_end_offset;57 cmd->seq_end_offset = ((cmd->seq_end_offset +58 conn->sess->sess_ops->MaxBurstLength) >=59 cmd->se_cmd.data_length) ? cmd->se_cmd.data_length :60 (cmd->seq_end_offset +61 conn->sess->sess_ops->MaxBurstLength);62 }63}64 65static int iscsit_dataout_within_command_recovery_check(66 struct iscsit_cmd *cmd,67 unsigned char *buf)68{69 struct iscsit_conn *conn = cmd->conn;70 struct iscsi_data *hdr = (struct iscsi_data *) buf;71 u32 payload_length = ntoh24(hdr->dlength);72 73 /*74 * We do the within-command recovery checks here as it is75 * the first function called in iscsi_check_pre_dataout().76 * Basically, if we are in within-command recovery and77 * the PDU does not contain the offset the sequence needs,78 * dump the payload.79 *80 * This only applies to DataPDUInOrder=Yes, for81 * DataPDUInOrder=No we only re-request the failed PDU82 * and check that all PDUs in a sequence are received83 * upon end of sequence.84 */85 if (conn->sess->sess_ops->DataSequenceInOrder) {86 if ((cmd->cmd_flags & ICF_WITHIN_COMMAND_RECOVERY) &&87 cmd->write_data_done != be32_to_cpu(hdr->offset))88 goto dump;89 90 cmd->cmd_flags &= ~ICF_WITHIN_COMMAND_RECOVERY;91 } else {92 struct iscsi_seq *seq;93 94 seq = iscsit_get_seq_holder(cmd, be32_to_cpu(hdr->offset),95 payload_length);96 if (!seq)97 return DATAOUT_CANNOT_RECOVER;98 /*99 * Set the struct iscsi_seq pointer to reuse later.100 */101 cmd->seq_ptr = seq;102 103 if (conn->sess->sess_ops->DataPDUInOrder) {104 if (seq->status ==105 DATAOUT_SEQUENCE_WITHIN_COMMAND_RECOVERY &&106 (seq->offset != be32_to_cpu(hdr->offset) ||107 seq->data_sn != be32_to_cpu(hdr->datasn)))108 goto dump;109 } else {110 if (seq->status ==111 DATAOUT_SEQUENCE_WITHIN_COMMAND_RECOVERY &&112 seq->data_sn != be32_to_cpu(hdr->datasn))113 goto dump;114 }115 116 if (seq->status == DATAOUT_SEQUENCE_COMPLETE)117 goto dump;118 119 if (seq->status != DATAOUT_SEQUENCE_COMPLETE)120 seq->status = 0;121 }122 123 return DATAOUT_NORMAL;124 125dump:126 pr_err("Dumping DataOUT PDU Offset: %u Length: %d DataSN:"127 " 0x%08x\n", hdr->offset, payload_length, hdr->datasn);128 return iscsit_dump_data_payload(conn, payload_length, 1);129}130 131static int iscsit_dataout_check_unsolicited_sequence(132 struct iscsit_cmd *cmd,133 unsigned char *buf)134{135 u32 first_burst_len;136 struct iscsit_conn *conn = cmd->conn;137 struct iscsi_data *hdr = (struct iscsi_data *) buf;138 u32 payload_length = ntoh24(hdr->dlength);139 140 141 if ((be32_to_cpu(hdr->offset) < cmd->seq_start_offset) ||142 ((be32_to_cpu(hdr->offset) + payload_length) > cmd->seq_end_offset)) {143 pr_err("Command ITT: 0x%08x with Offset: %u,"144 " Length: %u outside of Unsolicited Sequence %u:%u while"145 " DataSequenceInOrder=Yes.\n", cmd->init_task_tag,146 be32_to_cpu(hdr->offset), payload_length, cmd->seq_start_offset,147 cmd->seq_end_offset);148 return DATAOUT_CANNOT_RECOVER;149 }150 151 first_burst_len = (cmd->first_burst_len + payload_length);152 153 if (first_burst_len > conn->sess->sess_ops->FirstBurstLength) {154 pr_err("Total %u bytes exceeds FirstBurstLength: %u"155 " for this Unsolicited DataOut Burst.\n",156 first_burst_len, conn->sess->sess_ops->FirstBurstLength);157 transport_send_check_condition_and_sense(&cmd->se_cmd,158 TCM_INCORRECT_AMOUNT_OF_DATA, 0);159 return DATAOUT_CANNOT_RECOVER;160 }161 162 /*163 * Perform various MaxBurstLength and ISCSI_FLAG_CMD_FINAL sanity164 * checks for the current Unsolicited DataOUT Sequence.165 */166 if (hdr->flags & ISCSI_FLAG_CMD_FINAL) {167 /*168 * Ignore ISCSI_FLAG_CMD_FINAL checks while DataPDUInOrder=No, end of169 * sequence checks are handled in170 * iscsit_dataout_datapduinorder_no_fbit().171 */172 if (!conn->sess->sess_ops->DataPDUInOrder)173 goto out;174 175 if ((first_burst_len != cmd->se_cmd.data_length) &&176 (first_burst_len != conn->sess->sess_ops->FirstBurstLength)) {177 pr_err("Unsolicited non-immediate data"178 " received %u does not equal FirstBurstLength: %u, and"179 " does not equal ExpXferLen %u.\n", first_burst_len,180 conn->sess->sess_ops->FirstBurstLength,181 cmd->se_cmd.data_length);182 transport_send_check_condition_and_sense(&cmd->se_cmd,183 TCM_INCORRECT_AMOUNT_OF_DATA, 0);184 return DATAOUT_CANNOT_RECOVER;185 }186 } else {187 if (first_burst_len == conn->sess->sess_ops->FirstBurstLength) {188 pr_err("Command ITT: 0x%08x reached"189 " FirstBurstLength: %u, but ISCSI_FLAG_CMD_FINAL is not set. protocol"190 " error.\n", cmd->init_task_tag,191 conn->sess->sess_ops->FirstBurstLength);192 return DATAOUT_CANNOT_RECOVER;193 }194 if (first_burst_len == cmd->se_cmd.data_length) {195 pr_err("Command ITT: 0x%08x reached"196 " ExpXferLen: %u, but ISCSI_FLAG_CMD_FINAL is not set. protocol"197 " error.\n", cmd->init_task_tag, cmd->se_cmd.data_length);198 return DATAOUT_CANNOT_RECOVER;199 }200 }201 202out:203 return DATAOUT_NORMAL;204}205 206static int iscsit_dataout_check_sequence(207 struct iscsit_cmd *cmd,208 unsigned char *buf)209{210 u32 next_burst_len;211 struct iscsit_conn *conn = cmd->conn;212 struct iscsi_seq *seq = NULL;213 struct iscsi_data *hdr = (struct iscsi_data *) buf;214 u32 payload_length = ntoh24(hdr->dlength);215 216 /*217 * For DataSequenceInOrder=Yes: Check that the offset and offset+length218 * is within range as defined by iscsi_set_dataout_sequence_values().219 *220 * For DataSequenceInOrder=No: Check that an struct iscsi_seq exists for221 * offset+length tuple.222 */223 if (conn->sess->sess_ops->DataSequenceInOrder) {224 /*225 * Due to possibility of recovery DataOUT sent by the initiator226 * fullfilling an Recovery R2T, it's best to just dump the227 * payload here, instead of erroring out.228 */229 if ((be32_to_cpu(hdr->offset) < cmd->seq_start_offset) ||230 ((be32_to_cpu(hdr->offset) + payload_length) > cmd->seq_end_offset)) {231 pr_err("Command ITT: 0x%08x with Offset: %u,"232 " Length: %u outside of Sequence %u:%u while"233 " DataSequenceInOrder=Yes.\n", cmd->init_task_tag,234 be32_to_cpu(hdr->offset), payload_length, cmd->seq_start_offset,235 cmd->seq_end_offset);236 237 if (iscsit_dump_data_payload(conn, payload_length, 1) < 0)238 return DATAOUT_CANNOT_RECOVER;239 return DATAOUT_WITHIN_COMMAND_RECOVERY;240 }241 242 next_burst_len = (cmd->next_burst_len + payload_length);243 } else {244 seq = iscsit_get_seq_holder(cmd, be32_to_cpu(hdr->offset),245 payload_length);246 if (!seq)247 return DATAOUT_CANNOT_RECOVER;248 /*249 * Set the struct iscsi_seq pointer to reuse later.250 */251 cmd->seq_ptr = seq;252 253 if (seq->status == DATAOUT_SEQUENCE_COMPLETE) {254 if (iscsit_dump_data_payload(conn, payload_length, 1) < 0)255 return DATAOUT_CANNOT_RECOVER;256 return DATAOUT_WITHIN_COMMAND_RECOVERY;257 }258 259 next_burst_len = (seq->next_burst_len + payload_length);260 }261 262 if (next_burst_len > conn->sess->sess_ops->MaxBurstLength) {263 pr_err("Command ITT: 0x%08x, NextBurstLength: %u and"264 " Length: %u exceeds MaxBurstLength: %u. protocol"265 " error.\n", cmd->init_task_tag,266 (next_burst_len - payload_length),267 payload_length, conn->sess->sess_ops->MaxBurstLength);268 return DATAOUT_CANNOT_RECOVER;269 }270 271 /*272 * Perform various MaxBurstLength and ISCSI_FLAG_CMD_FINAL sanity273 * checks for the current DataOUT Sequence.274 */275 if (hdr->flags & ISCSI_FLAG_CMD_FINAL) {276 /*277 * Ignore ISCSI_FLAG_CMD_FINAL checks while DataPDUInOrder=No, end of278 * sequence checks are handled in279 * iscsit_dataout_datapduinorder_no_fbit().280 */281 if (!conn->sess->sess_ops->DataPDUInOrder)282 goto out;283 284 if (conn->sess->sess_ops->DataSequenceInOrder) {285 if ((next_burst_len <286 conn->sess->sess_ops->MaxBurstLength) &&287 ((cmd->write_data_done + payload_length) <288 cmd->se_cmd.data_length)) {289 pr_err("Command ITT: 0x%08x set ISCSI_FLAG_CMD_FINAL"290 " before end of DataOUT sequence, protocol"291 " error.\n", cmd->init_task_tag);292 return DATAOUT_CANNOT_RECOVER;293 }294 } else {295 if (next_burst_len < seq->xfer_len) {296 pr_err("Command ITT: 0x%08x set ISCSI_FLAG_CMD_FINAL"297 " before end of DataOUT sequence, protocol"298 " error.\n", cmd->init_task_tag);299 return DATAOUT_CANNOT_RECOVER;300 }301 }302 } else {303 if (conn->sess->sess_ops->DataSequenceInOrder) {304 if (next_burst_len ==305 conn->sess->sess_ops->MaxBurstLength) {306 pr_err("Command ITT: 0x%08x reached"307 " MaxBurstLength: %u, but ISCSI_FLAG_CMD_FINAL is"308 " not set, protocol error.", cmd->init_task_tag,309 conn->sess->sess_ops->MaxBurstLength);310 return DATAOUT_CANNOT_RECOVER;311 }312 if ((cmd->write_data_done + payload_length) ==313 cmd->se_cmd.data_length) {314 pr_err("Command ITT: 0x%08x reached"315 " last DataOUT PDU in sequence but ISCSI_FLAG_"316 "CMD_FINAL is not set, protocol error.\n",317 cmd->init_task_tag);318 return DATAOUT_CANNOT_RECOVER;319 }320 } else {321 if (next_burst_len == seq->xfer_len) {322 pr_err("Command ITT: 0x%08x reached"323 " last DataOUT PDU in sequence but ISCSI_FLAG_"324 "CMD_FINAL is not set, protocol error.\n",325 cmd->init_task_tag);326 return DATAOUT_CANNOT_RECOVER;327 }328 }329 }330 331out:332 return DATAOUT_NORMAL;333}334 335static int iscsit_dataout_check_datasn(336 struct iscsit_cmd *cmd,337 unsigned char *buf)338{339 u32 data_sn = 0;340 struct iscsit_conn *conn = cmd->conn;341 struct iscsi_data *hdr = (struct iscsi_data *) buf;342 u32 payload_length = ntoh24(hdr->dlength);343 344 /*345 * Considering the target has no method of re-requesting DataOUT346 * by DataSN, if we receieve a greater DataSN than expected we347 * assume the functions for DataPDUInOrder=[Yes,No] below will348 * handle it.349 *350 * If the DataSN is less than expected, dump the payload.351 */352 if (conn->sess->sess_ops->DataSequenceInOrder)353 data_sn = cmd->data_sn;354 else {355 struct iscsi_seq *seq = cmd->seq_ptr;356 data_sn = seq->data_sn;357 }358 359 if (be32_to_cpu(hdr->datasn) > data_sn) {360 pr_err("Command ITT: 0x%08x, received DataSN: 0x%08x"361 " higher than expected 0x%08x.\n", cmd->init_task_tag,362 be32_to_cpu(hdr->datasn), data_sn);363 goto recover;364 } else if (be32_to_cpu(hdr->datasn) < data_sn) {365 pr_err("Command ITT: 0x%08x, received DataSN: 0x%08x"366 " lower than expected 0x%08x, discarding payload.\n",367 cmd->init_task_tag, be32_to_cpu(hdr->datasn), data_sn);368 goto dump;369 }370 371 return DATAOUT_NORMAL;372 373recover:374 if (!conn->sess->sess_ops->ErrorRecoveryLevel) {375 pr_err("Unable to perform within-command recovery"376 " while ERL=0.\n");377 return DATAOUT_CANNOT_RECOVER;378 }379dump:380 if (iscsit_dump_data_payload(conn, payload_length, 1) < 0)381 return DATAOUT_CANNOT_RECOVER;382 383 return DATAOUT_WITHIN_COMMAND_RECOVERY;384}385 386static int iscsit_dataout_pre_datapduinorder_yes(387 struct iscsit_cmd *cmd,388 unsigned char *buf)389{390 int dump = 0, recovery = 0;391 struct iscsit_conn *conn = cmd->conn;392 struct iscsi_data *hdr = (struct iscsi_data *) buf;393 u32 payload_length = ntoh24(hdr->dlength);394 395 /*396 * For DataSequenceInOrder=Yes: If the offset is greater than the global397 * DataPDUInOrder=Yes offset counter in struct iscsit_cmd a protcol error has398 * occurred and fail the connection.399 *400 * For DataSequenceInOrder=No: If the offset is greater than the per401 * sequence DataPDUInOrder=Yes offset counter in struct iscsi_seq a protocol402 * error has occurred and fail the connection.403 */404 if (conn->sess->sess_ops->DataSequenceInOrder) {405 if (be32_to_cpu(hdr->offset) != cmd->write_data_done) {406 pr_err("Command ITT: 0x%08x, received offset"407 " %u different than expected %u.\n", cmd->init_task_tag,408 be32_to_cpu(hdr->offset), cmd->write_data_done);409 recovery = 1;410 goto recover;411 }412 } else {413 struct iscsi_seq *seq = cmd->seq_ptr;414 415 if (be32_to_cpu(hdr->offset) > seq->offset) {416 pr_err("Command ITT: 0x%08x, received offset"417 " %u greater than expected %u.\n", cmd->init_task_tag,418 be32_to_cpu(hdr->offset), seq->offset);419 recovery = 1;420 goto recover;421 } else if (be32_to_cpu(hdr->offset) < seq->offset) {422 pr_err("Command ITT: 0x%08x, received offset"423 " %u less than expected %u, discarding payload.\n",424 cmd->init_task_tag, be32_to_cpu(hdr->offset),425 seq->offset);426 dump = 1;427 goto dump;428 }429 }430 431 return DATAOUT_NORMAL;432 433recover:434 if (!conn->sess->sess_ops->ErrorRecoveryLevel) {435 pr_err("Unable to perform within-command recovery"436 " while ERL=0.\n");437 return DATAOUT_CANNOT_RECOVER;438 }439dump:440 if (iscsit_dump_data_payload(conn, payload_length, 1) < 0)441 return DATAOUT_CANNOT_RECOVER;442 443 return (recovery) ? iscsit_recover_dataout_sequence(cmd,444 be32_to_cpu(hdr->offset), payload_length) :445 (dump) ? DATAOUT_WITHIN_COMMAND_RECOVERY : DATAOUT_NORMAL;446}447 448static int iscsit_dataout_pre_datapduinorder_no(449 struct iscsit_cmd *cmd,450 unsigned char *buf)451{452 struct iscsi_pdu *pdu;453 struct iscsi_data *hdr = (struct iscsi_data *) buf;454 u32 payload_length = ntoh24(hdr->dlength);455 456 pdu = iscsit_get_pdu_holder(cmd, be32_to_cpu(hdr->offset),457 payload_length);458 if (!pdu)459 return DATAOUT_CANNOT_RECOVER;460 461 cmd->pdu_ptr = pdu;462 463 switch (pdu->status) {464 case ISCSI_PDU_NOT_RECEIVED:465 case ISCSI_PDU_CRC_FAILED:466 case ISCSI_PDU_TIMED_OUT:467 break;468 case ISCSI_PDU_RECEIVED_OK:469 pr_err("Command ITT: 0x%08x received already gotten"470 " Offset: %u, Length: %u\n", cmd->init_task_tag,471 be32_to_cpu(hdr->offset), payload_length);472 return iscsit_dump_data_payload(cmd->conn, payload_length, 1);473 default:474 return DATAOUT_CANNOT_RECOVER;475 }476 477 return DATAOUT_NORMAL;478}479 480static int iscsit_dataout_update_r2t(struct iscsit_cmd *cmd, u32 offset, u32 length)481{482 struct iscsi_r2t *r2t;483 484 if (cmd->unsolicited_data)485 return 0;486 487 r2t = iscsit_get_r2t_for_eos(cmd, offset, length);488 if (!r2t)489 return -1;490 491 spin_lock_bh(&cmd->r2t_lock);492 r2t->seq_complete = 1;493 cmd->outstanding_r2ts--;494 spin_unlock_bh(&cmd->r2t_lock);495 496 return 0;497}498 499static int iscsit_dataout_update_datapduinorder_no(500 struct iscsit_cmd *cmd,501 u32 data_sn,502 int f_bit)503{504 int ret = 0;505 struct iscsi_pdu *pdu = cmd->pdu_ptr;506 507 pdu->data_sn = data_sn;508 509 switch (pdu->status) {510 case ISCSI_PDU_NOT_RECEIVED:511 pdu->status = ISCSI_PDU_RECEIVED_OK;512 break;513 case ISCSI_PDU_CRC_FAILED:514 pdu->status = ISCSI_PDU_RECEIVED_OK;515 break;516 case ISCSI_PDU_TIMED_OUT:517 pdu->status = ISCSI_PDU_RECEIVED_OK;518 break;519 default:520 return DATAOUT_CANNOT_RECOVER;521 }522 523 if (f_bit) {524 ret = iscsit_dataout_datapduinorder_no_fbit(cmd, pdu);525 if (ret == DATAOUT_CANNOT_RECOVER)526 return ret;527 }528 529 return DATAOUT_NORMAL;530}531 532static int iscsit_dataout_post_crc_passed(533 struct iscsit_cmd *cmd,534 unsigned char *buf)535{536 int ret, send_r2t = 0;537 struct iscsit_conn *conn = cmd->conn;538 struct iscsi_seq *seq = NULL;539 struct iscsi_data *hdr = (struct iscsi_data *) buf;540 u32 payload_length = ntoh24(hdr->dlength);541 542 if (cmd->unsolicited_data) {543 if ((cmd->first_burst_len + payload_length) ==544 conn->sess->sess_ops->FirstBurstLength) {545 if (iscsit_dataout_update_r2t(cmd, be32_to_cpu(hdr->offset),546 payload_length) < 0)547 return DATAOUT_CANNOT_RECOVER;548 send_r2t = 1;549 }550 551 if (!conn->sess->sess_ops->DataPDUInOrder) {552 ret = iscsit_dataout_update_datapduinorder_no(cmd,553 be32_to_cpu(hdr->datasn),554 (hdr->flags & ISCSI_FLAG_CMD_FINAL));555 if (ret == DATAOUT_CANNOT_RECOVER)556 return ret;557 }558 559 cmd->first_burst_len += payload_length;560 561 if (conn->sess->sess_ops->DataSequenceInOrder)562 cmd->data_sn++;563 else {564 seq = cmd->seq_ptr;565 seq->data_sn++;566 seq->offset += payload_length;567 }568 569 if (send_r2t) {570 if (seq)571 seq->status = DATAOUT_SEQUENCE_COMPLETE;572 cmd->first_burst_len = 0;573 cmd->unsolicited_data = 0;574 }575 } else {576 if (conn->sess->sess_ops->DataSequenceInOrder) {577 if ((cmd->next_burst_len + payload_length) ==578 conn->sess->sess_ops->MaxBurstLength) {579 if (iscsit_dataout_update_r2t(cmd,580 be32_to_cpu(hdr->offset),581 payload_length) < 0)582 return DATAOUT_CANNOT_RECOVER;583 send_r2t = 1;584 }585 586 if (!conn->sess->sess_ops->DataPDUInOrder) {587 ret = iscsit_dataout_update_datapduinorder_no(588 cmd, be32_to_cpu(hdr->datasn),589 (hdr->flags & ISCSI_FLAG_CMD_FINAL));590 if (ret == DATAOUT_CANNOT_RECOVER)591 return ret;592 }593 594 cmd->next_burst_len += payload_length;595 cmd->data_sn++;596 597 if (send_r2t)598 cmd->next_burst_len = 0;599 } else {600 seq = cmd->seq_ptr;601 602 if ((seq->next_burst_len + payload_length) ==603 seq->xfer_len) {604 if (iscsit_dataout_update_r2t(cmd,605 be32_to_cpu(hdr->offset),606 payload_length) < 0)607 return DATAOUT_CANNOT_RECOVER;608 send_r2t = 1;609 }610 611 if (!conn->sess->sess_ops->DataPDUInOrder) {612 ret = iscsit_dataout_update_datapduinorder_no(613 cmd, be32_to_cpu(hdr->datasn),614 (hdr->flags & ISCSI_FLAG_CMD_FINAL));615 if (ret == DATAOUT_CANNOT_RECOVER)616 return ret;617 }618 619 seq->data_sn++;620 seq->offset += payload_length;621 seq->next_burst_len += payload_length;622 623 if (send_r2t) {624 seq->next_burst_len = 0;625 seq->status = DATAOUT_SEQUENCE_COMPLETE;626 }627 }628 }629 630 if (send_r2t && conn->sess->sess_ops->DataSequenceInOrder)631 cmd->data_sn = 0;632 633 cmd->write_data_done += payload_length;634 635 if (cmd->write_data_done == cmd->se_cmd.data_length)636 return DATAOUT_SEND_TO_TRANSPORT;637 else if (send_r2t)638 return DATAOUT_SEND_R2T;639 else640 return DATAOUT_NORMAL;641}642 643static int iscsit_dataout_post_crc_failed(644 struct iscsit_cmd *cmd,645 unsigned char *buf)646{647 struct iscsit_conn *conn = cmd->conn;648 struct iscsi_pdu *pdu;649 struct iscsi_data *hdr = (struct iscsi_data *) buf;650 u32 payload_length = ntoh24(hdr->dlength);651 652 if (conn->sess->sess_ops->DataPDUInOrder)653 goto recover;654 /*655 * The rest of this function is only called when DataPDUInOrder=No.656 */657 pdu = cmd->pdu_ptr;658 659 switch (pdu->status) {660 case ISCSI_PDU_NOT_RECEIVED:661 pdu->status = ISCSI_PDU_CRC_FAILED;662 break;663 case ISCSI_PDU_CRC_FAILED:664 break;665 case ISCSI_PDU_TIMED_OUT:666 pdu->status = ISCSI_PDU_CRC_FAILED;667 break;668 default:669 return DATAOUT_CANNOT_RECOVER;670 }671 672recover:673 return iscsit_recover_dataout_sequence(cmd, be32_to_cpu(hdr->offset),674 payload_length);675}676 677/*678 * Called from iscsit_handle_data_out() before DataOUT Payload is received679 * and CRC computed.680 */681int iscsit_check_pre_dataout(682 struct iscsit_cmd *cmd,683 unsigned char *buf)684{685 int ret;686 struct iscsit_conn *conn = cmd->conn;687 688 ret = iscsit_dataout_within_command_recovery_check(cmd, buf);689 if ((ret == DATAOUT_WITHIN_COMMAND_RECOVERY) ||690 (ret == DATAOUT_CANNOT_RECOVER))691 return ret;692 693 ret = iscsit_dataout_check_datasn(cmd, buf);694 if ((ret == DATAOUT_WITHIN_COMMAND_RECOVERY) ||695 (ret == DATAOUT_CANNOT_RECOVER))696 return ret;697 698 if (cmd->unsolicited_data) {699 ret = iscsit_dataout_check_unsolicited_sequence(cmd, buf);700 if ((ret == DATAOUT_WITHIN_COMMAND_RECOVERY) ||701 (ret == DATAOUT_CANNOT_RECOVER))702 return ret;703 } else {704 ret = iscsit_dataout_check_sequence(cmd, buf);705 if ((ret == DATAOUT_WITHIN_COMMAND_RECOVERY) ||706 (ret == DATAOUT_CANNOT_RECOVER))707 return ret;708 }709 710 return (conn->sess->sess_ops->DataPDUInOrder) ?711 iscsit_dataout_pre_datapduinorder_yes(cmd, buf) :712 iscsit_dataout_pre_datapduinorder_no(cmd, buf);713}714 715/*716 * Called from iscsit_handle_data_out() after DataOUT Payload is received717 * and CRC computed.718 */719int iscsit_check_post_dataout(720 struct iscsit_cmd *cmd,721 unsigned char *buf,722 u8 data_crc_failed)723{724 struct iscsit_conn *conn = cmd->conn;725 726 cmd->dataout_timeout_retries = 0;727 728 if (!data_crc_failed)729 return iscsit_dataout_post_crc_passed(cmd, buf);730 else {731 if (!conn->sess->sess_ops->ErrorRecoveryLevel) {732 pr_err("Unable to recover from DataOUT CRC"733 " failure while ERL=0, closing session.\n");734 iscsit_reject_cmd(cmd, ISCSI_REASON_DATA_DIGEST_ERROR,735 buf);736 return DATAOUT_CANNOT_RECOVER;737 }738 739 iscsit_reject_cmd(cmd, ISCSI_REASON_DATA_DIGEST_ERROR, buf);740 return iscsit_dataout_post_crc_failed(cmd, buf);741 }742}743 744void iscsit_handle_time2retain_timeout(struct timer_list *t)745{746 struct iscsit_session *sess = from_timer(sess, t, time2retain_timer);747 struct iscsi_portal_group *tpg = sess->tpg;748 struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;749 750 spin_lock_bh(&se_tpg->session_lock);751 if (sess->time2retain_timer_flags & ISCSI_TF_STOP) {752 spin_unlock_bh(&se_tpg->session_lock);753 return;754 }755 if (atomic_read(&sess->session_reinstatement)) {756 pr_err("Exiting Time2Retain handler because"757 " session_reinstatement=1\n");758 spin_unlock_bh(&se_tpg->session_lock);759 return;760 }761 sess->time2retain_timer_flags |= ISCSI_TF_EXPIRED;762 763 pr_err("Time2Retain timer expired for SID: %u, cleaning up"764 " iSCSI session.\n", sess->sid);765 766 iscsit_fill_cxn_timeout_err_stats(sess);767 spin_unlock_bh(&se_tpg->session_lock);768 iscsit_close_session(sess, false);769}770 771void iscsit_start_time2retain_handler(struct iscsit_session *sess)772{773 int tpg_active;774 /*775 * Only start Time2Retain timer when the associated TPG is still in776 * an ACTIVE (eg: not disabled or shutdown) state.777 */778 spin_lock(&sess->tpg->tpg_state_lock);779 tpg_active = (sess->tpg->tpg_state == TPG_STATE_ACTIVE);780 spin_unlock(&sess->tpg->tpg_state_lock);781 782 if (!tpg_active)783 return;784 785 if (sess->time2retain_timer_flags & ISCSI_TF_RUNNING)786 return;787 788 pr_debug("Starting Time2Retain timer for %u seconds on"789 " SID: %u\n", sess->sess_ops->DefaultTime2Retain, sess->sid);790 791 sess->time2retain_timer_flags &= ~ISCSI_TF_STOP;792 sess->time2retain_timer_flags |= ISCSI_TF_RUNNING;793 mod_timer(&sess->time2retain_timer,794 jiffies + sess->sess_ops->DefaultTime2Retain * HZ);795}796 797int iscsit_stop_time2retain_timer(struct iscsit_session *sess)798{799 struct iscsi_portal_group *tpg = sess->tpg;800 struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;801 802 lockdep_assert_held(&se_tpg->session_lock);803 804 if (sess->time2retain_timer_flags & ISCSI_TF_EXPIRED)805 return -1;806 807 if (!(sess->time2retain_timer_flags & ISCSI_TF_RUNNING))808 return 0;809 810 sess->time2retain_timer_flags |= ISCSI_TF_STOP;811 spin_unlock(&se_tpg->session_lock);812 813 del_timer_sync(&sess->time2retain_timer);814 815 spin_lock(&se_tpg->session_lock);816 sess->time2retain_timer_flags &= ~ISCSI_TF_RUNNING;817 pr_debug("Stopped Time2Retain Timer for SID: %u\n",818 sess->sid);819 return 0;820}821 822void iscsit_connection_reinstatement_rcfr(struct iscsit_conn *conn)823{824 spin_lock_bh(&conn->state_lock);825 if (atomic_read(&conn->connection_exit)) {826 spin_unlock_bh(&conn->state_lock);827 goto sleep;828 }829 830 if (atomic_read(&conn->transport_failed)) {831 spin_unlock_bh(&conn->state_lock);832 goto sleep;833 }834 spin_unlock_bh(&conn->state_lock);835 836 if (conn->tx_thread && conn->tx_thread_active)837 send_sig(SIGINT, conn->tx_thread, 1);838 if (conn->rx_thread && conn->rx_thread_active)839 send_sig(SIGINT, conn->rx_thread, 1);840 841sleep:842 wait_for_completion(&conn->conn_wait_rcfr_comp);843 complete(&conn->conn_post_wait_comp);844}845 846void iscsit_cause_connection_reinstatement(struct iscsit_conn *conn, int sleep)847{848 spin_lock_bh(&conn->state_lock);849 if (atomic_read(&conn->connection_exit)) {850 spin_unlock_bh(&conn->state_lock);851 return;852 }853 854 if (atomic_read(&conn->transport_failed)) {855 spin_unlock_bh(&conn->state_lock);856 return;857 }858 859 if (atomic_read(&conn->connection_reinstatement)) {860 spin_unlock_bh(&conn->state_lock);861 return;862 }863 864 if (conn->tx_thread && conn->tx_thread_active)865 send_sig(SIGINT, conn->tx_thread, 1);866 if (conn->rx_thread && conn->rx_thread_active)867 send_sig(SIGINT, conn->rx_thread, 1);868 869 atomic_set(&conn->connection_reinstatement, 1);870 if (!sleep) {871 spin_unlock_bh(&conn->state_lock);872 return;873 }874 875 atomic_set(&conn->sleep_on_conn_wait_comp, 1);876 spin_unlock_bh(&conn->state_lock);877 878 wait_for_completion(&conn->conn_wait_comp);879 complete(&conn->conn_post_wait_comp);880}881EXPORT_SYMBOL(iscsit_cause_connection_reinstatement);882 883void iscsit_fall_back_to_erl0(struct iscsit_session *sess)884{885 pr_debug("Falling back to ErrorRecoveryLevel=0 for SID:"886 " %u\n", sess->sid);887 888 atomic_set(&sess->session_fall_back_to_erl0, 1);889}890 891static void iscsit_handle_connection_cleanup(struct iscsit_conn *conn)892{893 struct iscsit_session *sess = conn->sess;894 895 if ((sess->sess_ops->ErrorRecoveryLevel == 2) &&896 !atomic_read(&sess->session_reinstatement) &&897 !atomic_read(&sess->session_fall_back_to_erl0))898 iscsit_connection_recovery_transport_reset(conn);899 else {900 pr_debug("Performing cleanup for failed iSCSI"901 " Connection ID: %hu from %s\n", conn->cid,902 sess->sess_ops->InitiatorName);903 iscsit_close_connection(conn);904 }905}906 907void iscsit_take_action_for_connection_exit(struct iscsit_conn *conn, bool *conn_freed)908{909 *conn_freed = false;910 911 spin_lock_bh(&conn->state_lock);912 if (atomic_read(&conn->connection_exit)) {913 spin_unlock_bh(&conn->state_lock);914 return;915 }916 atomic_set(&conn->connection_exit, 1);917 918 if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT) {919 spin_unlock_bh(&conn->state_lock);920 iscsit_close_connection(conn);921 *conn_freed = true;922 return;923 }924 925 if (conn->conn_state == TARG_CONN_STATE_CLEANUP_WAIT) {926 spin_unlock_bh(&conn->state_lock);927 return;928 }929 930 pr_debug("Moving to TARG_CONN_STATE_CLEANUP_WAIT.\n");931 conn->conn_state = TARG_CONN_STATE_CLEANUP_WAIT;932 spin_unlock_bh(&conn->state_lock);933 934 iscsit_handle_connection_cleanup(conn);935 *conn_freed = true;936}937