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

Commit 5bda90c8 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Nicholas Bellinger
Browse files

target: use ->exectute_task for all CDB emulation



Instead of calling into transport_emulate_control_cdb from
__transport_execute_tasks for some CDBs always set up ->exectute_tasks
in the command sequence and use it uniformly.

(nab: Add default passthrough break for SERVICE_ACTION_IN)

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent d29a5b6a
Loading
Loading
Loading
Loading
+10 −101
Original line number Original line Diff line number Diff line
@@ -32,6 +32,7 @@
#include <target/target_core_transport.h>
#include <target/target_core_transport.h>
#include <target/target_core_fabric_ops.h>
#include <target/target_core_fabric_ops.h>
#include "target_core_ua.h"
#include "target_core_ua.h"
#include "target_core_cdb.h"


static void
static void
target_fill_alua_data(struct se_port *port, unsigned char *buf)
target_fill_alua_data(struct se_port *port, unsigned char *buf)
@@ -679,8 +680,7 @@ target_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf)
	return 0;
	return 0;
}
}


static int
int target_emulate_inquiry(struct se_task *task)
target_emulate_inquiry(struct se_task *task)
{
{
	struct se_cmd *cmd = task->task_se_cmd;
	struct se_cmd *cmd = task->task_se_cmd;
	struct se_device *dev = cmd->se_dev;
	struct se_device *dev = cmd->se_dev;
@@ -731,8 +731,7 @@ out:
	return ret;
	return ret;
}
}


static int
int target_emulate_readcapacity(struct se_task *task)
target_emulate_readcapacity(struct se_task *task)
{
{
	struct se_cmd *cmd = task->task_se_cmd;
	struct se_cmd *cmd = task->task_se_cmd;
	struct se_device *dev = cmd->se_dev;
	struct se_device *dev = cmd->se_dev;
@@ -768,8 +767,7 @@ target_emulate_readcapacity(struct se_task *task)
	return 0;
	return 0;
}
}


static int
int target_emulate_readcapacity_16(struct se_task *task)
target_emulate_readcapacity_16(struct se_task *task)
{
{
	struct se_cmd *cmd = task->task_se_cmd;
	struct se_cmd *cmd = task->task_se_cmd;
	struct se_device *dev = cmd->se_dev;
	struct se_device *dev = cmd->se_dev;
@@ -939,8 +937,7 @@ target_modesense_dpofua(unsigned char *buf, int type)
	}
	}
}
}


static int
int target_emulate_modesense(struct se_task *task)
target_emulate_modesense(struct se_task *task)
{
{
	struct se_cmd *cmd = task->task_se_cmd;
	struct se_cmd *cmd = task->task_se_cmd;
	struct se_device *dev = cmd->se_dev;
	struct se_device *dev = cmd->se_dev;
@@ -1019,8 +1016,7 @@ target_emulate_modesense(struct se_task *task)
	return 0;
	return 0;
}
}


