Commit 19f9361a authored by Sagi Grimberg's avatar Sagi Grimberg Committed by Nicholas Bellinger

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: default avatarSagi Grimberg <sagig@mellanox.com>
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent acb2bde3
...@@ -569,30 +569,85 @@ sbc_compare_and_write(struct se_cmd *cmd) ...@@ -569,30 +569,85 @@ sbc_compare_and_write(struct se_cmd *cmd)
return TCM_NO_SENSE; 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 static bool
sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb, 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) if (!cmd->t_prot_sg || !cmd->t_prot_nents)
return true; return true;
switch (dev->dev_attrib.pi_prot_type) { switch (dev->dev_attrib.pi_prot_type) {
case TARGET_DIF_TYPE3_PROT: case TARGET_DIF_TYPE3_PROT:
if (!(cdb[1] & 0xe0))
return true;
cmd->reftag_seed = 0xffffffff; cmd->reftag_seed = 0xffffffff;
break; break;
case TARGET_DIF_TYPE2_PROT: case TARGET_DIF_TYPE2_PROT:
if (cdb[1] & 0xe0) if (protect)
return false; return false;
cmd->reftag_seed = cmd->t_task_lba; cmd->reftag_seed = cmd->t_task_lba;
break; break;
case TARGET_DIF_TYPE1_PROT: case TARGET_DIF_TYPE1_PROT:
if (!(cdb[1] & 0xe0))
return true;
cmd->reftag_seed = cmd->t_task_lba; cmd->reftag_seed = cmd->t_task_lba;
break; break;
case TARGET_DIF_TYPE0_PROT: case TARGET_DIF_TYPE0_PROT:
...@@ -600,6 +655,10 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb, ...@@ -600,6 +655,10 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb,
return true; 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_type = dev->dev_attrib.pi_prot_type;
cmd->prot_length = dev->prot_length * sectors; cmd->prot_length = dev->prot_length * sectors;
cmd->prot_handover = PROT_SEPERATED; cmd->prot_handover = PROT_SEPERATED;
...@@ -628,7 +687,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) ...@@ -628,7 +687,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
sectors = transport_get_sectors_10(cdb); sectors = transport_get_sectors_10(cdb);
cmd->t_task_lba = transport_lba_32(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; return TCM_UNSUPPORTED_SCSI_OPCODE;
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
...@@ -639,7 +698,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) ...@@ -639,7 +698,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
sectors = transport_get_sectors_12(cdb); sectors = transport_get_sectors_12(cdb);
cmd->t_task_lba = transport_lba_32(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; return TCM_UNSUPPORTED_SCSI_OPCODE;
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
...@@ -650,7 +709,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) ...@@ -650,7 +709,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
sectors = transport_get_sectors_16(cdb); sectors = transport_get_sectors_16(cdb);
cmd->t_task_lba = transport_lba_64(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; return TCM_UNSUPPORTED_SCSI_OPCODE;
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
...@@ -669,7 +728,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) ...@@ -669,7 +728,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
sectors = transport_get_sectors_10(cdb); sectors = transport_get_sectors_10(cdb);
cmd->t_task_lba = transport_lba_32(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; return TCM_UNSUPPORTED_SCSI_OPCODE;
if (cdb[1] & 0x8) if (cdb[1] & 0x8)
...@@ -682,7 +741,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) ...@@ -682,7 +741,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
sectors = transport_get_sectors_12(cdb); sectors = transport_get_sectors_12(cdb);
cmd->t_task_lba = transport_lba_32(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; return TCM_UNSUPPORTED_SCSI_OPCODE;
if (cdb[1] & 0x8) if (cdb[1] & 0x8)
...@@ -695,7 +754,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) ...@@ -695,7 +754,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
sectors = transport_get_sectors_16(cdb); sectors = transport_get_sectors_16(cdb);
cmd->t_task_lba = transport_lba_64(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; return TCM_UNSUPPORTED_SCSI_OPCODE;
if (cdb[1] & 0x8) if (cdb[1] & 0x8)
......
...@@ -2206,7 +2206,7 @@ transport_generic_new_cmd(struct se_cmd *cmd) ...@@ -2206,7 +2206,7 @@ transport_generic_new_cmd(struct se_cmd *cmd)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; 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, ret = target_alloc_sgl(&cmd->t_prot_sg,
&cmd->t_prot_nents, &cmd->t_prot_nents,
cmd->prot_length, true); cmd->prot_length, true);
......
...@@ -463,6 +463,12 @@ enum target_prot_type { ...@@ -463,6 +463,12 @@ enum target_prot_type {
TARGET_DIF_TYPE3_PROT, 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 { struct se_dif_v1_tuple {
__be16 guard_tag; __be16 guard_tag;
__be16 app_tag; __be16 app_tag;
...@@ -556,6 +562,7 @@ struct se_cmd { ...@@ -556,6 +562,7 @@ struct se_cmd {
/* DIF related members */ /* DIF related members */
enum target_prot_op prot_op; enum target_prot_op prot_op;
enum target_prot_type prot_type; enum target_prot_type prot_type;
u8 prot_checks;
u32 prot_length; u32 prot_length;
u32 reftag_seed; u32 reftag_seed;
struct scatterlist *t_prot_sg; struct scatterlist *t_prot_sg;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment