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

Commit 7bfea53b authored by Andy Grover's avatar Andy Grover Committed by Nicholas Bellinger
Browse files

target: Move passthrough CDB parsing into a common function



Aside from whether they handle BIDI ops or not, parsing of the CDB by
kernel and user SCSI passthrough modules should be identical. Move this
into a new passthrough_parse_cdb() and call it from tcm-pscsi and tcm-user.

Reported-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarIlias Tsitsimpis <iliastsi@arrikto.com>
Signed-off-by: default avatarAndy Grover <agrover@redhat.com>
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent 9c1cd1b6
Loading
Loading
Loading
Loading
+74 −0
Original line number Original line Diff line number Diff line
@@ -33,6 +33,7 @@
#include <linux/kthread.h>
#include <linux/kthread.h>
#include <linux/in.h>
#include <linux/in.h>
#include <linux/export.h>
#include <linux/export.h>
#include <asm/unaligned.h>
#include <net/sock.h>
#include <net/sock.h>
#include <net/tcp.h>
#include <net/tcp.h>
#include <scsi/scsi.h>
#include <scsi/scsi.h>
@@ -1707,3 +1708,76 @@ void core_dev_release_virtual_lun0(void)
		target_free_device(g_lun0_dev);
		target_free_device(g_lun0_dev);
	core_delete_hba(hba);
	core_delete_hba(hba);
}
}

/*
 * Common CDB parsing for kernel and user passthrough.
 */
sense_reason_t
passthrough_parse_cdb(struct se_cmd *cmd,
	sense_reason_t (*exec_cmd)(struct se_cmd *cmd))
{
	unsigned char *cdb = cmd->t_task_cdb;

	/*
	 * Clear a lun set in the cdb if the initiator talking to use spoke
	 * and old standards version, as we can't assume the underlying device
	 * won't choke up on it.
	 */
	switch (cdb[0]) {
	case READ_10: /* SBC - RDProtect */
	case READ_12: /* SBC - RDProtect */
	case READ_16: /* SBC - RDProtect */
	case SEND_DIAGNOSTIC: /* SPC - SELF-TEST Code */
	case VERIFY: /* SBC - VRProtect */
	case VERIFY_16: /* SBC - VRProtect */
	case WRITE_VERIFY: /* SBC - VRProtect */
	case WRITE_VERIFY_12: /* SBC - VRProtect */
	case MAINTENANCE_IN: /* SPC - Parameter Data Format for SA RTPG */
		break;
	default:
		cdb[1] &= 0x1f; /* clear logical unit number */
		break;
	}

	/*
	 * For REPORT LUNS we always need to emulate the response, for everything
	 * else, pass it up.
	 */
	if (cdb[0] == REPORT_LUNS) {
		cmd->execute_cmd = spc_emulate_report_luns;
		return TCM_NO_SENSE;
	}

	/* Set DATA_CDB flag for ops that should have it */
	switch (cdb[0]) {
	case READ_6:
	case READ_10:
	case READ_12:
	case READ_16:
	case WRITE_6:
	case WRITE_10:
	case WRITE_12:
	case WRITE_16:
	case WRITE_VERIFY:
	case WRITE_VERIFY_12:
	case 0x8e: /* WRITE_VERIFY_16 */
	case COMPARE_AND_WRITE:
	case XDWRITEREAD_10:
		cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
		break;
	case VARIABLE_LENGTH_CMD:
		switch (get_unaligned_be16(&cdb[8])) {
		case READ_32:
		case WRITE_32:
		case 0x0c: /* WRITE_VERIFY_32 */
		case XDWRITEREAD_32:
			cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
			break;
		}
	}

	cmd->execute_cmd = exec_cmd;

	return TCM_NO_SENSE;
}
EXPORT_SYMBOL(passthrough_parse_cdb);
+1 −52
Original line number Original line Diff line number Diff line
@@ -973,64 +973,13 @@ fail:
	return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
	return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
}
}


/*
 * Clear a lun set in the cdb if the initiator talking to use spoke
 * and old standards version, as we can't assume the underlying device
 * won't choke up on it.
 */
