[PATCH] SBC READ6/10/12/16: Add handling of residual overflow/underflow.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch adds support to return overflow/underflow residuals
for the cases where the transport layer (iSCSI, ...) specifies
an EDTL that is not matching the SCSI transdfer length.

Additionally, in case of residual underflow it will also clamp the size of
returned DATA-IN to the amount of data that was actually read and not the
EDTL that was requested.

This is from RFC 3720, 10.4.1 :
     bit 6 - (U) set for Residual Underflow.  In this case, the Residual
       Count indicates the number of bytes that were not transferred out
       of the number of bytes that were expected to be transferred.  For
       a bidirectional operation, the Residual Count contains the
       residual for the write operation.

I have added a specific test for this condition to the testsute in
libiscsi :

./bin/iscsi-test-cu -t "TestRead10.testRead10Residuals" \
	iscsi://127.0.0.1/iqn.ronnie.test/1 -V

Suite: TestRead10
  Test: testRead10Residuals ...
    Test invalid READ10 commands
    Block size is 512
    Try reading one block but with iSCSI expected transfer length==0
    Verify that the target returned SUCCESS
    Verify residual overflow flag is set
    Verify we got 512 bytes of residual overflow
    Try reading one block but with iSCSI expected transfer length==10000
    Verify that the target returned SUCCESS
    Verify we got one whole block back from the target
    Verify residual underflow flag is set
    Verify we got 9488 bytes of residual underflow
    Try reading one block but with iSCSI expected transfer length==200
    Verify that the target returned SUCCESS
    Verify we got 200 bytes back from the target
    Verify residual overflow flag is set
    Verify we got 312 bytes of residual overflow
    Try reading two blocks but iSCSI expected transfer length==512 (==one block)
    Verify that the target returned SUCCESS
    Verify we got one whole block back from the target
    Verify residual overflow flag is set
    Verify we got one block of residual overflow
passed

--Run Summary: Type      Total     Ran  Passed  Failed
               suites        1       1     n/a       0
               tests         1       1       1       0
               asserts      24      24      24       0

Signed-off-by: Ronnie Sahlberg <ronniesahlberg@xxxxxxxxx>
---
 usr/sbc.c |   30 ++++++++++++++++++++++++++++--
 1 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/usr/sbc.c b/usr/sbc.c
index 48dab04..26cceb1 100644
--- a/usr/sbc.c
+++ b/usr/sbc.c
@@ -226,6 +226,8 @@ static int sbc_rw(int host_no, struct scsi_cmd *cmd)
 	int ret;
 	uint64_t lba;
 	uint32_t tl;
+	long residual = 0;
+	long length;
 	unsigned char key = ILLEGAL_REQUEST;
 	uint16_t asc = ASC_LUN_NOT_SUPPORTED;
 	struct scsi_lu *lu = cmd->dev;
@@ -335,12 +337,36 @@ static int sbc_rw(int host_no, struct scsi_cmd *cmd)
 	cmd->offset = lba << cmd->dev->blk_shift;
 	cmd->tl     = tl  << cmd->dev->blk_shift;
 
+	/* Handle residuals */
+	switch (cmd->scb[0]) {
+	case READ_6:
+	case READ_10:
+	case READ_12:
+	case READ_16:
+		length = scsi_get_in_length(cmd);
+		if (length != cmd->tl) {
+			residual = length - cmd->tl;
+
+			if (length > cmd->tl) {
+				length = cmd->tl;
+				scsi_set_in_transfer_len(cmd, cmd->tl);
+				scsi_set_in_length(cmd, cmd->tl);
+			}
+		}
+		break;
+	}
+
 	ret = cmd->dev->bst->bs_cmd_submit(cmd);
 	if (ret) {
 		key = HARDWARE_ERROR;
 		asc = ASC_INTERNAL_TGT_FAILURE;
-	} else
-		return SAM_STAT_GOOD;
+		goto sense;
+	}
+
+	if (residual)
+		scsi_set_in_resid(cmd, residual);
+
+	return SAM_STAT_GOOD;
 
 sense:
 	cmd->offset = 0;
-- 
1.7.3.1

--
To unsubscribe from this list: send the line "unsubscribe stgt" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux SCSI]     [Linux RAID]     [Linux Clusters]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]

  Powered by Linux