[stgt] [PATCH 12/13] sbc: fix data-in buffer generation for GET_LBA_STATUS

nezhinsky at gmail.com nezhinsky at gmail.com
Wed Jan 16 10:01:52 CET 2013


From: Alexander Nezhinsky <nezhinsky at gmail.com>

GET_LBA_STATUS is an SBC command behaving in SPC-like manner.
Generate data-in directly in the command buffer, building data and hole records
one by one, while taking into account the allocation length.
Set the actual transfer len correctly.

Signed-off-by: Alexander Nezhinsky <nezhinsky at gmail.com>
---
 usr/sbc.c |   77 ++++++++++++++++++++++++++++++++-----------------------------
 1 file changed, 40 insertions(+), 37 deletions(-)

diff --git a/usr/sbc.c b/usr/sbc.c
index b2a03e2..4784aa5 100644
--- a/usr/sbc.c
+++ b/usr/sbc.c
@@ -524,13 +524,13 @@ sense:
 
 static int sbc_getlbastatus(int host_no, struct scsi_cmd *cmd)
 {
-	int len = 32;
 	uint64_t offset;
-	uint32_t pdl;
-	int type;
+	uint32_t alloc_len, avail_len, actual_len, remain_len;
 	unsigned char *buf;
-	unsigned char key = ILLEGAL_REQUEST;
-	uint16_t asc = ASC_INVALID_OP_CODE;
+	uint8_t data[16];
+	int mapped;
+	uint16_t asc;
+	unsigned char key;
 
 	if (cmd->dev->attrs.removable && !cmd->dev->attrs.online) {
 		key = NOT_READY;
@@ -538,13 +538,6 @@ static int sbc_getlbastatus(int host_no, struct scsi_cmd *cmd)
 		goto sense;
 	}
 
-	if (scsi_get_in_length(cmd) < 24)
-		goto overflow;
-
-	len = scsi_get_in_length(cmd);
-	buf = scsi_get_in_buffer(cmd);
-	memset(buf, 0, len);
-
 	offset = get_unaligned_be64(&cmd->scb[2]) << cmd->dev->blk_shift;
 	if (offset >= cmd->dev->size) {
 		key = ILLEGAL_REQUEST;
@@ -552,41 +545,51 @@ static int sbc_getlbastatus(int host_no, struct scsi_cmd *cmd)
 		goto sense;
 	}
 
-	pdl = 4;
-	put_unaligned_be32(pdl, &buf[0]);
-
-	type = 0;
-	while (len >= 4 + pdl + 16) {
-		off_t next_offset;
+	alloc_len = get_unaligned_be32(&cmd->scb[10]);
+	if (alloc_len < 4 || scsi_get_in_length(cmd) < alloc_len) {
+		key = ILLEGAL_REQUEST;
+		asc = ASC_INVALID_FIELD_IN_CDB;
+		goto sense;
+	}
 
-		put_unaligned_be32(pdl + 16, &buf[0]);
+	avail_len = 0;
+	remain_len = alloc_len;
+	buf = scsi_get_in_buffer(cmd);
+	memset(data, 0, 16);
+	/* Copy zeros now - Parameter Data Length to be set later */
+	actual_len = mem_copy_n32(&buf[0], data, 8, &avail_len, &remain_len);
 
-		if (offset >= cmd->dev->size)
-			break;
+	mapped = 1;
+	do {
+		off_t next_offset;
+		uint64_t start_lba;
+		uint32_t num_blocks;
 
-		next_offset = (type == 0) ?
-			find_next_hole(cmd->dev, offset) :
-			find_next_data(cmd->dev, offset);
+		next_offset = (!mapped) ? find_next_data(cmd->dev, offset) :
+					  find_next_hole(cmd->dev, offset);
 		if (next_offset == offset) {
-			type = 1 - type;
+			mapped = 1 - mapped;
 			continue;
 		}
+		if (next_offset > cmd->dev->size)
+			next_offset = cmd->dev->size;
 
-		put_unaligned_be64(offset >> cmd->dev->blk_shift,
-				   &buf[4 + pdl +  0]);
-		put_unaligned_be32((next_offset - offset)
-				   >> cmd->dev->blk_shift,
-				   &buf[4 + pdl +  8]);
-		buf[4 + pdl + 12] = type;
+		start_lba = offset >> cmd->dev->blk_shift;
+		num_blocks = (next_offset - offset) >> cmd->dev->blk_shift;
+		put_unaligned_be64(start_lba, &data[0]);
+		put_unaligned_be32(num_blocks, &data[8]);
+		data[12] = (!mapped) ? 1 : 0; /* 0:mapped 1:deallocated */
 
-		pdl += 16;
-		type = 1 - type;
+		actual_len += mem_copy_n32(&buf[avail_len], data, 16,
+					   &avail_len, &remain_len);
+
+		mapped = 1 - mapped;
 		offset = next_offset;
-	}
-	len = 4 + pdl;
+	} while (offset < cmd->dev->size);
 
-overflow:
-	scsi_set_in_resid_by_actual(cmd, len);
+	put_unaligned_be32(avail_len - 4, &buf[0]); /* Parameter Data Len */
+
+	scsi_set_in_resid_by_actual(cmd, actual_len);
 	return SAM_STAT_GOOD;
 
 sense:
-- 
1.7.9.6

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



More information about the stgt mailing list