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>
This commit is contained in:
parent
acb2bde3e3
commit
19f9361af7
3 changed files with 81 additions and 15 deletions
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue