[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