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

Commit fde9f50f authored by Nicholas Bellinger's avatar Nicholas Bellinger
Browse files

target: Add sanity checks for DPO/FUA bit usage



This patch adds a sbc_check_dpofua() function that performs sanity
checks for DPO/FUA command bits.

It introduces checks to fail when either bit is set, but the backend
device is not advertising support for them.

It also moves the existing cmd->se_cmd_flags |= SCF_FUA assignement
into the new helper function.

Cc: Christoph Hellwig <hch@lst.de>
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent afd73f1b
Loading
Loading
Loading
Loading
+46 −10
Original line number Original line Diff line number Diff line
@@ -692,6 +692,29 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb,
	return TCM_NO_SENSE;
	return TCM_NO_SENSE;
}
}


static int
sbc_check_dpofua(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb)
{
	if (cdb[1] & 0x10) {
		if (!dev->dev_attrib.emulate_dpo) {
			pr_err("Got CDB: 0x%02x with DPO bit set, but device"
			       " does not advertise support for DPO\n", cdb[0]);
			return -EINVAL;
		}
	}
	if (cdb[1] & 0x8) {
		if (!dev->dev_attrib.emulate_fua_write ||
		    !dev->dev_attrib.emulate_write_cache) {
			pr_err("Got CDB: 0x%02x with FUA bit set, but device"
			       " does not advertise support for FUA write\n",
			       cdb[0]);
			return -EINVAL;
		}
		cmd->se_cmd_flags |= SCF_FUA;
	}
	return 0;
}

sense_reason_t
sense_reason_t
sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
{
{
@@ -713,6 +736,9 @@ 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_dpofua(dev, cmd, cdb))
			return TCM_INVALID_CDB_FIELD;

		ret = sbc_check_prot(dev, cmd, cdb, sectors, false);
		ret = sbc_check_prot(dev, cmd, cdb, sectors, false);
		if (ret)
		if (ret)
			return ret;
			return ret;
@@ -725,6 +751,9 @@ 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_dpofua(dev, cmd, cdb))
			return TCM_INVALID_CDB_FIELD;

		ret = sbc_check_prot(dev, cmd, cdb, sectors, false);
		ret = sbc_check_prot(dev, cmd, cdb, sectors, false);
		if (ret)
		if (ret)
			return ret;
			return ret;
@@ -737,6 +766,9 @@ 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_dpofua(dev, cmd, cdb))
			return TCM_INVALID_CDB_FIELD;

		ret = sbc_check_prot(dev, cmd, cdb, sectors, false);
		ret = sbc_check_prot(dev, cmd, cdb, sectors, false);
		if (ret)
		if (ret)
			return ret;
			return ret;
@@ -757,12 +789,13 @@ 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_dpofua(dev, cmd, cdb))
			return TCM_INVALID_CDB_FIELD;

		ret = sbc_check_prot(dev, cmd, cdb, sectors, true);
		ret = sbc_check_prot(dev, cmd, cdb, sectors, true);
		if (ret)
		if (ret)
			return ret;
			return ret;


		if (cdb[1] & 0x8)
			cmd->se_cmd_flags |= SCF_FUA;
		cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
		cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
		cmd->execute_rw = ops->execute_rw;
		cmd->execute_rw = ops->execute_rw;
		cmd->execute_cmd = sbc_execute_rw;
		cmd->execute_cmd = sbc_execute_rw;
@@ -771,12 +804,13 @@ 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_dpofua(dev, cmd, cdb))
			return TCM_INVALID_CDB_FIELD;

		ret = sbc_check_prot(dev, cmd, cdb, sectors, true);
		ret = sbc_check_prot(dev, cmd, cdb, sectors, true);
		if (ret)
		if (ret)
			return ret;
			return ret;


		if (cdb[1] & 0x8)
			cmd->se_cmd_flags |= SCF_FUA;
		cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
		cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
		cmd->execute_rw = ops->execute_rw;
		cmd->execute_rw = ops->execute_rw;
		cmd->execute_cmd = sbc_execute_rw;
		cmd->execute_cmd = sbc_execute_rw;
@@ -785,12 +819,13 @@ 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_dpofua(dev, cmd, cdb))
			return TCM_INVALID_CDB_FIELD;

		ret = sbc_check_prot(dev, cmd, cdb, sectors, true);
		ret = sbc_check_prot(dev, cmd, cdb, sectors, true);
		if (ret)
		if (ret)
			return ret;
			return ret;


		if (cdb[1] & 0x8)
			cmd->se_cmd_flags |= SCF_FUA;
		cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
		cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
		cmd->execute_rw = ops->execute_rw;
		cmd->execute_rw = ops->execute_rw;
		cmd->execute_cmd = sbc_execute_rw;
		cmd->execute_cmd = sbc_execute_rw;
@@ -801,6 +836,9 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
			return TCM_INVALID_CDB_FIELD;
			return TCM_INVALID_CDB_FIELD;
		sectors = transport_get_sectors_10(cdb);
		sectors = transport_get_sectors_10(cdb);


		if (sbc_check_dpofua(dev, cmd, cdb))
			return TCM_INVALID_CDB_FIELD;

		cmd->t_task_lba = transport_lba_32(cdb);
		cmd->t_task_lba = transport_lba_32(cdb);
		cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
		cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;


@@ -810,8 +848,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
		cmd->execute_rw = ops->execute_rw;
		cmd->execute_rw = ops->execute_rw;
		cmd->execute_cmd = sbc_execute_rw;
		cmd->execute_cmd = sbc_execute_rw;
		cmd->transport_complete_callback = &xdreadwrite_callback;
		cmd->transport_complete_callback = &xdreadwrite_callback;
		if (cdb[1] & 0x8)
			cmd->se_cmd_flags |= SCF_FUA;
		break;
		break;
	case VARIABLE_LENGTH_CMD:
	case VARIABLE_LENGTH_CMD:
	{
	{
@@ -820,6 +856,8 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
		case XDWRITEREAD_32:
		case XDWRITEREAD_32:
			sectors = transport_get_sectors_32(cdb);
			sectors = transport_get_sectors_32(cdb);


			if (sbc_check_dpofua(dev, cmd, cdb))
				return TCM_INVALID_CDB_FIELD;
			/*
			/*
			 * Use WRITE_32 and READ_32 opcodes for the emulated
			 * Use WRITE_32 and READ_32 opcodes for the emulated
			 * XDWRITE_READ_32 logic.
			 * XDWRITE_READ_32 logic.
@@ -834,8 +872,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
			cmd->execute_rw = ops->execute_rw;
			cmd->execute_rw = ops->execute_rw;
			cmd->execute_cmd = sbc_execute_rw;
			cmd->execute_cmd = sbc_execute_rw;
			cmd->transport_complete_callback = &xdreadwrite_callback;
			cmd->transport_complete_callback = &xdreadwrite_callback;
			if (cdb[1] & 0x8)
				cmd->se_cmd_flags |= SCF_FUA;
			break;
			break;
		case WRITE_SAME_32:
		case WRITE_SAME_32:
			sectors = transport_get_sectors_32(cdb);
			sectors = transport_get_sectors_32(cdb);