mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-18 19:21:26 +00:00
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:
@@ -656,8 +656,6 @@ enum scst_tg_sup {
|
|||||||
** Misc SCSI constants
|
** Misc SCSI constants
|
||||||
*************************************************************/
|
*************************************************************/
|
||||||
#define SCST_SENSE_ASC_UA_RESET 0x29
|
#define SCST_SENSE_ASC_UA_RESET 0x29
|
||||||
#define POSITION_LEN_SHORT 20
|
|
||||||
#define POSITION_LEN_LONG 32
|
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
** Compatibility constants
|
** Compatibility constants
|
||||||
|
|||||||
@@ -10684,8 +10684,6 @@ static int get_cdb_info_serv_act_in(struct scst_cmd *cmd,
|
|||||||
case SAI_READ_CAPACITY_16:
|
case SAI_READ_CAPACITY_16:
|
||||||
cmd->op_name = "READ CAPACITY(16)";
|
cmd->op_name = "READ CAPACITY(16)";
|
||||||
cmd->bufflen = get_unaligned_be32(&cmd->cdb[10]);
|
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 |
|
cmd->op_flags |= SCST_IMPLICIT_HQ | SCST_LBA_NOT_VALID |
|
||||||
SCST_REG_RESERVE_ALLOWED |
|
SCST_REG_RESERVE_ALLOWED |
|
||||||
SCST_WRITE_EXCL_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->op_name = "GET LBA STATUS";
|
||||||
cmd->lba = get_unaligned_be64(&cmd->cdb[2]);
|
cmd->lba = get_unaligned_be64(&cmd->cdb[2]);
|
||||||
cmd->bufflen = get_unaligned_be32(&cmd->cdb[10]);
|
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;
|
cmd->op_flags |= SCST_WRITE_EXCL_ALLOWED;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -10706,16 +10702,8 @@ static int get_cdb_info_serv_act_in(struct scst_cmd *cmd,
|
|||||||
|
|
||||||
cmd->data_len = cmd->bufflen;
|
cmd->data_len = cmd->bufflen;
|
||||||
|
|
||||||
out:
|
|
||||||
TRACE_EXIT_RES(res);
|
TRACE_EXIT_RES(res);
|
||||||
return 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,
|
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);
|
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) {
|
switch (cmd->cdb[1] & 0x1f) {
|
||||||
case 0:
|
case 0:
|
||||||
case 1:
|
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);
|
cmd->lba = get_unaligned_be32(cmd->cdb + sdbops->info_lba_off);
|
||||||
if (cmd->cdb[1] & 2) { /* BYTCHK 01 */
|
if (cmd->cdb[1] & 2) { /* BYTCHK 01 */
|
||||||
cmd->bufflen = get_unaligned_be32(cmd->cdb + sdbops->info_len_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;
|
cmd->data_len = cmd->bufflen;
|
||||||
cmd->data_direction = SCST_DATA_WRITE;
|
cmd->data_direction = SCST_DATA_WRITE;
|
||||||
} else {
|
} 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);
|
cmd->lba = get_unaligned_be64(cmd->cdb + sdbops->info_lba_off);
|
||||||
if (cmd->cdb[1] & 2) { /* BYTCHK 01 */
|
if (cmd->cdb[1] & 2) { /* BYTCHK 01 */
|
||||||
cmd->bufflen = get_unaligned_be32(cmd->cdb + sdbops->info_len_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;
|
cmd->data_len = cmd->bufflen;
|
||||||
cmd->data_direction = SCST_DATA_WRITE;
|
cmd->data_direction = SCST_DATA_WRITE;
|
||||||
} else {
|
} 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);
|
cmd->lba = get_unaligned_be64(cmd->cdb + sdbops->info_lba_off);
|
||||||
if (cmd->cdb[10] & 2) {
|
if (cmd->cdb[10] & 2) {
|
||||||
cmd->bufflen = get_unaligned_be32(cmd->cdb + sdbops->info_len_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;
|
cmd->data_len = cmd->bufflen;
|
||||||
cmd->data_direction = SCST_DATA_WRITE;
|
cmd->data_direction = SCST_DATA_WRITE;
|
||||||
} else {
|
} else {
|
||||||
@@ -11085,12 +11042,6 @@ static int get_cdb_info_len_4(struct scst_cmd *cmd,
|
|||||||
cmd->op_flags |= SCST_LBA_NOT_VALID;
|
cmd->op_flags |= SCST_LBA_NOT_VALID;
|
||||||
cmd->lba = 0;
|
cmd->lba = 0;
|
||||||
cmd->bufflen = get_unaligned_be32(cmd->cdb + sdbops->info_len_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;
|
cmd->data_len = cmd->bufflen;
|
||||||
return 0;
|
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->lba = get_unaligned_be32(cmd->cdb + sdbops->info_lba_off);
|
||||||
cmd->bufflen = get_unaligned_be32(cmd->cdb + sdbops->info_len_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;
|
cmd->data_len = cmd->bufflen;
|
||||||
return 0;
|
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->lba = get_unaligned_be64(cmd->cdb + sdbops->info_lba_off);
|
||||||
cmd->bufflen = get_unaligned_be32(cmd->cdb + sdbops->info_len_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;
|
cmd->data_len = cmd->bufflen;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -11956,28 +11895,30 @@ int scst_tape_generic_parse(struct scst_cmd *cmd)
|
|||||||
* therefore change them only if necessary
|
* 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) {
|
if (cmd->op_flags & SCST_TRANSFER_LEN_TYPE_FIXED && cmd->cdb[1] & 1) {
|
||||||
int block_size = cmd->dev->block_size;
|
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->bufflen = cmd->bufflen * block_size;
|
||||||
cmd->data_len = cmd->data_len * block_size;
|
cmd->data_len = cmd->data_len * block_size;
|
||||||
cmd->out_bufflen = cmd->out_bufflen * 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)
|
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)
|
else if (cmd->op_flags & SCST_LONG_TIMEOUT)
|
||||||
cmd->timeout = SCST_GENERIC_TAPE_LONG_TIMEOUT;
|
cmd->timeout = SCST_GENERIC_TAPE_LONG_TIMEOUT;
|
||||||
|
|
||||||
|
out:
|
||||||
TRACE_EXIT_RES(res);
|
TRACE_EXIT_RES(res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user