diff options
author | Sagi Grimberg <sagig@mellanox.com> | 2014-02-19 17:50:15 +0200 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2014-03-13 12:03:02 -0700 |
commit | 19f9361af7dfa0bb1f98c7619544ed71d2dded39 (patch) | |
tree | 4afa7db32e56d65500661134906c729699f226bc | |
parent | acb2bde3e32100f1ab50e38f0db03660a1cb0a06 (diff) | |
download | linux-19f9361af7dfa0bb1f98c7619544ed71d2dded39.tar.bz2 |
Target/sbc: Set protection operation and relevant checks
SBC-3 mandates the protection checks that must be
performed in the rdprotect/wrprotect field. Use them.
According to backstore device pi_attributes and
cdb rdprotect/wrprotect field.
(Fix incorrect se_cmd->prot_type -> TARGET_PROT_NORMAL
comparision in transport_generic_new_cmd - nab)
(Fix missing break in sbc_set_prot_op_checks - DanC + Sagi)
Signed-off-by: Sagi Grimberg <sagig@mellanox.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r-- | drivers/target/target_core_sbc.c | 87 | ||||
-rw-r--r-- | drivers/target/target_core_transport.c | 2 | ||||
-rw-r--r-- | include/target/target_core_base.h | 7 |
3 files changed, 81 insertions, 15 deletions
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 77e6531fb0a1..a1e75dd636ac 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -569,30 +569,85 @@ sbc_compare_and_write(struct se_cmd *cmd) return TCM_NO_SENSE; } +static int +sbc_set_prot_op_checks(u8 protect, enum target_prot_type prot_type, + bool is_write, struct se_cmd *cmd) +{ + if (is_write) { + cmd->prot_op = protect ? TARGET_PROT_DOUT_PASS : + TARGET_PROT_DOUT_INSERT; + switch (protect) { + case 0x0: + case 0x3: + cmd->prot_checks = 0; + break; + case 0x1: + case 0x5: + cmd->prot_checks = TARGET_DIF_CHECK_GUARD; + if (prot_type == TARGET_DIF_TYPE1_PROT) + cmd->prot_checks |= TARGET_DIF_CHECK_REFTAG; + break; + case 0x2: + if (prot_type == TARGET_DIF_TYPE1_PROT) + cmd->prot_checks = TARGET_DIF_CHECK_REFTAG; + break; + case 0x4: + cmd->prot_checks = TARGET_DIF_CHECK_GUARD; + break; + default: + pr_err("Unsupported protect field %d\n", protect); + return -EINVAL; + } + } else { + cmd->prot_op = protect ? TARGET_PROT_DIN_PASS : + TARGET_PROT_DIN_STRIP; + switch (protect) { + case 0x0: + case 0x1: + case 0x5: + cmd->prot_checks = TARGET_DIF_CHECK_GUARD; + if (prot_type == TARGET_DIF_TYPE1_PROT) + cmd->prot_checks |= TARGET_DIF_CHECK_REFTAG; + break; + case 0x2: + if (prot_type == TARGET_DIF_TYPE1_PROT) + cmd->prot_checks = TARGET_DIF_CHECK_REFTAG; + break; + case 0x3: + cmd->prot_checks = 0; + break; + case 0x4: + cmd->prot_checks = TARGET_DIF_CHECK_GUARD; + break; + default: + pr_err("Unsupported protect field %d\n", protect); + return -EINVAL; + } + } + + return 0; +} + static bool sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb, - u32 sectors) + u32 sectors, bool is_write) { + u8 protect = cdb[1] >> 5; + if (!cmd->t_prot_sg || !cmd->t_prot_nents) return true; switch (dev->dev_attrib.pi_prot_type) { case TARGET_DIF_TYPE3_PROT: - if (!(cdb[1] & 0xe0)) - return true; - cmd->reftag_seed = 0xffffffff; break; case TARGET_DIF_TYPE2_PROT: - if (cdb[1] & 0xe0) + if (protect) return false; cmd->reftag_seed = cmd->t_task_lba; break; case TARGET_DIF_TYPE1_PROT: - if (!(cdb[1] & 0xe0)) - return true; - cmd->reftag_seed = cmd->t_task_lba; break; case TARGET_DIF_TYPE0_PROT: @@ -600,6 +655,10 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb, return true; } + if (sbc_set_prot_op_checks(protect, dev->dev_attrib.pi_prot_type, + is_write, cmd)) + return false; + cmd->prot_type = dev->dev_attrib.pi_prot_type; cmd->prot_length = dev->prot_length * sectors; cmd->prot_handover = PROT_SEPERATED; @@ -628,7 +687,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) sectors = transport_get_sectors_10(cdb); cmd->t_task_lba = transport_lba_32(cdb); - if (!sbc_check_prot(dev, cmd, cdb, sectors)) + if (!sbc_check_prot(dev, cmd, cdb, sectors, false)) return TCM_UNSUPPORTED_SCSI_OPCODE; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; @@ -639,7 +698,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) sectors = transport_get_sectors_12(cdb); cmd->t_task_lba = transport_lba_32(cdb); - if (!sbc_check_prot(dev, cmd, cdb, sectors)) + if (!sbc_check_prot(dev, cmd, cdb, sectors, false)) return TCM_UNSUPPORTED_SCSI_OPCODE; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; @@ -650,7 +709,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) sectors = transport_get_sectors_16(cdb); cmd->t_task_lba = transport_lba_64(cdb); - if (!sbc_check_prot(dev, cmd, cdb, sectors)) + if (!sbc_check_prot(dev, cmd, cdb, sectors, false)) return TCM_UNSUPPORTED_SCSI_OPCODE; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; @@ -669,7 +728,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) sectors = transport_get_sectors_10(cdb); cmd->t_task_lba = transport_lba_32(cdb); - if (!sbc_check_prot(dev, cmd, cdb, sectors)) + if (!sbc_check_prot(dev, cmd, cdb, sectors, true)) return TCM_UNSUPPORTED_SCSI_OPCODE; if (cdb[1] & 0x8) @@ -682,7 +741,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) sectors = transport_get_sectors_12(cdb); cmd->t_task_lba = transport_lba_32(cdb); - if (!sbc_check_prot(dev, cmd, cdb, sectors)) + if (!sbc_check_prot(dev, cmd, cdb, sectors, true)) return TCM_UNSUPPORTED_SCSI_OPCODE; if (cdb[1] & 0x8) @@ -695,7 +754,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) sectors = transport_get_sectors_16(cdb); cmd->t_task_lba = transport_lba_64(cdb); - if (!sbc_check_prot(dev, cmd, cdb, sectors)) + if (!sbc_check_prot(dev, cmd, cdb, sectors, true)) return TCM_UNSUPPORTED_SCSI_OPCODE; if (cdb[1] & 0x8) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 6ddd4cfc53ba..4653d826e595 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2206,7 +2206,7 @@ transport_generic_new_cmd(struct se_cmd *cmd) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } - if (cmd->prot_type != TARGET_PROT_NORMAL) { + if (cmd->prot_op != TARGET_PROT_NORMAL) { ret = target_alloc_sgl(&cmd->t_prot_sg, &cmd->t_prot_nents, cmd->prot_length, true); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 1772fadcff62..5ae92492d1ee 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -463,6 +463,12 @@ enum target_prot_type { TARGET_DIF_TYPE3_PROT, }; +enum target_core_dif_check { + TARGET_DIF_CHECK_GUARD = 0x1 << 0, + TARGET_DIF_CHECK_APPTAG = 0x1 << 1, + TARGET_DIF_CHECK_REFTAG = 0x1 << 2, +}; + struct se_dif_v1_tuple { __be16 guard_tag; __be16 app_tag; @@ -556,6 +562,7 @@ struct se_cmd { /* DIF related members */ enum target_prot_op prot_op; enum target_prot_type prot_type; + u8 prot_checks; u32 prot_length; u32 reftag_seed; struct scatterlist *t_prot_sg; |