summaryrefslogtreecommitdiffstats
path: root/drivers/target
diff options
context:
space:
mode:
authorSumit Rai <sumitrai96@gmail.com>2016-07-20 16:59:42 -0400
committerNicholas Bellinger <nab@linux-iscsi.org>2016-07-24 02:34:54 -0400
commitc1ccbfe0311e2380a6d2dcb0714b36904f5d586f (patch)
treec5fa2656c5ede92e8c2de52a0c133d0f67658ec7 /drivers/target
parent107818e2dad943ec357f6fdfa70377317a142d9d (diff)
target: Fix residual overflow handling in target_complete_cmd_with_length
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 <sumitrai96@gmail.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target')
-rw-r--r--drivers/target/target_core_transport.c16
1 files changed, 15 insertions, 1 deletions
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);
754 754
755void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int length) 755void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int length)
756{ 756{
757 if (scsi_status == SAM_STAT_GOOD && length < cmd->data_length) { 757 if (scsi_status != SAM_STAT_GOOD) {
758 return;
759 }
760
761 /*
762 * Calculate new residual count based upon length of SCSI data
763 * transferred.
764 */
765 if (length < cmd->data_length) {
758 if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) { 766 if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) {
759 cmd->residual_count += cmd->data_length - length; 767 cmd->residual_count += cmd->data_length - length;
760 } else { 768 } else {
@@ -763,6 +771,12 @@ void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int len
763 } 771 }
764 772
765 cmd->data_length = length; 773 cmd->data_length = length;
774 } else if (length > cmd->data_length) {
775 cmd->se_cmd_flags |= SCF_OVERFLOW_BIT;
776 cmd->residual_count = length - cmd->data_length;
777 } else {
778 cmd->se_cmd_flags &= ~(SCF_OVERFLOW_BIT | SCF_UNDERFLOW_BIT);
779 cmd->residual_count = 0;
766 } 780 }
767 781
768 target_complete_cmd(cmd, scsi_status); 782 target_complete_cmd(cmd, scsi_status);