From: Alexander Nezhinsky <nezhinsky@xxxxxxxxx> 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@xxxxxxxxx> --- usr/sbc.c | 79 ++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 42 insertions(+), 37 deletions(-) diff --git a/usr/sbc.c b/usr/sbc.c index 7fb1ea8..48dab04 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,53 @@ 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 = spc_memcpy(&buf[0], &remain_len, data, 8); + avail_len += 8; - 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 += spc_memcpy(&buf[avail_len], &remain_len, + data, 16); + avail_len += 16; + + 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@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html