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

Commit 6aad3738 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending:
  target: use ->exectute_task for all CDB emulation
  target: remove SCF_EMULATE_CDB_ASYNC
  target: refactor transport_emulate_control_cdb
  target: pass the se_task to the CDB emulation callback
  target: split core_scsi3_emulate_pr
  target: split core_scsi2_emulate_crh
  target: Add generic active I/O shutdown logic
  target: add back error handling in transport_complete_task
  target/pscsi: blk_make_request() returns an ERR_PTR()
  target: Remove core TRANSPORT_FREE_CMD_INTR usage
  target: Make TFO->check_stop_free return free status
  iscsi-target: Fix non-immediate TMR handling
  iscsi-target: Add missing CMDSN_LOWER_THAN_EXP check in iscsit_handle_scsi_cmd
  target: Avoid double list_del for aborted se_tmr_req
  target: Minor cleanups to core_tmr_drain_tmr_list
  target: Fix wrong se_tmr being added to drain_tmr_list
  target: Fix incorrect se_cmd assignment in core_tmr_drain_tmr_list
  target: Check -ENOMEM to signal QUEUE_FULL from fabric callbacks
  tcm_loop: Add explict read buffer memset for SCF_SCSI_CONTROL_SG_IO_CDB
  target: Fix compile warning w/ missing module.h include
