--- /dev/null
+From nab@linux-iscsi.org Fri Aug 2 06:54:09 2013
+From: "Nicholas A. Bellinger" <nab@linux-iscsi.org>
+Date: Tue, 30 Jul 2013 04:04:01 +0000
+Subject: iscsi-target: Fix iscsit_add_reject* usage for iser
+To: target-devel <target-devel@vger.kernel.org>
+Cc: Greg-KH <gregkh@linuxfoundation.org>, Stable <stable@vger.kernel.org>, Nicholas Bellinger <nab@linux-iscsi.org>, Or Gerlitz <ogerlitz@mellanox.com>, Mike Christie <michaelc@cs.wisc.edu>
+Message-ID: <1375157042-25935-2-git-send-email-nab@linux-iscsi.org>
+
+
+From: Nicholas Bellinger <nab@linux-iscsi.org>
+
+commit ba159914086f06532079fc15141f46ffe7e04a41 upstream
+
+This patch changes iscsit_add_reject() + iscsit_add_reject_from_cmd()
+usage to not sleep on iscsi_cmd->reject_comp to address a free-after-use
+usage bug in v3.10 with iser-target code.
+
+It saves ->reject_reason for use within iscsit_build_reject() so the
+correct value for both transport cases. It also drops the legacy
+fail_conn parameter usage throughput iscsi-target code and adds
+two iscsit_add_reject_cmd() and iscsit_reject_cmd helper functions,
+along with various small cleanups.
+
+(v2: Re-enable target_put_sess_cmd() to be called from
+ iscsit_add_reject_from_cmd() for rejects invoked after
+ target_get_sess_cmd() has been called)
+
+Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
+Cc: Or Gerlitz <ogerlitz@mellanox.com>
+Cc: Mike Christie <michaelc@cs.wisc.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/infiniband/ulp/isert/ib_isert.c | 5
+ drivers/target/iscsi/iscsi_target.c | 251 ++++++++++++-------------------
+ drivers/target/iscsi/iscsi_target.h | 2
+ drivers/target/iscsi/iscsi_target_core.h | 4
+ drivers/target/iscsi/iscsi_target_erl0.c | 7
+ drivers/target/iscsi/iscsi_target_erl1.c | 20 +-
+ drivers/target/iscsi/iscsi_target_util.c | 1
+ include/target/iscsi/iscsi_transport.h | 2
+ 8 files changed, 116 insertions(+), 176 deletions(-)
+
+--- a/drivers/infiniband/ulp/isert/ib_isert.c
++++ b/drivers/infiniband/ulp/isert/ib_isert.c
+@@ -957,11 +957,6 @@ sequence_cmd:
+ if (!rc && dump_payload == false && unsol_data)
+ iscsit_set_unsoliticed_dataout(cmd);
+
+- if (rc == CMDSN_ERROR_CANNOT_RECOVER)
+- return iscsit_add_reject_from_cmd(
+- ISCSI_REASON_PROTOCOL_ERROR,
+- 1, 0, (unsigned char *)hdr, cmd);
+-
+ return 0;
+ }
+
+--- a/drivers/target/iscsi/iscsi_target.c
++++ b/drivers/target/iscsi/iscsi_target.c
+@@ -628,25 +628,18 @@ static void __exit iscsi_target_cleanup_
+ }
+
+ static int iscsit_add_reject(
++ struct iscsi_conn *conn,
+ u8 reason,
+- int fail_conn,
+- unsigned char *buf,
+- struct iscsi_conn *conn)
++ unsigned char *buf)
+ {
+ struct iscsi_cmd *cmd;
+- struct iscsi_reject *hdr;
+- int ret;
+
+ cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+ if (!cmd)
+ return -1;
+
+ cmd->iscsi_opcode = ISCSI_OP_REJECT;
+- if (fail_conn)
+- cmd->cmd_flags |= ICF_REJECT_FAIL_CONN;
+-
+- hdr = (struct iscsi_reject *) cmd->pdu;
+- hdr->reason = reason;
++ cmd->reject_reason = reason;
+
+ cmd->buf_ptr = kmemdup(buf, ISCSI_HDR_LEN, GFP_KERNEL);
+ if (!cmd->buf_ptr) {
+@@ -662,23 +655,16 @@ static int iscsit_add_reject(
+ cmd->i_state = ISTATE_SEND_REJECT;
+ iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
+
+- ret = wait_for_completion_interruptible(&cmd->reject_comp);
+- if (ret != 0)
+- return -1;
+-
+- return (!fail_conn) ? 0 : -1;
++ return -1;
+ }
+
+-int iscsit_add_reject_from_cmd(
++static int iscsit_add_reject_from_cmd(
++ struct iscsi_cmd *cmd,
+ u8 reason,
+- int fail_conn,
+- int add_to_conn,
+- unsigned char *buf,
+- struct iscsi_cmd *cmd)
++ bool add_to_conn,
++ unsigned char *buf)
+ {
+ struct iscsi_conn *conn;
+- struct iscsi_reject *hdr;
+- int ret;
+
+ if (!cmd->conn) {
+ pr_err("cmd->conn is NULL for ITT: 0x%08x\n",
+@@ -688,11 +674,7 @@ int iscsit_add_reject_from_cmd(
+ conn = cmd->conn;
+
+ cmd->iscsi_opcode = ISCSI_OP_REJECT;
+- if (fail_conn)
+- cmd->cmd_flags |= ICF_REJECT_FAIL_CONN;
+-
+- hdr = (struct iscsi_reject *) cmd->pdu;
+- hdr->reason = reason;
++ cmd->reject_reason = reason;
+
+ cmd->buf_ptr = kmemdup(buf, ISCSI_HDR_LEN, GFP_KERNEL);
+ if (!cmd->buf_ptr) {
+@@ -709,8 +691,6 @@ int iscsit_add_reject_from_cmd(
+
+ cmd->i_state = ISTATE_SEND_REJECT;
+ iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
+-
+- ret = wait_for_completion_interruptible(&cmd->reject_comp);
+ /*
+ * Perform the kref_put now if se_cmd has already been setup by
+ * scsit_setup_scsi_cmd()
+@@ -719,12 +699,19 @@ int iscsit_add_reject_from_cmd(
+ pr_debug("iscsi reject: calling target_put_sess_cmd >>>>>>\n");
+ target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
+ }
+- if (ret != 0)
+- return -1;
++ return -1;
++}
++
++static int iscsit_add_reject_cmd(struct iscsi_cmd *cmd, u8 reason,
++ unsigned char *buf)
++{
++ return iscsit_add_reject_from_cmd(cmd, reason, true, buf);
++}
+
+- return (!fail_conn) ? 0 : -1;
++int iscsit_reject_cmd(struct iscsi_cmd *cmd, u8 reason, unsigned char *buf)
++{
++ return iscsit_add_reject_from_cmd(cmd, reason, false, buf);
+ }
+-EXPORT_SYMBOL(iscsit_add_reject_from_cmd);
+
+ /*
+ * Map some portion of the allocated scatterlist to an iovec, suitable for
+@@ -844,8 +831,8 @@ int iscsit_setup_scsi_cmd(struct iscsi_c
+ !(hdr->flags & ISCSI_FLAG_CMD_FINAL)) {
+ pr_err("ISCSI_FLAG_CMD_WRITE & ISCSI_FLAG_CMD_FINAL"
+ " not set. Bad iSCSI Initiator.\n");
+- return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
+- 1, 1, buf, cmd);
++ return iscsit_add_reject_cmd(cmd,
++ ISCSI_REASON_BOOKMARK_INVALID, buf);
+ }
+
+ if (((hdr->flags & ISCSI_FLAG_CMD_READ) ||
+@@ -865,8 +852,8 @@ int iscsit_setup_scsi_cmd(struct iscsi_c
+ pr_err("ISCSI_FLAG_CMD_READ or ISCSI_FLAG_CMD_WRITE"
+ " set when Expected Data Transfer Length is 0 for"
+ " CDB: 0x%02x. Bad iSCSI Initiator.\n", hdr->cdb[0]);
+- return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
+- 1, 1, buf, cmd);
++ return iscsit_add_reject_cmd(cmd,
++ ISCSI_REASON_BOOKMARK_INVALID, buf);
+ }
+ done:
+
+@@ -875,62 +862,62 @@ done:
+ pr_err("ISCSI_FLAG_CMD_READ and/or ISCSI_FLAG_CMD_WRITE"
+ " MUST be set if Expected Data Transfer Length is not 0."
+ " Bad iSCSI Initiator\n");
+- return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
+- 1, 1, buf, cmd);
++ return iscsit_add_reject_cmd(cmd,
++ ISCSI_REASON_BOOKMARK_INVALID, buf);
+ }
+
+ if ((hdr->flags & ISCSI_FLAG_CMD_READ) &&
+ (hdr->flags & ISCSI_FLAG_CMD_WRITE)) {
+ pr_err("Bidirectional operations not supported!\n");
+- return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
+- 1, 1, buf, cmd);
++ return iscsit_add_reject_cmd(cmd,
++ ISCSI_REASON_BOOKMARK_INVALID, buf);
+ }
+
+ if (hdr->opcode & ISCSI_OP_IMMEDIATE) {
+ pr_err("Illegally set Immediate Bit in iSCSI Initiator"
+ " Scsi Command PDU.\n");
+- return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
+- 1, 1, buf, cmd);
++ return iscsit_add_reject_cmd(cmd,
++ ISCSI_REASON_BOOKMARK_INVALID, buf);
+ }
+
+ if (payload_length && !conn->sess->sess_ops->ImmediateData) {
+ pr_err("ImmediateData=No but DataSegmentLength=%u,"
+ " protocol error.\n", payload_length);
+- return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
+- 1, 1, buf, cmd);
++ return iscsit_add_reject_cmd(cmd,
++ ISCSI_REASON_PROTOCOL_ERROR, buf);
+ }
+
+- if ((be32_to_cpu(hdr->data_length )== payload_length) &&
++ if ((be32_to_cpu(hdr->data_length) == payload_length) &&
+ (!(hdr->flags & ISCSI_FLAG_CMD_FINAL))) {
+ pr_err("Expected Data Transfer Length and Length of"
+ " Immediate Data are the same, but ISCSI_FLAG_CMD_FINAL"
+ " bit is not set protocol error\n");
+- return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
+- 1, 1, buf, cmd);
++ return iscsit_add_reject_cmd(cmd,
++ ISCSI_REASON_PROTOCOL_ERROR, buf);
+ }
+
+ if (payload_length > be32_to_cpu(hdr->data_length)) {
+ pr_err("DataSegmentLength: %u is greater than"
+ " EDTL: %u, protocol error.\n", payload_length,
+ hdr->data_length);
+- return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
+- 1, 1, buf, cmd);
++ return iscsit_add_reject_cmd(cmd,
++ ISCSI_REASON_PROTOCOL_ERROR, buf);
+ }
+
+ if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
+ pr_err("DataSegmentLength: %u is greater than"
+ " MaxXmitDataSegmentLength: %u, protocol error.\n",
+ payload_length, conn->conn_ops->MaxXmitDataSegmentLength);
+- return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
+- 1, 1, buf, cmd);
++ return iscsit_add_reject_cmd(cmd,
++ ISCSI_REASON_PROTOCOL_ERROR, buf);
+ }
+
+ if (payload_length > conn->sess->sess_ops->FirstBurstLength) {
+ pr_err("DataSegmentLength: %u is greater than"
+ " FirstBurstLength: %u, protocol error.\n",
+ payload_length, conn->sess->sess_ops->FirstBurstLength);
+- return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
+- 1, 1, buf, cmd);
++ return iscsit_add_reject_cmd(cmd,
++ ISCSI_REASON_BOOKMARK_INVALID, buf);
+ }
+
+ data_direction = (hdr->flags & ISCSI_FLAG_CMD_WRITE) ? DMA_TO_DEVICE :
+@@ -985,9 +972,8 @@ done:
+
+ dr = iscsit_allocate_datain_req();
+ if (!dr)
+- return iscsit_add_reject_from_cmd(
+- ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+- 1, 1, buf, cmd);
++ return iscsit_add_reject_cmd(cmd,
++ ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
+
+ iscsit_attach_datain_req(cmd, dr);
+ }
+@@ -1015,18 +1001,16 @@ done:
+ cmd->sense_reason = target_setup_cmd_from_cdb(&cmd->se_cmd, hdr->cdb);
+ if (cmd->sense_reason) {
+ if (cmd->sense_reason == TCM_OUT_OF_RESOURCES) {
+- return iscsit_add_reject_from_cmd(
+- ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+- 1, 1, buf, cmd);
++ return iscsit_add_reject_cmd(cmd,
++ ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
+ }
+
+ goto attach_cmd;
+ }
+
+ if (iscsit_build_pdu_and_seq_lists(cmd, payload_length) < 0) {
+- return iscsit_add_reject_from_cmd(
+- ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+- 1, 1, buf, cmd);
++ return iscsit_add_reject_cmd(cmd,
++ ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
+ }
+
+ attach_cmd:
+@@ -1075,10 +1059,6 @@ int iscsit_process_scsi_cmd(struct iscsi
+
+ target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
+ return 0;
+- } else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) {
+- return iscsit_add_reject_from_cmd(
+- ISCSI_REASON_PROTOCOL_ERROR,
+- 1, 0, (unsigned char *)hdr, cmd);
+ }
+ }
+
+@@ -1149,11 +1129,6 @@ after_immediate_data:
+ } else if (cmd->unsolicited_data)
+ iscsit_set_unsoliticed_dataout(cmd);
+
+- if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
+- return iscsit_add_reject_from_cmd(
+- ISCSI_REASON_PROTOCOL_ERROR,
+- 1, 0, (unsigned char *)hdr, cmd);
+-
+ } else if (immed_ret == IMMEDIATE_DATA_ERL1_CRC_FAILURE) {
+ /*
+ * Immediate Data failed DataCRC and ERL>=1,
+@@ -1190,9 +1165,8 @@ iscsit_handle_scsi_cmd(struct iscsi_conn
+ * traditional iSCSI block I/O.
+ */
+ if (iscsit_allocate_iovecs(cmd) < 0) {
+- return iscsit_add_reject_from_cmd(
+- ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+- 1, 0, buf, cmd);
++ return iscsit_add_reject_cmd(cmd,
++ ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
+ }
+ immed_data = cmd->immediate_data;
+
+@@ -1283,8 +1257,8 @@ iscsit_check_dataout_hdr(struct iscsi_co
+
+ if (!payload_length) {
+ pr_err("DataOUT payload is ZERO, protocol error.\n");
+- return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
+- buf, conn);
++ return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
++ buf);
+ }
+
+ /* iSCSI write */
+@@ -1301,8 +1275,8 @@ iscsit_check_dataout_hdr(struct iscsi_co
+ pr_err("DataSegmentLength: %u is greater than"
+ " MaxXmitDataSegmentLength: %u\n", payload_length,
+ conn->conn_ops->MaxXmitDataSegmentLength);
+- return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
+- buf, conn);
++ return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
++ buf);
+ }
+
+ cmd = iscsit_find_cmd_from_itt_or_dump(conn, hdr->itt,
+@@ -1325,8 +1299,7 @@ iscsit_check_dataout_hdr(struct iscsi_co
+ if (cmd->data_direction != DMA_TO_DEVICE) {
+ pr_err("Command ITT: 0x%08x received DataOUT for a"
+ " NON-WRITE command.\n", cmd->init_task_tag);
+- return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
+- 1, 0, buf, cmd);
++ return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, buf);
+ }
+ se_cmd = &cmd->se_cmd;
+ iscsit_mod_dataout_timer(cmd);
+@@ -1335,8 +1308,7 @@ iscsit_check_dataout_hdr(struct iscsi_co
+ pr_err("DataOut Offset: %u, Length %u greater than"
+ " iSCSI Command EDTL %u, protocol error.\n",
+ hdr->offset, payload_length, cmd->se_cmd.data_length);
+- return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
+- 1, 0, buf, cmd);
++ return iscsit_reject_cmd(cmd, ISCSI_REASON_BOOKMARK_INVALID, buf);
+ }
+
+ if (cmd->unsolicited_data) {
+@@ -1557,8 +1529,8 @@ int iscsit_handle_nop_out(struct iscsi_c
+ if (hdr->itt == RESERVED_ITT && !(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
+ pr_err("NOPOUT ITT is reserved, but Immediate Bit is"
+ " not set, protocol error.\n");
+- return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
+- buf, conn);
++ return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
++ (unsigned char *)hdr);
+ }
+
+ if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
+@@ -1566,8 +1538,8 @@ int iscsit_handle_nop_out(struct iscsi_c
+ " greater than MaxXmitDataSegmentLength: %u, protocol"
+ " error.\n", payload_length,
+ conn->conn_ops->MaxXmitDataSegmentLength);
+- return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
+- buf, conn);
++ return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
++ (unsigned char *)hdr);
+ }
+
+ pr_debug("Got NOPOUT Ping %s ITT: 0x%08x, TTT: 0x%08x,"
+@@ -1584,9 +1556,9 @@ int iscsit_handle_nop_out(struct iscsi_c
+ */
+ if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
+ if (!cmd)
+- return iscsit_add_reject(
++ return iscsit_reject_cmd(cmd,
+ ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+- 1, buf, conn);
++ (unsigned char *)hdr);
+
+ cmd->iscsi_opcode = ISCSI_OP_NOOP_OUT;
+ cmd->i_state = ISTATE_SEND_NOPIN;
+@@ -1706,9 +1678,7 @@ int iscsit_handle_nop_out(struct iscsi_c
+ goto ping_out;
+ }
+ if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
+- return iscsit_add_reject_from_cmd(
+- ISCSI_REASON_PROTOCOL_ERROR,
+- 1, 0, buf, cmd);
++ return -1;
+
+ return 0;
+ }
+@@ -1782,8 +1752,8 @@ iscsit_handle_task_mgt_cmd(struct iscsi_
+ pr_err("Task Management Request TASK_REASSIGN not"
+ " issued as immediate command, bad iSCSI Initiator"
+ "implementation\n");
+- return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
+- 1, 1, buf, cmd);
++ return iscsit_add_reject_cmd(cmd,
++ ISCSI_REASON_PROTOCOL_ERROR, buf);
+ }
+ if ((function != ISCSI_TM_FUNC_ABORT_TASK) &&
+ be32_to_cpu(hdr->refcmdsn) != ISCSI_RESERVED_TAG)
+@@ -1795,9 +1765,9 @@ iscsit_handle_task_mgt_cmd(struct iscsi_
+ if (!cmd->tmr_req) {
+ pr_err("Unable to allocate memory for"
+ " Task Management command!\n");
+- return iscsit_add_reject_from_cmd(
+- ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+- 1, 1, buf, cmd);
++ return iscsit_add_reject_cmd(cmd,
++ ISCSI_REASON_BOOKMARK_NO_RESOURCES,
++ buf);
+ }
+
+ /*
+@@ -1842,17 +1812,15 @@ iscsit_handle_task_mgt_cmd(struct iscsi_
+ default:
+ pr_err("Unknown iSCSI TMR Function:"
+ " 0x%02x\n", function);
+- return iscsit_add_reject_from_cmd(
+- ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+- 1, 1, buf, cmd);
++ return iscsit_add_reject_cmd(cmd,
++ ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
+ }
+
+ ret = core_tmr_alloc_req(&cmd->se_cmd, cmd->tmr_req,
+ tcm_function, GFP_KERNEL);
+ if (ret < 0)
+- return iscsit_add_reject_from_cmd(
+- ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+- 1, 1, buf, cmd);
++ return iscsit_add_reject_cmd(cmd,
++ ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
+
+ cmd->tmr_req->se_tmr_req = cmd->se_cmd.se_tmr_req;
+ }
+@@ -1911,9 +1879,8 @@ iscsit_handle_task_mgt_cmd(struct iscsi_
+ break;
+
+ if (iscsit_check_task_reassign_expdatasn(tmr_req, conn) < 0)
+- return iscsit_add_reject_from_cmd(
+- ISCSI_REASON_BOOKMARK_INVALID, 1, 1,
+- buf, cmd);
++ return iscsit_add_reject_cmd(cmd,
++ ISCSI_REASON_BOOKMARK_INVALID, buf);
+ break;
+ default:
+ pr_err("Unknown TMR function: 0x%02x, protocol"
+@@ -1937,9 +1904,7 @@ attach:
+ else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
+ return 0;
+ else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
+- return iscsit_add_reject_from_cmd(
+- ISCSI_REASON_PROTOCOL_ERROR,
+- 1, 0, buf, cmd);
++ return -1;
+ }
+ iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
+
+@@ -1989,8 +1954,7 @@ static int iscsit_handle_text_cmd(
+ pr_err("Unable to accept text parameter length: %u"
+ "greater than MaxXmitDataSegmentLength %u.\n",
+ payload_length, conn->conn_ops->MaxXmitDataSegmentLength);
+- return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
+- buf, conn);
++ return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR, buf);
+ }
+
+ pr_debug("Got Text Request: ITT: 0x%08x, CmdSN: 0x%08x,"
+@@ -2092,8 +2056,8 @@ static int iscsit_handle_text_cmd(
+
+ cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+ if (!cmd)
+- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+- 1, buf, conn);
++ return iscsit_add_reject(conn,
++ ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
+
+ cmd->iscsi_opcode = ISCSI_OP_TEXT;
+ cmd->i_state = ISTATE_SEND_TEXTRSP;
+@@ -2113,9 +2077,7 @@ static int iscsit_handle_text_cmd(
+ if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
+ cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
+ if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
+- return iscsit_add_reject_from_cmd(
+- ISCSI_REASON_PROTOCOL_ERROR,
+- 1, 0, buf, cmd);
++ return -1;
+
+ return 0;
+ }
+@@ -2301,13 +2263,10 @@ iscsit_handle_logout_cmd(struct iscsi_co
+ return ret;
+ } else {
+ cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
+- if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
++ if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
+ logout_remove = 0;
+- } else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) {
+- return iscsit_add_reject_from_cmd(
+- ISCSI_REASON_PROTOCOL_ERROR,
+- 1, 0, buf, cmd);
+- }
++ else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
++ return -1;
+ }
+
+ return logout_remove;
+@@ -2331,8 +2290,8 @@ static int iscsit_handle_snack(
+ if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
+ pr_err("Initiator sent SNACK request while in"
+ " ErrorRecoveryLevel=0.\n");
+- return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
+- buf, conn);
++ return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
++ buf);
+ }
+ /*
+ * SNACK_DATA and SNACK_R2T are both 0, so check which function to
+@@ -2356,13 +2315,13 @@ static int iscsit_handle_snack(
+ case ISCSI_FLAG_SNACK_TYPE_RDATA:
+ /* FIXME: Support R-Data SNACK */
+ pr_err("R-Data SNACK Not Supported.\n");
+- return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
+- buf, conn);
++ return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
++ buf);
+ default:
+ pr_err("Unknown SNACK type 0x%02x, protocol"
+ " error.\n", hdr->flags & 0x0f);
+- return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
+- buf, conn);
++ return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
++ buf);
+ }
+
+ return 0;
+@@ -2434,14 +2393,14 @@ static int iscsit_handle_immediate_data(
+ pr_err("Unable to recover from"
+ " Immediate Data digest failure while"
+ " in ERL=0.\n");
+- iscsit_add_reject_from_cmd(
++ iscsit_reject_cmd(cmd,
+ ISCSI_REASON_DATA_DIGEST_ERROR,
+- 1, 0, (unsigned char *)hdr, cmd);
++ (unsigned char *)hdr);
+ return IMMEDIATE_DATA_CANNOT_RECOVER;
+ } else {
+- iscsit_add_reject_from_cmd(
++ iscsit_reject_cmd(cmd,
+ ISCSI_REASON_DATA_DIGEST_ERROR,
+- 0, 0, (unsigned char *)hdr, cmd);
++ (unsigned char *)hdr);
+ return IMMEDIATE_DATA_ERL1_CRC_FAILURE;
+ }
+ } else {
+@@ -3541,6 +3500,7 @@ iscsit_build_reject(struct iscsi_cmd *cm
+ struct iscsi_reject *hdr)
+ {
+ hdr->opcode = ISCSI_OP_REJECT;
++ hdr->reason = cmd->reject_reason;
+ hdr->flags |= ISCSI_FLAG_CMD_FINAL;
+ hton24(hdr->dlength, ISCSI_HDR_LEN);
+ hdr->ffffffff = cpu_to_be32(0xffffffff);
+@@ -3814,18 +3774,11 @@ check_rsp_state:
+ case ISTATE_SEND_STATUS_RECOVERY:
+ case ISTATE_SEND_TEXTRSP:
+ case ISTATE_SEND_TASKMGTRSP:
++ case ISTATE_SEND_REJECT:
+ spin_lock_bh(&cmd->istate_lock);
+ cmd->i_state = ISTATE_SENT_STATUS;
+ spin_unlock_bh(&cmd->istate_lock);
+ break;
+- case ISTATE_SEND_REJECT:
+- if (cmd->cmd_flags & ICF_REJECT_FAIL_CONN) {
+- cmd->cmd_flags &= ~ICF_REJECT_FAIL_CONN;
+- complete(&cmd->reject_comp);
+- goto err;
+- }
+- complete(&cmd->reject_comp);
+- break;
+ default:
+ pr_err("Unknown Opcode: 0x%02x ITT:"
+ " 0x%08x, i_state: %d on CID: %hu\n",
+@@ -3930,8 +3883,7 @@ static int iscsi_target_rx_opcode(struct
+ case ISCSI_OP_SCSI_CMD:
+ cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+ if (!cmd)
+- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+- 1, buf, conn);
++ goto reject;
+
+ ret = iscsit_handle_scsi_cmd(conn, cmd, buf);
+ break;
+@@ -3943,16 +3895,14 @@ static int iscsi_target_rx_opcode(struct
+ if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
+ cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+ if (!cmd)
+- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+- 1, buf, conn);
++ goto reject;
+ }
+ ret = iscsit_handle_nop_out(conn, cmd, buf);
+ break;
+ case ISCSI_OP_SCSI_TMFUNC:
+ cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+ if (!cmd)
+- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+- 1, buf, conn);
++ goto reject;
+
+ ret = iscsit_handle_task_mgt_cmd(conn, cmd, buf);
+ break;
+@@ -3962,8 +3912,7 @@ static int iscsi_target_rx_opcode(struct
+ case ISCSI_OP_LOGOUT:
+ cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+ if (!cmd)
+- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+- 1, buf, conn);
++ goto reject;
+
+ ret = iscsit_handle_logout_cmd(conn, cmd, buf);
+ if (ret > 0)
+@@ -3995,6 +3944,8 @@ static int iscsi_target_rx_opcode(struct
+ }
+
+ return ret;
++reject:
++ return iscsit_add_reject(conn, ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
+ }
+
+ int iscsi_target_rx_thread(void *arg)
+@@ -4094,8 +4045,8 @@ restart:
+ (!(opcode & ISCSI_OP_LOGOUT)))) {
+ pr_err("Received illegal iSCSI Opcode: 0x%02x"
+ " while in Discovery Session, rejecting.\n", opcode);
+- iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
+- buffer, conn);
++ iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
++ buffer);
+ goto transport_err;
+ }
+
+--- a/drivers/target/iscsi/iscsi_target.h
++++ b/drivers/target/iscsi/iscsi_target.h
+@@ -15,7 +15,7 @@ extern struct iscsi_np *iscsit_add_np(st
+ extern int iscsit_reset_np_thread(struct iscsi_np *, struct iscsi_tpg_np *,
+ struct iscsi_portal_group *);
+ extern int iscsit_del_np(struct iscsi_np *);
+-extern int iscsit_add_reject_from_cmd(u8, int, int, unsigned char *, struct iscsi_cmd *);
++extern int iscsit_reject_cmd(struct iscsi_cmd *cmd, u8, unsigned char *);
+ extern void iscsit_set_unsoliticed_dataout(struct iscsi_cmd *);
+ extern int iscsit_logout_closesession(struct iscsi_cmd *, struct iscsi_conn *);
+ extern int iscsit_logout_closeconnection(struct iscsi_cmd *, struct iscsi_conn *);
+--- a/drivers/target/iscsi/iscsi_target_core.h
++++ b/drivers/target/iscsi/iscsi_target_core.h
+@@ -132,7 +132,6 @@ enum cmd_flags_table {
+ ICF_CONTIG_MEMORY = 0x00000020,
+ ICF_ATTACHED_TO_RQUEUE = 0x00000040,
+ ICF_OOO_CMDSN = 0x00000080,
+- ICF_REJECT_FAIL_CONN = 0x00000100,
+ };
+
+ /* struct iscsi_cmd->i_state */
+@@ -366,6 +365,8 @@ struct iscsi_cmd {
+ u8 maxcmdsn_inc;
+ /* Immediate Unsolicited Dataout */
+ u8 unsolicited_data;
++ /* Reject reason code */
++ u8 reject_reason;
+ /* CID contained in logout PDU when opcode == ISCSI_INIT_LOGOUT_CMND */
+ u16 logout_cid;
+ /* Command flags */
+@@ -446,7 +447,6 @@ struct iscsi_cmd {
+ struct list_head datain_list;
+ /* R2T List */
+ struct list_head cmd_r2t_list;
+- struct completion reject_comp;
+ /* Timer for DataOUT */
+ struct timer_list dataout_timer;
+ /* Iovecs for SCSI data payload RX/TX w/ kernel level sockets */
+--- a/drivers/target/iscsi/iscsi_target_erl0.c
++++ b/drivers/target/iscsi/iscsi_target_erl0.c
+@@ -746,13 +746,12 @@ int iscsit_check_post_dataout(
+ if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
+ pr_err("Unable to recover from DataOUT CRC"
+ " failure while ERL=0, closing session.\n");
+- iscsit_add_reject_from_cmd(ISCSI_REASON_DATA_DIGEST_ERROR,
+- 1, 0, buf, cmd);
++ iscsit_reject_cmd(cmd, ISCSI_REASON_DATA_DIGEST_ERROR,
++ buf);
+ return DATAOUT_CANNOT_RECOVER;
+ }
+
+- iscsit_add_reject_from_cmd(ISCSI_REASON_DATA_DIGEST_ERROR,
+- 0, 0, buf, cmd);
++ iscsit_reject_cmd(cmd, ISCSI_REASON_DATA_DIGEST_ERROR, buf);
+ return iscsit_dataout_post_crc_failed(cmd, buf);
+ }
+ }
+--- a/drivers/target/iscsi/iscsi_target_erl1.c
++++ b/drivers/target/iscsi/iscsi_target_erl1.c
+@@ -162,9 +162,8 @@ static int iscsit_handle_r2t_snack(
+ " protocol error.\n", cmd->init_task_tag, begrun,
+ (begrun + runlength), cmd->acked_data_sn);
+
+- return iscsit_add_reject_from_cmd(
+- ISCSI_REASON_PROTOCOL_ERROR,
+- 1, 0, buf, cmd);
++ return iscsit_reject_cmd(cmd,
++ ISCSI_REASON_PROTOCOL_ERROR, buf);
+ }
+
+ if (runlength) {
+@@ -173,8 +172,8 @@ static int iscsit_handle_r2t_snack(
+ " with BegRun: 0x%08x, RunLength: 0x%08x, exceeds"
+ " current R2TSN: 0x%08x, protocol error.\n",
+ cmd->init_task_tag, begrun, runlength, cmd->r2t_sn);
+- return iscsit_add_reject_from_cmd(
+- ISCSI_REASON_BOOKMARK_INVALID, 1, 0, buf, cmd);
++ return iscsit_reject_cmd(cmd,
++ ISCSI_REASON_BOOKMARK_INVALID, buf);
+ }
+ last_r2tsn = (begrun + runlength);
+ } else
+@@ -433,8 +432,7 @@ static int iscsit_handle_recovery_datain
+ " protocol error.\n", cmd->init_task_tag, begrun,
+ (begrun + runlength), cmd->acked_data_sn);
+
+- return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
+- 1, 0, buf, cmd);
++ return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, buf);
+ }
+
+ /*
+@@ -445,14 +443,14 @@ static int iscsit_handle_recovery_datain
+ pr_err("Initiator requesting BegRun: 0x%08x, RunLength"
+ ": 0x%08x greater than maximum DataSN: 0x%08x.\n",
+ begrun, runlength, (cmd->data_sn - 1));
+- return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
+- 1, 0, buf, cmd);
++ return iscsit_reject_cmd(cmd, ISCSI_REASON_BOOKMARK_INVALID,
++ buf);
+ }
+
+ dr = iscsit_allocate_datain_req();
+ if (!dr)
+- return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+- 1, 0, buf, cmd);
++ return iscsit_reject_cmd(cmd, ISCSI_REASON_BOOKMARK_NO_RESOURCES,
++ buf);
+
+ dr->data_sn = dr->begrun = begrun;
+ dr->runlength = runlength;
+--- a/drivers/target/iscsi/iscsi_target_util.c
++++ b/drivers/target/iscsi/iscsi_target_util.c
+@@ -178,7 +178,6 @@ struct iscsi_cmd *iscsit_allocate_cmd(st
+ INIT_LIST_HEAD(&cmd->i_conn_node);
+ INIT_LIST_HEAD(&cmd->datain_list);
+ INIT_LIST_HEAD(&cmd->cmd_r2t_list);
+- init_completion(&cmd->reject_comp);
+ spin_lock_init(&cmd->datain_lock);
+ spin_lock_init(&cmd->dataout_timeout_lock);
+ spin_lock_init(&cmd->istate_lock);
+--- a/include/target/iscsi/iscsi_transport.h
++++ b/include/target/iscsi/iscsi_transport.h
+@@ -34,8 +34,6 @@ extern void iscsit_put_transport(struct
+ /*
+ * From iscsi_target.c
+ */
+-extern int iscsit_add_reject_from_cmd(u8, int, int, unsigned char *,
+- struct iscsi_cmd *);
+ extern int iscsit_setup_scsi_cmd(struct iscsi_conn *, struct iscsi_cmd *,
+ unsigned char *);
+ extern void iscsit_set_unsoliticed_dataout(struct iscsi_cmd *);
--- /dev/null
+From nab@linux-iscsi.org Fri Aug 2 06:54:36 2013
+From: "Nicholas A. Bellinger" <nab@linux-iscsi.org>
+Date: Tue, 30 Jul 2013 04:04:02 +0000
+Subject: iscsi-target: Fix iscsit_sequence_cmd reject handling for iser
+To: target-devel <target-devel@vger.kernel.org>
+Cc: Greg-KH <gregkh@linuxfoundation.org>, Stable <stable@vger.kernel.org>, Nicholas Bellinger <nab@linux-iscsi.org>, Or Gerlitz <ogerlitz@mellanox.com>, Mike Christie <michaelc@cs.wisc.edu>
+Message-ID: <1375157042-25935-3-git-send-email-nab@linux-iscsi.org>
+
+
+From: Nicholas Bellinger <nab@linux-iscsi.org>
+
+commit 561bf15892375597ee59d473a704a3e634c4f311 upstream
+
+This patch moves ISCSI_OP_REJECT failures into iscsit_sequence_cmd()
+in order to avoid external iscsit_reject_cmd() reject usage for all
+PDU types.
+
+It also updates PDU specific handlers for traditional iscsi-target
+code to not reset the session after posting a ISCSI_OP_REJECT during
+setup.
+
+(v2: Fix CMDSN_LOWER_THAN_EXP for ISCSI_OP_SCSI to call
+ target_put_sess_cmd() after iscsit_sequence_cmd() failure)
+
+Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
+Cc: Or Gerlitz <ogerlitz@mellanox.com>
+Cc: Mike Christie <michaelc@cs.wisc.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/infiniband/ulp/isert/ib_isert.c | 2 -
+ drivers/target/iscsi/iscsi_target.c | 50 +++++++++++++++++++------------
+ drivers/target/iscsi/iscsi_target_erl1.c | 6 +--
+ drivers/target/iscsi/iscsi_target_util.c | 26 ++++++++++++----
+ drivers/target/iscsi/iscsi_target_util.h | 3 +
+ include/target/iscsi/iscsi_transport.h | 3 +
+ 6 files changed, 60 insertions(+), 30 deletions(-)
+
+--- a/drivers/infiniband/ulp/isert/ib_isert.c
++++ b/drivers/infiniband/ulp/isert/ib_isert.c
+@@ -952,7 +952,7 @@ isert_handle_scsi_cmd(struct isert_conn
+ }
+
+ sequence_cmd:
+- rc = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
++ rc = iscsit_sequence_cmd(conn, cmd, buf, hdr->cmdsn);
+
+ if (!rc && dump_payload == false && unsol_data)
+ iscsit_set_unsoliticed_dataout(cmd);
+--- a/drivers/target/iscsi/iscsi_target.c
++++ b/drivers/target/iscsi/iscsi_target.c
+@@ -1052,11 +1052,11 @@ int iscsit_process_scsi_cmd(struct iscsi
+ * be acknowledged. (See below)
+ */
+ if (!cmd->immediate_data) {
+- cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
+- if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
+- if (!cmd->sense_reason)
+- return 0;
+-
++ cmdsn_ret = iscsit_sequence_cmd(conn, cmd,
++ (unsigned char *)hdr, hdr->cmdsn);
++ if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
++ return -1;
++ else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
+ target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
+ return 0;
+ }
+@@ -1083,6 +1083,9 @@ int iscsit_process_scsi_cmd(struct iscsi
+ * iscsit_check_received_cmdsn() in iscsit_get_immediate_data() below.
+ */
+ if (cmd->sense_reason) {
++ if (cmd->reject_reason)
++ return 0;
++
+ target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
+ return 1;
+ }
+@@ -1091,10 +1094,8 @@ int iscsit_process_scsi_cmd(struct iscsi
+ * the backend memory allocation.
+ */
+ cmd->sense_reason = transport_generic_new_cmd(&cmd->se_cmd);
+- if (cmd->sense_reason) {
+- target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
++ if (cmd->sense_reason)
+ return 1;
+- }
+
+ return 0;
+ }
+@@ -1104,6 +1105,7 @@ static int
+ iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr,
+ bool dump_payload)
+ {
++ struct iscsi_conn *conn = cmd->conn;
+ int cmdsn_ret = 0, immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION;
+ /*
+ * Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes.
+@@ -1120,12 +1122,22 @@ after_immediate_data:
+ * DataCRC, check against ExpCmdSN/MaxCmdSN if
+ * Immediate Bit is not set.
+ */
+- cmdsn_ret = iscsit_sequence_cmd(cmd->conn, cmd, hdr->cmdsn);
++ cmdsn_ret = iscsit_sequence_cmd(cmd->conn, cmd,
++ (unsigned char *)hdr, hdr->cmdsn);
++ if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) {
++ return -1;
++ } else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
++ target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
++ return 0;
++ }
+
+ if (cmd->sense_reason) {
+- if (iscsit_dump_data_payload(cmd->conn,
+- cmd->first_burst_len, 1) < 0)
+- return -1;
++ int rc;
++
++ rc = iscsit_dump_data_payload(cmd->conn,
++ cmd->first_burst_len, 1);
++ target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
++ return rc;
+ } else if (cmd->unsolicited_data)
+ iscsit_set_unsoliticed_dataout(cmd);
+
+@@ -1159,7 +1171,7 @@ iscsit_handle_scsi_cmd(struct iscsi_conn
+
+ rc = iscsit_setup_scsi_cmd(conn, cmd, buf);
+ if (rc < 0)
+- return rc;
++ return 0;
+ /*
+ * Allocation iovecs needed for struct socket operations for
+ * traditional iSCSI block I/O.
+@@ -1500,7 +1512,7 @@ static int iscsit_handle_data_out(struct
+
+ rc = iscsit_check_dataout_hdr(conn, buf, &cmd);
+ if (rc < 0)
+- return rc;
++ return 0;
+ else if (!cmd)
+ return 0;
+
+@@ -1672,7 +1684,8 @@ int iscsit_handle_nop_out(struct iscsi_c
+ return 0;
+ }
+
+- cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
++ cmdsn_ret = iscsit_sequence_cmd(conn, cmd,
++ (unsigned char *)hdr, hdr->cmdsn);
+ if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
+ ret = 0;
+ goto ping_out;
+@@ -1898,7 +1911,7 @@ attach:
+ spin_unlock_bh(&conn->cmd_lock);
+
+ if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
+- int cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
++ int cmdsn_ret = iscsit_sequence_cmd(conn, cmd, buf, hdr->cmdsn);
+ if (cmdsn_ret == CMDSN_HIGHER_THAN_EXP)
+ out_of_order_cmdsn = 1;
+ else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
+@@ -2075,7 +2088,8 @@ static int iscsit_handle_text_cmd(
+ iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
+
+ if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
+- cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
++ cmdsn_ret = iscsit_sequence_cmd(conn, cmd,
++ (unsigned char *)hdr, hdr->cmdsn);
+ if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
+ return -1;
+
+@@ -2262,7 +2276,7 @@ iscsit_handle_logout_cmd(struct iscsi_co
+ if (ret < 0)
+ return ret;
+ } else {
+- cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
++ cmdsn_ret = iscsit_sequence_cmd(conn, cmd, buf, hdr->cmdsn);
+ if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
+ logout_remove = 0;
+ else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
+--- a/drivers/target/iscsi/iscsi_target_erl1.c
++++ b/drivers/target/iscsi/iscsi_target_erl1.c
+@@ -1088,7 +1088,7 @@ int iscsit_handle_ooo_cmdsn(
+
+ ooo_cmdsn = iscsit_allocate_ooo_cmdsn();
+ if (!ooo_cmdsn)
+- return CMDSN_ERROR_CANNOT_RECOVER;
++ return -ENOMEM;
+
+ ooo_cmdsn->cmd = cmd;
+ ooo_cmdsn->batch_count = (batch) ?
+@@ -1099,10 +1099,10 @@ int iscsit_handle_ooo_cmdsn(
+
+ if (iscsit_attach_ooo_cmdsn(sess, ooo_cmdsn) < 0) {
+ kmem_cache_free(lio_ooo_cache, ooo_cmdsn);
+- return CMDSN_ERROR_CANNOT_RECOVER;
++ return -ENOMEM;
+ }
+
+- return CMDSN_HIGHER_THAN_EXP;
++ return 0;
+ }
+
+ static int iscsit_set_dataout_timeout_values(
+--- a/drivers/target/iscsi/iscsi_target_util.c
++++ b/drivers/target/iscsi/iscsi_target_util.c
+@@ -283,13 +283,12 @@ static inline int iscsit_check_received_
+ * Commands may be received out of order if MC/S is in use.
+ * Ensure they are executed in CmdSN order.
+ */
+-int iscsit_sequence_cmd(
+- struct iscsi_conn *conn,
+- struct iscsi_cmd *cmd,
+- __be32 cmdsn)
++int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
++ unsigned char *buf, __be32 cmdsn)
+ {
+- int ret;
+- int cmdsn_ret;
++ int ret, cmdsn_ret;
++ bool reject = false;
++ u8 reason = ISCSI_REASON_BOOKMARK_NO_RESOURCES;
+
+ mutex_lock(&conn->sess->cmdsn_mutex);
+
+@@ -299,9 +298,19 @@ int iscsit_sequence_cmd(
+ ret = iscsit_execute_cmd(cmd, 0);
+ if ((ret >= 0) && !list_empty(&conn->sess->sess_ooo_cmdsn_list))
+ iscsit_execute_ooo_cmdsns(conn->sess);
++ else if (ret < 0) {
++ reject = true;
++ ret = CMDSN_ERROR_CANNOT_RECOVER;
++ }
+ break;
+ case CMDSN_HIGHER_THAN_EXP:
+ ret = iscsit_handle_ooo_cmdsn(conn->sess, cmd, be32_to_cpu(cmdsn));
++ if (ret < 0) {
++ reject = true;
++ ret = CMDSN_ERROR_CANNOT_RECOVER;
++ break;
++ }
++ ret = CMDSN_HIGHER_THAN_EXP;
+ break;
+ case CMDSN_LOWER_THAN_EXP:
+ cmd->i_state = ISTATE_REMOVE;
+@@ -309,11 +318,16 @@ int iscsit_sequence_cmd(
+ ret = cmdsn_ret;
+ break;
+ default:
++ reason = ISCSI_REASON_PROTOCOL_ERROR;
++ reject = true;
+ ret = cmdsn_ret;
+ break;
+ }
+ mutex_unlock(&conn->sess->cmdsn_mutex);
+
++ if (reject)
++ iscsit_reject_cmd(cmd, reason, buf);
++
+ return ret;
+ }
+ EXPORT_SYMBOL(iscsit_sequence_cmd);
+--- a/drivers/target/iscsi/iscsi_target_util.h
++++ b/drivers/target/iscsi/iscsi_target_util.h
+@@ -13,7 +13,8 @@ extern struct iscsi_cmd *iscsit_allocate
+ extern struct iscsi_seq *iscsit_get_seq_holder_for_datain(struct iscsi_cmd *, u32);
+ extern struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsi_cmd *);
+ extern struct iscsi_r2t *iscsit_get_holder_for_r2tsn(struct iscsi_cmd *, u32);
+-int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, __be32 cmdsn);
++extern int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
++ unsigned char * ,__be32 cmdsn);
+ extern int iscsit_check_unsolicited_dataout(struct iscsi_cmd *, unsigned char *);
+ extern struct iscsi_cmd *iscsit_find_cmd_from_itt(struct iscsi_conn *, itt_t);
+ extern struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(struct iscsi_conn *,
+--- a/include/target/iscsi/iscsi_transport.h
++++ b/include/target/iscsi/iscsi_transport.h
+@@ -82,4 +82,5 @@ extern int iscsit_tmr_post_handler(struc
+ * From iscsi_target_util.c
+ */
+ extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t);
+-extern int iscsit_sequence_cmd(struct iscsi_conn *, struct iscsi_cmd *, __be32);
++extern int iscsit_sequence_cmd(struct iscsi_conn *, struct iscsi_cmd *,
++ unsigned char *, __be32);