static int
int target_emulate_request_sense(struct se_task *task)
target_emulate_request_sense(struct se_task *task)
{
{
	struct se_cmd *cmd = task->task_se_cmd;
	struct se_cmd *cmd = task->task_se_cmd;
	unsigned char *cdb = cmd->t_task_cdb;
	unsigned char *cdb = cmd->t_task_cdb;
@@ -1090,8 +1086,7 @@ end:
 * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support.
 * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support.
 * Note this is not used for TCM/pSCSI passthrough
 * Note this is not used for TCM/pSCSI passthrough
 */
 */
static int
int target_emulate_unmap(struct se_task *task)
target_emulate_unmap(struct se_task *task)
{
{
	struct se_cmd *cmd = task->task_se_cmd;
	struct se_cmd *cmd = task->task_se_cmd;
	struct se_device *dev = cmd->se_dev;
	struct se_device *dev = cmd->se_dev;
@@ -1150,8 +1145,7 @@ err:
 * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support.
 * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support.
 * Note this is not used for TCM/pSCSI passthrough
 * Note this is not used for TCM/pSCSI passthrough
 */
 */
static int
int target_emulate_write_same(struct se_task *task)
target_emulate_write_same(struct se_task *task)
{
{
	struct se_cmd *cmd = task->task_se_cmd;
	struct se_cmd *cmd = task->task_se_cmd;
	struct se_device *dev = cmd->se_dev;
	struct se_device *dev = cmd->se_dev;
@@ -1196,8 +1190,7 @@ target_emulate_write_same(struct se_task *task)
	return 0;
	return 0;
}
}


static int
int target_emulate_synchronize_cache(struct se_task *task)
target_emulate_synchronize_cache(struct se_task *task)
{
{
	struct se_device *dev = task->task_se_cmd->se_dev;
	struct se_device *dev = task->task_se_cmd->se_dev;


@@ -1211,97 +1204,13 @@ target_emulate_synchronize_cache(struct se_task *task)
	return 0;
	return 0;
}
}


static int
int target_emulate_noop(struct se_task *task)
target_emulate_noop(struct se_task *task)
{
{
	task->task_scsi_status = GOOD;
	task->task_scsi_status = GOOD;
	transport_complete_task(task, 1);
	transport_complete_task(task, 1);
	return 0;
	return 0;
}
}


int
transport_emulate_control_cdb(struct se_task *task)
{
	struct se_cmd *cmd = task->task_se_cmd;
	struct se_device *dev = cmd->se_dev;
	unsigned short service_action;
	int ret = 0;

	switch (cmd->t_task_cdb[0]) {
	case INQUIRY:
		ret = target_emulate_inquiry(task);
		break;
	case READ_CAPACITY:
		ret = target_emulate_readcapacity(task);
		break;
	case MODE_SENSE:
		ret = target_emulate_modesense(task);
		break;
	case MODE_SENSE_10:
		ret = target_emulate_modesense(task);
		break;
	case SERVICE_ACTION_IN:
		switch (cmd->t_task_cdb[1] & 0x1f) {
		case SAI_READ_CAPACITY_16:
			ret = target_emulate_readcapacity_16(task);
			break;
		default:
			pr_err("Unsupported SA: 0x%02x\n",
				cmd->t_task_cdb[1] & 0x1f);
			return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
		}
		break;
	case REQUEST_SENSE:
		ret = target_emulate_request_sense(task);
		break;
	case UNMAP:
		ret = target_emulate_unmap(task);
		break;
	case WRITE_SAME:
		ret = target_emulate_write_same(task);
		break;
	case WRITE_SAME_16:
		ret = target_emulate_write_same(task);
		break;
	case VARIABLE_LENGTH_CMD:
		service_action =
			get_unaligned_be16(&cmd->t_task_cdb[8]);
		switch (service_action) {
		case WRITE_SAME_32:
			ret = target_emulate_write_same(task);
			break;
		default:
			pr_err("Unsupported VARIABLE_LENGTH_CMD SA:"
					" 0x%02x\n", service_action);
			break;
		}
		break;
	case SYNCHRONIZE_CACHE:
	case 0x91: /* SYNCHRONIZE_CACHE_16: */
		ret = target_emulate_synchronize_cache(task);
		break;
	case ALLOW_MEDIUM_REMOVAL:
	case ERASE:
	case REZERO_UNIT:
	case SEEK_10:
	case SPACE:
	case START_STOP:
	case TEST_UNIT_READY:
	case VERIFY:
	case WRITE_FILEMARKS:
		ret = target_emulate_noop(task);
		break;
	default:
		pr_err("Unsupported SCSI Opcode: 0x%02x for %s\n",
			cmd->t_task_cdb[0], dev->transport->name);
		return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
	}

	if (ret < 0)
		return ret;
	return PYX_TRANSPORT_SENT_TO_TRANSPORT;
}

/*
/*
 * Write a CDB into @cdb that is based on the one the intiator sent us,
 * Write a CDB into @cdb that is based on the one the intiator sent us,
 * but updated to only cover the sectors that the current task handles.
 * but updated to only cover the sectors that the current task handles.
+14 −0
Original line number Original line Diff line number Diff line
#ifndef TARGET_CORE_CDB_H
#define TARGET_CORE_CDB_H

int target_emulate_inquiry(struct se_task *task);
int target_emulate_readcapacity(struct se_task *task);
int target_emulate_readcapacity_16(struct se_task *task);
int target_emulate_modesense(struct se_task *task);
int target_emulate_request_sense(struct se_task *task);
int target_emulate_unmap(struct se_task *task);
int target_emulate_write_same(struct se_task *task);
int target_emulate_synchronize_cache(struct se_task *task);
int target_emulate_noop(struct se_task *task);

#endif /* TARGET_CORE_CDB_H */
+73 −39
Original line number Original line Diff line number Diff line
@@ -52,6 +52,7 @@
#include <target/target_core_configfs.h>
#include <target/target_core_configfs.h>


#include "target_core_alua.h"
#include "target_core_alua.h"
#include "target_core_cdb.h"
#include "target_core_hba.h"
#include "target_core_hba.h"
#include "target_core_pr.h"
#include "target_core_pr.h"
#include "target_core_ua.h"
#include "target_core_ua.h"
@@ -2155,31 +2156,11 @@ check_depth:
		atomic_set(&cmd->t_transport_sent, 1);
		atomic_set(&cmd->t_transport_sent, 1);


	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
	/*

	 * The struct se_cmd->execute_task() function pointer is used
	if (cmd->execute_task)
	 * to grab REPORT_LUNS and other CDBs we want to handle before they hit the
	 * struct se_subsystem_api->do_task() caller below.
	 */
	if (cmd->execute_task) {
		error = cmd->execute_task(task);
		error = cmd->execute_task(task);
	} else {
		/*
		 * Currently for all virtual TCM plugins including IBLOCK, FILEIO and
		 * RAMDISK we use the internal transport_emulate_control_cdb() logic
		 * with struct se_subsystem_api callers for the primary SPC-3 TYPE_DISK
		 * LUN emulation code.
		 *
		 * For TCM/pSCSI and all other SCF_SCSI_DATA_SG_IO_CDB I/O tasks we
		 * call ->do_task() directly and let the underlying TCM subsystem plugin
		 * code handle the CDB emulation.
		 */
		if ((dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) &&
		    (!(task->task_se_cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB)))
			error = transport_emulate_control_cdb(task);
	else
	else
		error = dev->transport->do_task(task);
		error = dev->transport->do_task(task);
	}

	if (error != 0) {
	if (error != 0) {
		cmd->transport_error_status = error;
		cmd->transport_error_status = error;
		spin_lock_irqsave(&cmd->t_state_lock, flags);
		spin_lock_irqsave(&cmd->t_state_lock, flags);
@@ -2622,6 +2603,13 @@ static int transport_generic_cmd_sequencer(
		 */
		 */
	}
	}


	/*
	 * If we operate in passthrough mode we skip most CDB emulation and
	 * instead hand the commands down to the physical SCSI device.
	 */
	passthrough =
		(dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV);

	switch (cdb[0]) {
	switch (cdb[0]) {
	case READ_6:
	case READ_6:
		sectors = transport_get_sectors_6(cdb, cmd, &sector_ret);
		sectors = transport_get_sectors_6(cdb, cmd, &sector_ret);
@@ -2701,9 +2689,12 @@ static int transport_generic_cmd_sequencer(
		cmd->t_task_lba = transport_lba_32(cdb);
		cmd->t_task_lba = transport_lba_32(cdb);
		cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
		cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;


		if (dev->transport->transport_type ==
		/*
				TRANSPORT_PLUGIN_PHBA_PDEV)
		 * Do now allow BIDI commands for passthrough mode.
		 */
		if (passthrough)
			goto out_unsupported_cdb;
			goto out_unsupported_cdb;

		/*
		/*
		 * Setup BIDI XOR callback to be run after I/O completion.
		 * Setup BIDI XOR callback to be run after I/O completion.
		 */
		 */
@@ -2712,13 +2703,6 @@ static int transport_generic_cmd_sequencer(
		break;
		break;
	case VARIABLE_LENGTH_CMD:
	case VARIABLE_LENGTH_CMD:
		service_action = get_unaligned_be16(&cdb[8]);
		service_action = get_unaligned_be16(&cdb[8]);
		/*
		 * Determine if this is TCM/PSCSI device and we should disable
		 * internal emulation for this CDB.
		 */
		passthrough = (dev->transport->transport_type ==
					TRANSPORT_PLUGIN_PHBA_PDEV);

		switch (service_action) {
		switch (service_action) {
		case XDWRITEREAD_32:
		case XDWRITEREAD_32:
			sectors = transport_get_sectors_32(cdb, cmd, &sector_ret);
			sectors = transport_get_sectors_32(cdb, cmd, &sector_ret);
@@ -2732,8 +2716,12 @@ static int transport_generic_cmd_sequencer(
			cmd->t_task_lba = transport_lba_64_ext(cdb);
			cmd->t_task_lba = transport_lba_64_ext(cdb);
			cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
			cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;


			/*
			 * Do now allow BIDI commands for passthrough mode.
			 */
			if (passthrough)
			if (passthrough)
				goto out_unsupported_cdb;
				goto out_unsupported_cdb;

			/*
			/*
			 * Setup BIDI XOR callback to be run during after I/O
			 * Setup BIDI XOR callback to be run during after I/O
			 * completion.
			 * completion.
@@ -2759,7 +2747,8 @@ static int transport_generic_cmd_sequencer(


			if (target_check_write_same_discard(&cdb[10], dev) < 0)
			if (target_check_write_same_discard(&cdb[10], dev) < 0)
				goto out_invalid_cdb_field;
				goto out_invalid_cdb_field;

			if (!passthrough)
				cmd->execute_task = target_emulate_write_same;
			break;
			break;
		default:
		default:
			pr_err("VARIABLE_LENGTH_CMD service action"
			pr_err("VARIABLE_LENGTH_CMD service action"
@@ -2797,8 +2786,15 @@ static int transport_generic_cmd_sequencer(
	case MODE_SENSE:
	case MODE_SENSE:
		size = cdb[4];
		size = cdb[4];
		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
		if (!passthrough)
			cmd->execute_task = target_emulate_modesense;
		break;
		break;
	case MODE_SENSE_10:
	case MODE_SENSE_10:
		size = (cdb[7] << 8) + cdb[8];
		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
		if (!passthrough)
			cmd->execute_task = target_emulate_modesense;
		break;
	case GPCMD_READ_BUFFER_CAPACITY:
	case GPCMD_READ_BUFFER_CAPACITY:
	case GPCMD_SEND_OPC:
	case GPCMD_SEND_OPC:
	case LOG_SELECT:
	case LOG_SELECT:
@@ -2867,6 +2863,8 @@ static int transport_generic_cmd_sequencer(
		if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
		if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
			cmd->sam_task_attr = MSG_HEAD_TAG;
			cmd->sam_task_attr = MSG_HEAD_TAG;
		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
		if (!passthrough)
			cmd->execute_task = target_emulate_inquiry;
		break;
		break;
	case READ_BUFFER:
	case READ_BUFFER:
		size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8];
		size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8];
@@ -2875,6 +2873,8 @@ static int transport_generic_cmd_sequencer(
	case READ_CAPACITY:
	case READ_CAPACITY:
		size = READ_CAP_LEN;
		size = READ_CAP_LEN;
		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
		if (!passthrough)
			cmd->execute_task = target_emulate_readcapacity;
		break;
		break;
	case READ_MEDIA_SERIAL_NUMBER:
	case READ_MEDIA_SERIAL_NUMBER:
	case SECURITY_PROTOCOL_IN:
	case SECURITY_PROTOCOL_IN:
@@ -2883,6 +2883,21 @@ static int transport_generic_cmd_sequencer(
		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
		break;
		break;
	case SERVICE_ACTION_IN:
	case SERVICE_ACTION_IN:
		switch (cmd->t_task_cdb[1] & 0x1f) {
		case SAI_READ_CAPACITY_16:
			if (!passthrough)
				cmd->execute_task =
					target_emulate_readcapacity_16;
			break;
		default:
			if (passthrough)
				break;

			pr_err("Unsupported SA: 0x%02x\n",
				cmd->t_task_cdb[1] & 0x1f);
			goto out_unsupported_cdb;
		}
		/*FALLTHROUGH*/
	case ACCESS_CONTROL_IN:
	case ACCESS_CONTROL_IN:
	case ACCESS_CONTROL_OUT:
	case ACCESS_CONTROL_OUT:
	case EXTENDED_COPY:
	case EXTENDED_COPY:
@@ -2913,6 +2928,8 @@ static int transport_generic_cmd_sequencer(
	case REQUEST_SENSE:
	case REQUEST_SENSE:
		size = cdb[4];
		size = cdb[4];
		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
		if (!passthrough)
			cmd->execute_task = target_emulate_request_sense;
		break;
		break;
	case READ_ELEMENT_STATUS:
	case READ_ELEMENT_STATUS:
		size = 65536 * cdb[7] + 256 * cdb[8] + cdb[9];
		size = 65536 * cdb[7] + 256 * cdb[8] + cdb[9];
@@ -2977,8 +2994,9 @@ static int transport_generic_cmd_sequencer(
		size = transport_get_size(sectors, cdb, cmd);
		size = transport_get_size(sectors, cdb, cmd);
		cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
		cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;


		if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV)
		if (passthrough)
			break;
			break;

		/*
		/*
		 * Check to ensure that LBA + Range does not exceed past end of
		 * Check to ensure that LBA + Range does not exceed past end of
		 * device for IBLOCK and FILEIO ->do_sync_cache() backend calls
		 * device for IBLOCK and FILEIO ->do_sync_cache() backend calls
@@ -2987,10 +3005,13 @@ static int transport_generic_cmd_sequencer(
			if (transport_cmd_get_valid_sectors(cmd) < 0)
			if (transport_cmd_get_valid_sectors(cmd) < 0)
				goto out_invalid_cdb_field;
				goto out_invalid_cdb_field;
		}
		}
		cmd->execute_task = target_emulate_synchronize_cache;
		break;
		break;
	case UNMAP:
	case UNMAP:
		size = get_unaligned_be16(&cdb[7]);
		size = get_unaligned_be16(&cdb[7]);
		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
		cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
		if (!passthrough)
			cmd->execute_task = target_emulate_unmap;
		break;
		break;
	case WRITE_SAME_16:
	case WRITE_SAME_16:
		sectors = transport_get_sectors_16(cdb, cmd, &sector_ret);
		sectors = transport_get_sectors_16(cdb, cmd, &sector_ret);
@@ -3009,6 +3030,8 @@ static int transport_generic_cmd_sequencer(


		if (target_check_write_same_discard(&cdb[1], dev) < 0)
		if (target_check_write_same_discard(&cdb[1], dev) < 0)
			goto out_invalid_cdb_field;
			goto out_invalid_cdb_field;
		if (!passthrough)
			cmd->execute_task = target_emulate_write_same;
		break;
		break;
	case WRITE_SAME:
	case WRITE_SAME:
		sectors = transport_get_sectors_10(cdb, cmd, &sector_ret);
		sectors = transport_get_sectors_10(cdb, cmd, &sector_ret);
@@ -3030,20 +3053,26 @@ static int transport_generic_cmd_sequencer(
		 */
		 */
		if (target_check_write_same_discard(&cdb[1], dev) < 0)
		if (target_check_write_same_discard(&cdb[1], dev) < 0)
			goto out_invalid_cdb_field;
			goto out_invalid_cdb_field;
		if (!passthrough)
			cmd->execute_task = target_emulate_write_same;
		break;
		break;
	case ALLOW_MEDIUM_REMOVAL:
	case ALLOW_MEDIUM_REMOVAL:
	case GPCMD_CLOSE_TRACK:
	case ERASE:
	case ERASE:
	case INITIALIZE_ELEMENT_STATUS:
	case GPCMD_LOAD_UNLOAD:
	case REZERO_UNIT:
	case REZERO_UNIT:
	case SEEK_10:
	case SEEK_10:
	case GPCMD_SET_SPEED:
	case SPACE:
	case SPACE:
	case START_STOP:
	case START_STOP:
	case TEST_UNIT_READY:
	case TEST_UNIT_READY:
	case VERIFY:
	case VERIFY:
	case WRITE_FILEMARKS:
	case WRITE_FILEMARKS:
		cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
		if (!passthrough)
			cmd->execute_task = target_emulate_noop;
		break;
	case GPCMD_CLOSE_TRACK:
	case INITIALIZE_ELEMENT_STATUS:
	case GPCMD_LOAD_UNLOAD:
	case GPCMD_SET_SPEED:
	case MOVE_MEDIUM:
	case MOVE_MEDIUM:
		cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
		cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
		break;
		break;
@@ -3100,6 +3129,11 @@ static int transport_generic_cmd_sequencer(
		cmd->data_length = size;
		cmd->data_length = size;
	}
	}


	/* reject any command that we don't have a handler for */
	if (!(passthrough || cmd->execute_task ||
	     (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB)))
		goto out_unsupported_cdb;

	/* Let's limit control cdbs to a page, for simplicity's sake. */
	/* Let's limit control cdbs to a page, for simplicity's sake. */
	if ((cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) &&
	if ((cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) &&
	    size > PAGE_SIZE)
	    size > PAGE_SIZE)