parents 02ebbbd4 5bda90c8
Loading
Loading
Loading
Loading
+6 −5
Original line number Diff line number Diff line
@@ -1079,7 +1079,9 @@ static int iscsit_handle_scsi_cmd(
	 */
	if (!cmd->immediate_data) {
		cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
		if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
		if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
			return 0;
		else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
			return iscsit_add_reject_from_cmd(
				ISCSI_REASON_PROTOCOL_ERROR,
				1, 0, buf, cmd);
@@ -1819,17 +1821,16 @@ static int iscsit_handle_task_mgt_cmd(
		int cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
		if (cmdsn_ret == CMDSN_HIGHER_THAN_EXP)
			out_of_order_cmdsn = 1;
		else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
		else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
			return 0;
		} else { /* (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) */
		else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
			return iscsit_add_reject_from_cmd(
					ISCSI_REASON_PROTOCOL_ERROR,
					1, 0, buf, cmd);
	}
	}
	iscsit_ack_from_expstatsn(conn, hdr->exp_statsn);

	if (out_of_order_cmdsn)
	if (out_of_order_cmdsn || !(hdr->opcode & ISCSI_OP_IMMEDIATE))
		return 0;
	/*
	 * Found the referenced task, send to transport for processing.
+21 −2
Original line number Diff line number Diff line
@@ -174,6 +174,24 @@ static int tcm_loop_new_cmd_map(struct se_cmd *se_cmd)
		sgl_bidi = sdb->table.sgl;
		sgl_bidi_count = sdb->table.nents;
	}
	/*
	 * Because some userspace code via scsi-generic do not memset their
	 * associated read buffers, go ahead and do that here for type
	 * SCF_SCSI_CONTROL_SG_IO_CDB.  Also note that this is currently
	 * guaranteed to be a single SGL for SCF_SCSI_CONTROL_SG_IO_CDB
	 * by target core in transport_generic_allocate_tasks() ->
	 * transport_generic_cmd_sequencer().
	 */
	if (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB &&
	    se_cmd->data_direction == DMA_FROM_DEVICE) {
		struct scatterlist *sg = scsi_sglist(sc);
		unsigned char *buf = kmap(sg_page(sg)) + sg->offset;

		if (buf != NULL) {
			memset(buf, 0, sg->length);
			kunmap(sg_page(sg));
		}
	}

	/* Tell the core about our preallocated memory */
	ret = transport_generic_map_mem_to_cmd(se_cmd, scsi_sglist(sc),
@@ -187,7 +205,7 @@ static int tcm_loop_new_cmd_map(struct se_cmd *se_cmd)
/*
 * Called from struct target_core_fabric_ops->check_stop_free()
 */
static void tcm_loop_check_stop_free(struct se_cmd *se_cmd)
static int tcm_loop_check_stop_free(struct se_cmd *se_cmd)
{
	/*
	 * Do not release struct se_cmd's containing a valid TMR
@@ -195,12 +213,13 @@ static void tcm_loop_check_stop_free(struct se_cmd *se_cmd)
	 * with transport_generic_free_cmd().
	 */
	if (se_cmd->se_tmr_req)
		return;
		return 0;
	/*
	 * Release the struct se_cmd, which will make a callback to release
	 * struct tcm_loop_cmd * in tcm_loop_deallocate_core_cmd()
	 */
	transport_generic_free_cmd(se_cmd, 0);
	return 1;
}

static void tcm_loop_release_cmd(struct se_cmd *se_cmd)
+8 −3
Original line number Diff line number Diff line
@@ -58,8 +58,9 @@ struct t10_alua_lu_gp *default_lu_gp;
 *
 * See spc4r17 section 6.27
 */
int core_emulate_report_target_port_groups(struct se_cmd *cmd)
int target_emulate_report_target_port_groups(struct se_task *task)
{
	struct se_cmd *cmd = task->task_se_cmd;
	struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev;
	struct se_port *port;
	struct t10_alua_tg_pt_gp *tg_pt_gp;
@@ -164,6 +165,8 @@ int core_emulate_report_target_port_groups(struct se_cmd *cmd)

	transport_kunmap_first_data_page(cmd);

	task->task_scsi_status = GOOD;
	transport_complete_task(task, 1);
	return 0;
}

@@ -172,8 +175,9 @@ int core_emulate_report_target_port_groups(struct se_cmd *cmd)
 *
 * See spc4r17 section 6.35
 */
int core_emulate_set_target_port_groups(struct se_cmd *cmd)
int target_emulate_set_target_port_groups(struct se_task *task)
{
	struct se_cmd *cmd = task->task_se_cmd;
	struct se_device *dev = cmd->se_dev;
	struct se_subsystem_dev *su_dev = dev->se_sub_dev;
	struct se_port *port, *l_port = cmd->se_lun->lun_sep;
@@ -341,7 +345,8 @@ int core_emulate_set_target_port_groups(struct se_cmd *cmd)

out:
	transport_kunmap_first_data_page(cmd);

	task->task_scsi_status = GOOD;
	transport_complete_task(task, 1);
	return 0;
}

+2 −2
Original line number Diff line number Diff line
@@ -66,8 +66,8 @@ extern struct kmem_cache *t10_alua_lu_gp_mem_cache;
extern struct kmem_cache *t10_alua_tg_pt_gp_cache;
extern struct kmem_cache *t10_alua_tg_pt_gp_mem_cache;

extern int core_emulate_report_target_port_groups(struct se_cmd *);
extern int core_emulate_set_target_port_groups(struct se_cmd *);
extern int target_emulate_report_target_port_groups(struct se_task *);
extern int target_emulate_set_target_port_groups(struct se_task *);
extern int core_alua_check_nonop_delay(struct se_cmd *);
extern int core_alua_do_port_transition(struct t10_alua_tg_pt_gp *,
				struct se_device *, struct se_port *,
+80 −136
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@
#include <target/target_core_transport.h>
#include <target/target_core_fabric_ops.h>
#include "target_core_ua.h"
#include "target_core_cdb.h"

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

static int
target_emulate_inquiry(struct se_cmd *cmd)
int target_emulate_inquiry(struct se_task *task)
{
	struct se_cmd *cmd = task->task_se_cmd;
	struct se_device *dev = cmd->se_dev;
	unsigned char *buf;
	unsigned char *cdb = cmd->t_task_cdb;
	int p, ret;

	if (!(cdb[1] & 0x1))
		return target_emulate_inquiry_std(cmd);
	if (!(cdb[1] & 0x1)) {
		ret = target_emulate_inquiry_std(cmd);
		goto out;
	}

	/*
	 * Make sure we at least have 4 bytes of INQUIRY response
@@ -707,22 +710,30 @@ target_emulate_inquiry(struct se_cmd *cmd)

	buf[0] = dev->transport->get_device_type(dev);

	for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p)
	for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p) {
		if (cdb[2] == evpd_handlers[p].page) {
			buf[1] = cdb[2];
			ret = evpd_handlers[p].emulate(cmd, buf);
			transport_kunmap_first_data_page(cmd);
			return ret;
			goto out_unmap;
		}
	}

	transport_kunmap_first_data_page(cmd);
	pr_err("Unknown VPD Code: 0x%02x\n", cdb[2]);
	return -EINVAL;
	ret = -EINVAL;

out_unmap:
	transport_kunmap_first_data_page(cmd);
out:
	if (!ret) {
		task->task_scsi_status = GOOD;
		transport_complete_task(task, 1);
	}
	return ret;
}

static int
target_emulate_readcapacity(struct se_cmd *cmd)
int target_emulate_readcapacity(struct se_task *task)
{
	struct se_cmd *cmd = task->task_se_cmd;
	struct se_device *dev = cmd->se_dev;
	unsigned char *buf;
	unsigned long long blocks_long = dev->transport->get_blocks(dev);
@@ -751,12 +762,14 @@ target_emulate_readcapacity(struct se_cmd *cmd)

	transport_kunmap_first_data_page(cmd);

	task->task_scsi_status = GOOD;
	transport_complete_task(task, 1);
	return 0;
}

static int
target_emulate_readcapacity_16(struct se_cmd *cmd)
int target_emulate_readcapacity_16(struct se_task *task)
{
	struct se_cmd *cmd = task->task_se_cmd;
	struct se_device *dev = cmd->se_dev;
	unsigned char *buf;
	unsigned long long blocks = dev->transport->get_blocks(dev);
@@ -784,6 +797,8 @@ target_emulate_readcapacity_16(struct se_cmd *cmd)

	transport_kunmap_first_data_page(cmd);

	task->task_scsi_status = GOOD;
	transport_complete_task(task, 1);
	return 0;
}

@@ -922,14 +937,15 @@ target_modesense_dpofua(unsigned char *buf, int type)
	}
}

static int
target_emulate_modesense(struct se_cmd *cmd, int ten)
int target_emulate_modesense(struct se_task *task)
{
	struct se_cmd *cmd = task->task_se_cmd;
	struct se_device *dev = cmd->se_dev;
	char *cdb = cmd->t_task_cdb;
	unsigned char *rbuf;
	int type = dev->transport->get_device_type(dev);
	int offset = (ten) ? 8 : 4;
	int ten = (cmd->t_task_cdb[0] == MODE_SENSE_10);
	int offset = ten ? 8 : 4;
	int length = 0;
	unsigned char buf[SE_MODE_PAGE_BUF];

@@ -995,12 +1011,14 @@ target_emulate_modesense(struct se_cmd *cmd, int ten)
	memcpy(rbuf, buf, offset);
	transport_kunmap_first_data_page(cmd);

	task->task_scsi_status = GOOD;
	transport_complete_task(task, 1);
	return 0;
}

static int
target_emulate_request_sense(struct se_cmd *cmd)
int target_emulate_request_sense(struct se_task *task)
{
	struct se_cmd *cmd = task->task_se_cmd;
	unsigned char *cdb = cmd->t_task_cdb;
	unsigned char *buf;
	u8 ua_asc = 0, ua_ascq = 0;
@@ -1059,7 +1077,8 @@ target_emulate_request_sense(struct se_cmd *cmd)

end:
	transport_kunmap_first_data_page(cmd);

	task->task_scsi_status = GOOD;
	transport_complete_task(task, 1);
	return 0;
}

@@ -1067,8 +1086,7 @@ target_emulate_request_sense(struct se_cmd *cmd)
 * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support.
 * Note this is not used for TCM/pSCSI passthrough
 */
static int
target_emulate_unmap(struct se_task *task)
int target_emulate_unmap(struct se_task *task)
{
	struct se_cmd *cmd = task->task_se_cmd;
	struct se_device *dev = cmd->se_dev;
@@ -1079,6 +1097,12 @@ target_emulate_unmap(struct se_task *task)
	int ret = 0, offset;
	unsigned short dl, bd_dl;

	if (!dev->transport->do_discard) {
		pr_err("UNMAP emulation not supported for: %s\n",
				dev->transport->name);
		return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
	}

	/* First UNMAP block descriptor starts at 8 byte offset */
	offset = 8;
	size -= 8;
@@ -1110,7 +1134,10 @@ target_emulate_unmap(struct se_task *task)

err:
	transport_kunmap_first_data_page(cmd);

	if (!ret) {
		task->task_scsi_status = GOOD;
		transport_complete_task(task, 1);
	}
	return ret;
}

@@ -1118,14 +1145,28 @@ target_emulate_unmap(struct se_task *task)
 * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support.
 * Note this is not used for TCM/pSCSI passthrough
 */
static int
target_emulate_write_same(struct se_task *task, u32 num_blocks)
int target_emulate_write_same(struct se_task *task)
{
	struct se_cmd *cmd = task->task_se_cmd;
	struct se_device *dev = cmd->se_dev;
	sector_t range;
	sector_t lba = cmd->t_task_lba;
	u32 num_blocks;
	int ret;

	if (!dev->transport->do_discard) {
		pr_err("WRITE_SAME emulation not supported"
				" for: %s\n", dev->transport->name);
		return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
	}

	if (cmd->t_task_cdb[0] == WRITE_SAME)
		num_blocks = get_unaligned_be16(&cmd->t_task_cdb[7]);
	else if (cmd->t_task_cdb[0] == WRITE_SAME_16)
		num_blocks = get_unaligned_be32(&cmd->t_task_cdb[10]);
	else /* WRITE_SAME_32 via VARIABLE_LENGTH_CMD */
		num_blocks = get_unaligned_be32(&cmd->t_task_cdb[28]);

	/*
	 * Use the explicit range when non zero is supplied, otherwise calculate
	 * the remaining range based on ->get_blocks() - starting LBA.
@@ -1144,127 +1185,30 @@ target_emulate_write_same(struct se_task *task, u32 num_blocks)
		return ret;
	}

	task->task_scsi_status = GOOD;
	transport_complete_task(task, 1);
	return 0;
}

int
transport_emulate_control_cdb(struct se_task *task)
int target_emulate_synchronize_cache(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;
	struct se_device *dev = task->task_se_cmd->se_dev;

	switch (cmd->t_task_cdb[0]) {
	case INQUIRY:
		ret = target_emulate_inquiry(cmd);
		break;
	case READ_CAPACITY:
		ret = target_emulate_readcapacity(cmd);
		break;
	case MODE_SENSE:
		ret = target_emulate_modesense(cmd, 0);
		break;
	case MODE_SENSE_10:
		ret = target_emulate_modesense(cmd, 1);
		break;
	case SERVICE_ACTION_IN:
		switch (cmd->t_task_cdb[1] & 0x1f) {
		case SAI_READ_CAPACITY_16:
			ret = target_emulate_readcapacity_16(cmd);
			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(cmd);
		break;
	case UNMAP:
		if (!dev->transport->do_discard) {
			pr_err("UNMAP emulation not supported for: %s\n",
					dev->transport->name);
			return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
		}
		ret = target_emulate_unmap(task);
		break;
	case WRITE_SAME:
		if (!dev->transport->do_discard) {
			pr_err("WRITE_SAME emulation not supported"
					" for: %s\n", dev->transport->name);
			return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
		}
		ret = target_emulate_write_same(task,
				get_unaligned_be16(&cmd->t_task_cdb[7]));
		break;
	case WRITE_SAME_16:
		if (!dev->transport->do_discard) {
			pr_err("WRITE_SAME_16 emulation not supported"
					" for: %s\n", dev->transport->name);
			return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
		}
		ret = target_emulate_write_same(task,
				get_unaligned_be32(&cmd->t_task_cdb[10]));
		break;
	case VARIABLE_LENGTH_CMD:
		service_action =
			get_unaligned_be16(&cmd->t_task_cdb[8]);
		switch (service_action) {
		case WRITE_SAME_32:
			if (!dev->transport->do_discard) {
				pr_err("WRITE_SAME_32 SA emulation not"
					" supported for: %s\n",
					dev->transport->name);
				return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
			}
			ret = target_emulate_write_same(task,
				get_unaligned_be32(&cmd->t_task_cdb[28]));
			break;
		default:
			pr_err("Unsupported VARIABLE_LENGTH_CMD SA:"
					" 0x%02x\n", service_action);
			break;
		}
		break;
	case SYNCHRONIZE_CACHE:
	case 0x91: /* SYNCHRONIZE_CACHE_16: */
	if (!dev->transport->do_sync_cache) {
		pr_err("SYNCHRONIZE_CACHE emulation not supported"
			" for: %s\n", dev->transport->name);
		return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
	}

	dev->transport->do_sync_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:
		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;
	return 0;
}

	if (ret < 0)
		return ret;
	/*
	 * Handle the successful completion here unless a caller
	 * has explictly requested an asychronous completion.
	 */
	if (!(cmd->se_cmd_flags & SCF_EMULATE_CDB_ASYNC)) {
int target_emulate_noop(struct se_task *task)
{
	task->task_scsi_status = GOOD;
	transport_complete_task(task, 1);
	}

	return PYX_TRANSPORT_SENT_TO_TRANSPORT;
	return 0;
}

/*
Loading