Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+73 −14
Original line number Diff line number Diff line
@@ -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)
+1 −1
Original line number Diff line number Diff line
@@ -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);
+7 −0
Original line number Diff line number Diff line
@@ -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;