scst: Fix WRITE SAME parsing

* scst_lib: refuse WRITE SAME commands with UNMAP=0 and ANCHOR=1 or
  with UNMAP=0 and no data buffer. SBC-4 requires to respond with
  "ILLEGAL REQUEST / INVALID FIELD IN CDB" to such WRITE SAME commands.
* scst_lib: use the WRITE SAME(16) NODB bit to determine the data
  buffer length.
* scst_vdisk: test for the ANCHOR bit via mask 0x10 instead of mask 0x01.
* scst_vdisk: print an error message if a WRITE SAME command has been
  refused because of an unusual value of NUMBER OF LOGICAL BLOCKS.

Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
This commit is contained in:
Bart Van Assche
2015-04-14 10:40:33 +02:00
parent 6c46b1a5a0
commit bf9d2668a5
2 changed files with 33 additions and 6 deletions

View File

@@ -3201,10 +3201,10 @@ static enum compl_status_e vdisk_exec_write_same(struct vdisk_cmd_params *p)
TRACE_ENTRY();
if (unlikely(cmd->cdb[1] & 1)) {
if (unlikely(cmd->cdb[1] & 0x10)) {
TRACE_DBG("%s", "ANCHOR not supported");
scst_set_invalid_field_in_cdb(cmd, 1,
SCST_INVAL_FIELD_BIT_OFFS_VALID | 0);
SCST_INVAL_FIELD_BIT_OFFS_VALID | 4);
goto out;
}
@@ -3216,6 +3216,8 @@ static enum compl_status_e vdisk_exec_write_same(struct vdisk_cmd_params *p)
}
if (unlikely(cmd->data_len <= 0)) {
PRINT_ERROR("WRITE SAME: refused data_len = %#llx",
cmd->data_len);
scst_set_invalid_field_in_cdb(cmd, cmd->len_off, 0);
goto out;
}

View File

@@ -7550,22 +7550,47 @@ static int get_cdb_info_lba_8_len_4(struct scst_cmd *cmd,
return 0;
}
static int get_cdb_info_write_same(struct scst_cmd *cmd,
const struct scst_sdbops *sdbops,
const bool ndob)
{
const bool anchor = (cmd->cdb[1] >> 4) & 1;
const bool unmap = (cmd->cdb[1] >> 3) & 1;
if (!unmap && (anchor || ndob)) {
PRINT_ERROR("Received invalid %s command (UNMAP = %d;"
" ANCHOR = %d; NDOB = %d)",
scst_get_opcode_name(cmd), unmap, anchor, ndob);
scst_set_invalid_field_in_cdb(cmd, 1,
SCST_INVAL_FIELD_BIT_OFFS_VALID | (ndob ? 0 : 4));
return 1;
}
if (ndob) {
cmd->bufflen = 0;
cmd->data_direction = SCST_DATA_NONE;
} else {
cmd->bufflen = 1;
cmd->data_direction = SCST_DATA_WRITE;
}
return 0;
}
static int get_cdb_info_write_same10(struct scst_cmd *cmd,
const struct scst_sdbops *sdbops)
{
cmd->lba = get_unaligned_be32(cmd->cdb + sdbops->info_lba_off);
cmd->bufflen = 1;
cmd->data_len = get_unaligned_be16(cmd->cdb + sdbops->info_len_off);
return 0;
return get_cdb_info_write_same(cmd, sdbops, false);
}
static int get_cdb_info_write_same16(struct scst_cmd *cmd,
const struct scst_sdbops *sdbops)
{
cmd->lba = get_unaligned_be64(cmd->cdb + sdbops->info_lba_off);
cmd->bufflen = 1;
cmd->data_len = get_unaligned_be32(cmd->cdb + sdbops->info_len_off);
return 0;
return get_cdb_info_write_same(cmd, sdbops, cmd->cdb[1] & 1 /*NDOB*/);
}
static int get_cdb_info_compare_and_write(struct scst_cmd *cmd,