static inline void pscsi_clear_cdb_lun(unsigned char *cdb)
{
	switch (cdb[0]) {
	case READ_10: /* SBC - RDProtect */
	case READ_12: /* SBC - RDProtect */
	case READ_16: /* SBC - RDProtect */
	case SEND_DIAGNOSTIC: /* SPC - SELF-TEST Code */
	case VERIFY: /* SBC - VRProtect */
	case VERIFY_16: /* SBC - VRProtect */
	case WRITE_VERIFY: /* SBC - VRProtect */
	case WRITE_VERIFY_12: /* SBC - VRProtect */
	case MAINTENANCE_IN: /* SPC - Parameter Data Format for SA RTPG */
		break;
	default:
		cdb[1] &= 0x1f; /* clear logical unit number */
		break;
	}
}

static sense_reason_t
static sense_reason_t
pscsi_parse_cdb(struct se_cmd *cmd)
pscsi_parse_cdb(struct se_cmd *cmd)
{
{
	unsigned char *cdb = cmd->t_task_cdb;

	if (cmd->se_cmd_flags & SCF_BIDI)
	if (cmd->se_cmd_flags & SCF_BIDI)
		return TCM_UNSUPPORTED_SCSI_OPCODE;
		return TCM_UNSUPPORTED_SCSI_OPCODE;


	pscsi_clear_cdb_lun(cdb);
	return passthrough_parse_cdb(cmd, pscsi_execute_cmd);

	/*
	 * For REPORT LUNS we always need to emulate the response, for everything
	 * else the default for pSCSI is to pass the command to the underlying
	 * LLD / physical hardware.
	 */
	switch (cdb[0]) {
	case REPORT_LUNS:
		cmd->execute_cmd = spc_emulate_report_luns;
		return 0;
	case READ_6:
	case READ_10:
	case READ_12:
	case READ_16:
	case WRITE_6:
	case WRITE_10:
	case WRITE_12:
	case WRITE_16:
	case WRITE_VERIFY:
		cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
		/* FALLTHROUGH*/
	default:
		cmd->execute_cmd = pscsi_execute_cmd;
		return 0;
	}
}
}


static sense_reason_t
static sense_reason_t
+1 −42
Original line number Original line Diff line number Diff line
@@ -1049,48 +1049,7 @@ tcmu_pass_op(struct se_cmd *se_cmd)
static sense_reason_t
static sense_reason_t
tcmu_parse_cdb(struct se_cmd *cmd)
tcmu_parse_cdb(struct se_cmd *cmd)
{
{
	unsigned char *cdb = cmd->t_task_cdb;
	return passthrough_parse_cdb(cmd, tcmu_pass_op);

	/*
	 * For REPORT LUNS we always need to emulate the response, for everything
	 * else, pass it up.
	 */
	if (cdb[0] == REPORT_LUNS) {
		cmd->execute_cmd = spc_emulate_report_luns;
		return TCM_NO_SENSE;
	}

	/* Set DATA_CDB flag for ops that should have it */
	switch (cdb[0]) {
	case READ_6:
	case READ_10:
	case READ_12:
	case READ_16:
	case WRITE_6:
	case WRITE_10:
	case WRITE_12:
	case WRITE_16:
	case WRITE_VERIFY:
	case WRITE_VERIFY_12:
	case 0x8e: /* WRITE_VERIFY_16 */
	case COMPARE_AND_WRITE:
	case XDWRITEREAD_10:
		cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
		break;
	case VARIABLE_LENGTH_CMD:
		switch (get_unaligned_be16(&cdb[8])) {
		case READ_32:
		case WRITE_32:
		case 0x0c: /* WRITE_VERIFY_32 */
		case XDWRITEREAD_32:
			cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
			break;
		}
	}

	cmd->execute_cmd = tcmu_pass_op;

	return TCM_NO_SENSE;
}
}


DEF_TB_DEV_ATTRIB_RO(tcmu, hw_pi_prot_type);
DEF_TB_DEV_ATTRIB_RO(tcmu, hw_pi_prot_type);
+2 −0
Original line number Original line Diff line number Diff line
@@ -138,5 +138,7 @@ int se_dev_set_queue_depth(struct se_device *, u32);
int	se_dev_set_max_sectors(struct se_device *, u32);
int	se_dev_set_max_sectors(struct se_device *, u32);
int	se_dev_set_optimal_sectors(struct se_device *, u32);
int	se_dev_set_optimal_sectors(struct se_device *, u32);
int	se_dev_set_block_size(struct se_device *, u32);
int	se_dev_set_block_size(struct se_device *, u32);
sense_reason_t passthrough_parse_cdb(struct se_cmd *cmd,
	sense_reason_t (*exec_cmd)(struct se_cmd *cmd));


#endif /* TARGET_CORE_BACKEND_H */
#endif /* TARGET_CORE_BACKEND_H */