From 47efee04ce7f7b9eb5dddcf4531de66baea05e87 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 16 Jun 2015 23:51:26 +0000 Subject: [PATCH] scst: Fix WRITE SAME parsing Check bit 4 instead of bit 0 as the ANCHOR bit. Handle the NDOB bit correctly. git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@6347 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/src/dev_handlers/scst_vdisk.c | 6 +++-- scst/src/scst_lib.c | 38 +++++++++++++++++++++++++----- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index f90d1ab90..6c826d2b4 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -3696,14 +3696,16 @@ static enum compl_status_e vdisk_exec_write_same(struct vdisk_cmd_params *p) TRACE_ENTRY(); - if (unlikely(cmd->cdb[ctrl_offs] & 1)) { + if (unlikely(cmd->cdb[ctrl_offs] & 0x10)) { TRACE_DBG("%s", "ANCHOR not supported"); scst_set_invalid_field_in_cdb(cmd, ctrl_offs, - SCST_INVAL_FIELD_BIT_OFFS_VALID | 0); + SCST_INVAL_FIELD_BIT_OFFS_VALID | 4); goto out; } 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; } diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 97cf59e8a..901d7409f 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -10154,31 +10154,57 @@ static int get_cdb_info_lba_8_len_4_rdprotect32(struct scst_cmd *cmd, return scst_parse_rdprotect32(cmd); } +static int get_cdb_info_write_same(struct scst_cmd *cmd, + const struct scst_sdbops *sdbops, + const bool ndob) +{ + const uint8_t ctrl_offs = cmd->cdb_len < 32 ? 1 : 10; + const bool anchor = (cmd->cdb[ctrl_offs] >> 4) & 1; + const bool unmap = (cmd->cdb[ctrl_offs] >> 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, ctrl_offs, + 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 cmd->cdb_len < 32 ? scst_parse_wrprotect(cmd) : + scst_parse_wrprotect32(cmd); +} + 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 scst_parse_wrprotect(cmd); + 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 scst_parse_wrprotect(cmd); + return get_cdb_info_write_same(cmd, sdbops, cmd->cdb[1] & 1 /*NDOB*/); } static int get_cdb_info_write_same32(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 scst_parse_wrprotect32(cmd); + return get_cdb_info_write_same(cmd, sdbops, cmd->cdb[1] & 1 /*NDOB*/); } static int scst_set_cmd_from_cdb_info(struct scst_cmd *cmd,