From c1ccbfe0311e2380a6d2dcb0714b36904f5d586f Mon Sep 17 00:00:00 2001 From: Sumit Rai Date: Wed, 20 Jul 2016 13:59:42 -0700 Subject: [PATCH] target: Fix residual overflow handling in target_complete_cmd_with_length MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes residual overflow handling to correctly set the residual_count using SPDTL, instead of SCSI Allocation Length. Allocation Length is the maximum value of the SPDTL and not substitute for it, hence it shouldn’t be used to calculate ResidualCount except for cases where SPDTL > Allocation Length and Data is truncated (in that case both Alloc Len and SPDTL are same). (SPC 5r01 Section 4.2.5.6). Thanks to Ajay Nair in assisting with this patch. Signed-off-by: Sumit Rai Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 42c2a44b83dd..6094a6beddde 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -754,7 +754,15 @@ EXPORT_SYMBOL(target_complete_cmd); void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int length) { - if (scsi_status == SAM_STAT_GOOD && length < cmd->data_length) { + if (scsi_status != SAM_STAT_GOOD) { + return; + } + + /* + * Calculate new residual count based upon length of SCSI data + * transferred. + */ + if (length < cmd->data_length) { if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) { cmd->residual_count += cmd->data_length - length; } else { @@ -763,6 +771,12 @@ void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int len } cmd->data_length = length; + } else if (length > cmd->data_length) { + cmd->se_cmd_flags |= SCF_OVERFLOW_BIT; + cmd->residual_count = length - cmd->data_length; + } else { + cmd->se_cmd_flags &= ~(SCF_OVERFLOW_BIT | SCF_UNDERFLOW_BIT); + cmd->residual_count = 0; } target_complete_cmd(cmd, scsi_status);