scst: fix tapes handling with Windows initiators

Reported and tested by Florian Gall <florian@enterprize.dyndns.info>



git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@7006 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2016-10-11 03:06:41 +00:00
parent 74a537dcfd
commit be8b679bb8
2 changed files with 19 additions and 79 deletions

View File

@@ -656,8 +656,6 @@ enum scst_tg_sup {
** Misc SCSI constants
*************************************************************/
#define SCST_SENSE_ASC_UA_RESET 0x29
#define POSITION_LEN_SHORT 20
#define POSITION_LEN_LONG 32
/*************************************************************
** Compatibility constants

View File

@@ -10684,8 +10684,6 @@ static int get_cdb_info_serv_act_in(struct scst_cmd *cmd,
case SAI_READ_CAPACITY_16:
cmd->op_name = "READ CAPACITY(16)";
cmd->bufflen = get_unaligned_be32(&cmd->cdb[10]);
if (unlikely(cmd->bufflen & SCST_MAX_VALID_BUFFLEN_MASK))
goto out_inval_bufflen10;
cmd->op_flags |= SCST_IMPLICIT_HQ | SCST_LBA_NOT_VALID |
SCST_REG_RESERVE_ALLOWED |
SCST_WRITE_EXCL_ALLOWED |
@@ -10695,8 +10693,6 @@ static int get_cdb_info_serv_act_in(struct scst_cmd *cmd,
cmd->op_name = "GET LBA STATUS";
cmd->lba = get_unaligned_be64(&cmd->cdb[2]);
cmd->bufflen = get_unaligned_be32(&cmd->cdb[10]);
if (unlikely(cmd->bufflen & SCST_MAX_VALID_BUFFLEN_MASK))
goto out_inval_bufflen10;
cmd->op_flags |= SCST_WRITE_EXCL_ALLOWED;
break;
default:
@@ -10706,16 +10702,8 @@ static int get_cdb_info_serv_act_in(struct scst_cmd *cmd,
cmd->data_len = cmd->bufflen;
out:
TRACE_EXIT_RES(res);
return res;
out_inval_bufflen10:
PRINT_ERROR("Too big bufflen %d (op %s)", cmd->bufflen,
scst_get_opcode_name(cmd));
scst_set_invalid_field_in_cdb(cmd, 10, 0);
res = 1;
goto out;
}
static int get_cdb_info_single(struct scst_cmd *cmd,
@@ -10738,19 +10726,6 @@ static int get_cdb_info_read_pos(struct scst_cmd *cmd,
cmd->bufflen = get_unaligned_be16(cmd->cdb + sdbops->info_len_off);
switch (cmd->cdb[1] & 0x1f) {
case 0:
case 1:
case 6:
if (cmd->bufflen != 0) {
PRINT_ERROR("READ POSITION: Invalid non-zero (%d) "
"allocation length for service action %x",
cmd->bufflen, cmd->cdb[1] & 0x1f);
goto out_inval_field1;
}
break;
}
switch (cmd->cdb[1] & 0x1f) {
case 0:
case 1:
@@ -10913,12 +10888,6 @@ static int get_cdb_info_verify12(struct scst_cmd *cmd,
cmd->lba = get_unaligned_be32(cmd->cdb + sdbops->info_lba_off);
if (cmd->cdb[1] & 2) { /* BYTCHK 01 */
cmd->bufflen = get_unaligned_be32(cmd->cdb + sdbops->info_len_off);
if (unlikely(cmd->bufflen & SCST_MAX_VALID_BUFFLEN_MASK)) {
PRINT_ERROR("Too big bufflen %d (op %s)",
cmd->bufflen, scst_get_opcode_name(cmd));
scst_set_invalid_field_in_cdb(cmd, sdbops->info_len_off, 0);
return 1;
}
cmd->data_len = cmd->bufflen;
cmd->data_direction = SCST_DATA_WRITE;
} else {
@@ -10943,12 +10912,6 @@ static int get_cdb_info_verify16(struct scst_cmd *cmd,
cmd->lba = get_unaligned_be64(cmd->cdb + sdbops->info_lba_off);
if (cmd->cdb[1] & 2) { /* BYTCHK 01 */
cmd->bufflen = get_unaligned_be32(cmd->cdb + sdbops->info_len_off);
if (unlikely(cmd->bufflen & SCST_MAX_VALID_BUFFLEN_MASK)) {
PRINT_ERROR("Too big bufflen %d (op %s)",
cmd->bufflen, scst_get_opcode_name(cmd));
scst_set_invalid_field_in_cdb(cmd, sdbops->info_len_off, 0);
return 1;
}
cmd->data_len = cmd->bufflen;
cmd->data_direction = SCST_DATA_WRITE;
} else {
@@ -10973,12 +10936,6 @@ static int get_cdb_info_verify32(struct scst_cmd *cmd,
cmd->lba = get_unaligned_be64(cmd->cdb + sdbops->info_lba_off);
if (cmd->cdb[10] & 2) {
cmd->bufflen = get_unaligned_be32(cmd->cdb + sdbops->info_len_off);
if (unlikely(cmd->bufflen & SCST_MAX_VALID_BUFFLEN_MASK)) {
PRINT_ERROR("Too big bufflen %d (op %s)",
cmd->bufflen, scst_get_opcode_name(cmd));
scst_set_invalid_field_in_cdb(cmd, sdbops->info_len_off, 0);
return 1;
}
cmd->data_len = cmd->bufflen;
cmd->data_direction = SCST_DATA_WRITE;
} else {
@@ -11085,12 +11042,6 @@ static int get_cdb_info_len_4(struct scst_cmd *cmd,
cmd->op_flags |= SCST_LBA_NOT_VALID;
cmd->lba = 0;
cmd->bufflen = get_unaligned_be32(cmd->cdb + sdbops->info_len_off);
if (unlikely(cmd->bufflen & SCST_MAX_VALID_BUFFLEN_MASK)) {
PRINT_ERROR("Too big bufflen %d (op %s)", cmd->bufflen,
scst_get_opcode_name(cmd));
scst_set_invalid_field_in_cdb(cmd, sdbops->info_len_off, 0);
return 1;
}
cmd->data_len = cmd->bufflen;
return 0;
}
@@ -11185,12 +11136,6 @@ static inline int get_cdb_info_lba_4_len_4(struct scst_cmd *cmd,
{
cmd->lba = get_unaligned_be32(cmd->cdb + sdbops->info_lba_off);
cmd->bufflen = get_unaligned_be32(cmd->cdb + sdbops->info_len_off);
if (unlikely(cmd->bufflen & SCST_MAX_VALID_BUFFLEN_MASK)) {
PRINT_ERROR("Too big bufflen %d (op %s)", cmd->bufflen,
scst_get_opcode_name(cmd));
scst_set_invalid_field_in_cdb(cmd, sdbops->info_len_off, 0);
return 1;
}
cmd->data_len = cmd->bufflen;
return 0;
}
@@ -11222,12 +11167,6 @@ static inline int get_cdb_info_lba_8_len_4(struct scst_cmd *cmd,
{
cmd->lba = get_unaligned_be64(cmd->cdb + sdbops->info_lba_off);
cmd->bufflen = get_unaligned_be32(cmd->cdb + sdbops->info_len_off);
if (unlikely(cmd->bufflen & SCST_MAX_VALID_BUFFLEN_MASK)) {
PRINT_ERROR("Too big bufflen %d (op %s)", cmd->bufflen,
scst_get_opcode_name(cmd));
scst_set_invalid_field_in_cdb(cmd, sdbops->info_len_off, 0);
return 1;
}
cmd->data_len = cmd->bufflen;
return 0;
}
@@ -11956,28 +11895,30 @@ int scst_tape_generic_parse(struct scst_cmd *cmd)
* therefore change them only if necessary
*/
if (cmd->cdb[0] == READ_POSITION) {
int tclp = cmd->cdb[1] & 4;
int long_bit = cmd->cdb[1] & 2;
int bt = cmd->cdb[1] & 1;
if ((tclp == long_bit) && (!bt || !long_bit)) {
cmd->bufflen =
tclp ? POSITION_LEN_LONG : POSITION_LEN_SHORT;
cmd->data_direction = SCST_DATA_READ;
} else {
cmd->bufflen = 0;
cmd->data_direction = SCST_DATA_NONE;
}
cmd->data_len = cmd->bufflen;
}
if (cmd->op_flags & SCST_TRANSFER_LEN_TYPE_FIXED && cmd->cdb[1] & 1) {
int block_size = cmd->dev->block_size;
unsigned int ob = cmd->bufflen, od = cmd->data_len, oo = cmd->out_bufflen;
bool overflow;
cmd->bufflen = cmd->bufflen * block_size;
cmd->data_len = cmd->data_len * block_size;
cmd->out_bufflen = cmd->out_bufflen * block_size;
overflow = (ob < (unsigned int)cmd->bufflen) ||
(od < (unsigned int)cmd->data_len) ||
(oo < (unsigned int)cmd->out_bufflen);
if (unlikely(overflow)) {
PRINT_WARNING("bufflen %u, data_len %llu or out_bufflen"
" %u too large for device %s (block size"
" %u)", cmd->bufflen, cmd->data_len,
cmd->out_bufflen, cmd->dev->virt_name,
block_size);
PRINT_BUFFER("CDB", cmd->cdb, cmd->cdb_len);
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(
scst_sense_block_out_range_error));
res = -EINVAL;
goto out;
}
}
if ((cmd->op_flags & (SCST_SMALL_TIMEOUT | SCST_LONG_TIMEOUT)) == 0)
@@ -11987,6 +11928,7 @@ int scst_tape_generic_parse(struct scst_cmd *cmd)
else if (cmd->op_flags & SCST_LONG_TIMEOUT)
cmd->timeout = SCST_GENERIC_TAPE_LONG_TIMEOUT;
out:
TRACE_EXIT_RES(res);
return res;
}