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

Commit cb38b453 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'scsi-target-for-v4.10' of...

Merge branch 'scsi-target-for-v4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/bvanassche/linux

Pull scsi target fixes from Bart Van Assche:

 - a series of bug fixes for the XCOPY implementation from David
   Disseldorp

 - one bug fix for the ibmvscsis driver, a driver that is used for
   communication between partitions on IBM POWER systems.

* 'scsi-target-for-v4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/bvanassche/linux:
  ibmvscsis: Fix srp_transfer_data fail return code
  target: support XCOPY requests without parameters
  target: check for XCOPY parameter truncation
  target: use XCOPY segment descriptor CSCD IDs
  target: check XCOPY segment descriptor CSCD IDs
  target: simplify XCOPY wwn->se_dev lookup helper
  target: return UNSUPPORTED TARGET/SEGMENT DESC TYPE CODE sense
  target: bounds check XCOPY total descriptor list length
  target: bounds check XCOPY segment descriptor list
  target: use XCOPY TOO MANY TARGET DESCRIPTORS sense
  target: add XCOPY target/segment desc sense codes
parents 607ae5f2 7c9d8d0c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -3585,7 +3585,7 @@ static int ibmvscsis_write_pending(struct se_cmd *se_cmd)
			       1, 1);
	if (rc) {
		pr_err("srp_transfer_data() failed: %d\n", rc);
		return -EAGAIN;
		return -EIO;
	}
	/*
	 * We now tell TCM to add this WRITE CDB directly into the TCM storage
+24 −0
Original line number Diff line number Diff line
@@ -1693,6 +1693,10 @@ void transport_generic_request_failure(struct se_cmd *cmd,
	case TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED:
	case TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED:
	case TCM_COPY_TARGET_DEVICE_NOT_REACHABLE:
	case TCM_TOO_MANY_TARGET_DESCS:
	case TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE:
	case TCM_TOO_MANY_SEGMENT_DESCS:
	case TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE:
		break;
	case TCM_OUT_OF_RESOURCES:
		sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
@@ -2808,6 +2812,26 @@ static const struct sense_info sense_info_table[] = {
		.key = ILLEGAL_REQUEST,
		.asc = 0x26, /* INVALID FIELD IN PARAMETER LIST */
	},
	[TCM_TOO_MANY_TARGET_DESCS] = {
		.key = ILLEGAL_REQUEST,
		.asc = 0x26,
		.ascq = 0x06, /* TOO MANY TARGET DESCRIPTORS */
	},
	[TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE] = {
		.key = ILLEGAL_REQUEST,
		.asc = 0x26,
		.ascq = 0x07, /* UNSUPPORTED TARGET DESCRIPTOR TYPE CODE */
	},
	[TCM_TOO_MANY_SEGMENT_DESCS] = {
		.key = ILLEGAL_REQUEST,
		.asc = 0x26,
		.ascq = 0x08, /* TOO MANY SEGMENT DESCRIPTORS */
	},
	[TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE] = {
		.key = ILLEGAL_REQUEST,
		.asc = 0x26,
		.ascq = 0x09, /* UNSUPPORTED SEGMENT DESCRIPTOR TYPE CODE */
	},
	[TCM_PARAMETER_LIST_LENGTH_ERROR] = {
		.key = ILLEGAL_REQUEST,
		.asc = 0x1a, /* PARAMETER LIST LENGTH ERROR */
+106 −51
Original line number Diff line number Diff line
@@ -53,18 +53,13 @@ static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf)
	return 0;
}

static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op *xop,
					bool src)
static int target_xcopy_locate_se_dev_e4(const unsigned char *dev_wwn,
					struct se_device **found_dev)
{
	struct se_device *se_dev;
	unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN], *dev_wwn;
	unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN];
	int rc;

	if (src)
		dev_wwn = &xop->dst_tid_wwn[0];
	else
		dev_wwn = &xop->src_tid_wwn[0];

	mutex_lock(&g_device_mutex);
	list_for_each_entry(se_dev, &g_device_list, g_dev_node) {

@@ -78,15 +73,8 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op
		if (rc != 0)
			continue;

		if (src) {
			xop->dst_dev = se_dev;
			pr_debug("XCOPY 0xe4: Setting xop->dst_dev: %p from located"
				" se_dev\n", xop->dst_dev);
		} else {
			xop->src_dev = se_dev;
			pr_debug("XCOPY 0xe4: Setting xop->src_dev: %p from located"
				" se_dev\n", xop->src_dev);
		}
		*found_dev = se_dev;
		pr_debug("XCOPY 0xe4: located se_dev: %p\n", se_dev);

		rc = target_depend_item(&se_dev->dev_group.cg_item);
		if (rc != 0) {
@@ -110,7 +98,7 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op
}

static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op *xop,
				unsigned char *p, bool src)
				unsigned char *p, unsigned short cscd_index)
{
	unsigned char *desc = p;
	unsigned short ript;
@@ -155,7 +143,13 @@ static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op
		return -EINVAL;
	}

	if (src) {
	if (cscd_index != xop->stdi && cscd_index != xop->dtdi) {
		pr_debug("XCOPY 0xe4: ignoring CSCD entry %d - neither src nor "
			 "dest\n", cscd_index);
		return 0;
	}

	if (cscd_index == xop->stdi) {
		memcpy(&xop->src_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN);
		/*
		 * Determine if the source designator matches the local device
@@ -167,10 +161,15 @@ static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op
			pr_debug("XCOPY 0xe4: Set xop->src_dev %p from source"
					" received xop\n", xop->src_dev);
		}
	} else {
	}

	if (cscd_index == xop->dtdi) {
		memcpy(&xop->dst_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN);
		/*
		 * Determine if the destination designator matches the local device
		 * Determine if the destination designator matches the local
		 * device. If @cscd_index corresponds to both source (stdi) and
		 * destination (dtdi), or dtdi comes after stdi, then
		 * XCOL_DEST_RECV_OP wins.
		 */
		if (!memcmp(&xop->local_dev_wwn[0], &xop->dst_tid_wwn[0],
				XCOPY_NAA_IEEE_REGEX_LEN)) {
@@ -190,20 +189,23 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
{
	struct se_device *local_dev = se_cmd->se_dev;
	unsigned char *desc = p;
	int offset = tdll % XCOPY_TARGET_DESC_LEN, rc, ret = 0;
	int offset = tdll % XCOPY_TARGET_DESC_LEN, rc;
	unsigned short cscd_index = 0;
	unsigned short start = 0;
	bool src = true;

	*sense_ret = TCM_INVALID_PARAMETER_LIST;

	if (offset != 0) {
		pr_err("XCOPY target descriptor list length is not"
			" multiple of %d\n", XCOPY_TARGET_DESC_LEN);
		*sense_ret = TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE;
		return -EINVAL;
	}
	if (tdll > 64) {
	if (tdll > RCR_OP_MAX_TARGET_DESC_COUNT * XCOPY_TARGET_DESC_LEN) {
		pr_err("XCOPY target descriptor supports a maximum"
			" two src/dest descriptors, tdll: %hu too large..\n", tdll);
		/* spc4r37 6.4.3.4 CSCD DESCRIPTOR LIST LENGTH field */
		*sense_ret = TCM_TOO_MANY_TARGET_DESCS;
		return -EINVAL;
	}
	/*
@@ -215,37 +217,43 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,

	while (start < tdll) {
		/*
		 * Check target descriptor identification with 0xE4 type with
		 * use VPD 0x83 WWPN matching ..
		 * Check target descriptor identification with 0xE4 type, and
		 * compare the current index with the CSCD descriptor IDs in
		 * the segment descriptor. Use VPD 0x83 WWPN matching ..
		 */
		switch (desc[0]) {
		case 0xe4:
			rc = target_xcopy_parse_tiddesc_e4(se_cmd, xop,
							&desc[0], src);
							&desc[0], cscd_index);
			if (rc != 0)
				goto out;
			/*
			 * Assume target descriptors are in source -> destination order..
			 */
			if (src)
				src = false;
			else
				src = true;
			start += XCOPY_TARGET_DESC_LEN;
			desc += XCOPY_TARGET_DESC_LEN;
			ret++;
			cscd_index++;
			break;
		default:
			pr_err("XCOPY unsupported descriptor type code:"
					" 0x%02x\n", desc[0]);
			*sense_ret = TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE;
			goto out;
		}
	}

	if (xop->op_origin == XCOL_SOURCE_RECV_OP)
		rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, true);
	else
		rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, false);
	switch (xop->op_origin) {
	case XCOL_SOURCE_RECV_OP:
		rc = target_xcopy_locate_se_dev_e4(xop->dst_tid_wwn,
						&xop->dst_dev);
		break;
	case XCOL_DEST_RECV_OP:
		rc = target_xcopy_locate_se_dev_e4(xop->src_tid_wwn,
						&xop->src_dev);
		break;
	default:
		pr_err("XCOPY CSCD descriptor IDs not found in CSCD list - "
			"stdi: %hu dtdi: %hu\n", xop->stdi, xop->dtdi);
		rc = -EINVAL;
		break;
	}
	/*
	 * If a matching IEEE NAA 0x83 descriptor for the requested device
	 * is not located on this node, return COPY_ABORTED with ASQ/ASQC
@@ -262,7 +270,7 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
	pr_debug("XCOPY TGT desc: Dest dev: %p NAA IEEE WWN: 0x%16phN\n",
		 xop->dst_dev, &xop->dst_tid_wwn[0]);

	return ret;
	return cscd_index;

out:
	return -EINVAL;
@@ -284,6 +292,14 @@ static int target_xcopy_parse_segdesc_02(struct se_cmd *se_cmd, struct xcopy_op

	xop->stdi = get_unaligned_be16(&desc[4]);
	xop->dtdi = get_unaligned_be16(&desc[6]);

	if (xop->stdi > XCOPY_CSCD_DESC_ID_LIST_OFF_MAX ||
	    xop->dtdi > XCOPY_CSCD_DESC_ID_LIST_OFF_MAX) {
		pr_err("XCOPY segment desc 0x02: unsupported CSCD ID > 0x%x; stdi: %hu dtdi: %hu\n",
			XCOPY_CSCD_DESC_ID_LIST_OFF_MAX, xop->stdi, xop->dtdi);
		return -EINVAL;
	}

	pr_debug("XCOPY seg desc 0x02: desc_len: %hu stdi: %hu dtdi: %hu, DC: %d\n",
		desc_len, xop->stdi, xop->dtdi, dc);

@@ -306,15 +322,25 @@ static int target_xcopy_parse_segdesc_02(struct se_cmd *se_cmd, struct xcopy_op

static int target_xcopy_parse_segment_descriptors(struct se_cmd *se_cmd,
				struct xcopy_op *xop, unsigned char *p,
				unsigned int sdll)
				unsigned int sdll, sense_reason_t *sense_ret)
{
	unsigned char *desc = p;
	unsigned int start = 0;
	int offset = sdll % XCOPY_SEGMENT_DESC_LEN, rc, ret = 0;

	*sense_ret = TCM_INVALID_PARAMETER_LIST;

	if (offset != 0) {
		pr_err("XCOPY segment descriptor list length is not"
			" multiple of %d\n", XCOPY_SEGMENT_DESC_LEN);
		*sense_ret = TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE;
		return -EINVAL;
	}
	if (sdll > RCR_OP_MAX_SG_DESC_COUNT * XCOPY_SEGMENT_DESC_LEN) {
		pr_err("XCOPY supports %u segment descriptor(s), sdll: %u too"
			" large..\n", RCR_OP_MAX_SG_DESC_COUNT, sdll);
		/* spc4r37 6.4.3.5 SEGMENT DESCRIPTOR LIST LENGTH field */
		*sense_ret = TCM_TOO_MANY_SEGMENT_DESCS;
		return -EINVAL;
	}

@@ -335,6 +361,7 @@ static int target_xcopy_parse_segment_descriptors(struct se_cmd *se_cmd,
		default:
			pr_err("XCOPY unsupported segment descriptor"
				"type: 0x%02x\n", desc[0]);
			*sense_ret = TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE;
			goto out;
		}
	}
@@ -861,6 +888,16 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
		return TCM_UNSUPPORTED_SCSI_OPCODE;
	}

	if (se_cmd->data_length == 0) {
		target_complete_cmd(se_cmd, SAM_STAT_GOOD);
		return TCM_NO_SENSE;
	}
	if (se_cmd->data_length < XCOPY_HDR_LEN) {
		pr_err("XCOPY parameter truncation: length %u < hdr_len %u\n",
				se_cmd->data_length, XCOPY_HDR_LEN);
		return TCM_PARAMETER_LIST_LENGTH_ERROR;
	}

	xop = kzalloc(sizeof(struct xcopy_op), GFP_KERNEL);
	if (!xop) {
		pr_err("Unable to allocate xcopy_op\n");
@@ -883,6 +920,12 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
	 */
	tdll = get_unaligned_be16(&p[2]);
	sdll = get_unaligned_be32(&p[8]);
	if (tdll + sdll > RCR_OP_MAX_DESC_LIST_LEN) {
		pr_err("XCOPY descriptor list length %u exceeds maximum %u\n",
		       tdll + sdll, RCR_OP_MAX_DESC_LIST_LEN);
		ret = TCM_PARAMETER_LIST_LENGTH_ERROR;
		goto out;
	}

	inline_dl = get_unaligned_be32(&p[12]);
	if (inline_dl != 0) {
@@ -890,10 +933,32 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
		goto out;
	}

	if (se_cmd->data_length < (XCOPY_HDR_LEN + tdll + sdll + inline_dl)) {
		pr_err("XCOPY parameter truncation: data length %u too small "
			"for tdll: %hu sdll: %u inline_dl: %u\n",
			se_cmd->data_length, tdll, sdll, inline_dl);
		ret = TCM_PARAMETER_LIST_LENGTH_ERROR;
		goto out;
	}

	pr_debug("Processing XCOPY with list_id: 0x%02x list_id_usage: 0x%02x"
		" tdll: %hu sdll: %u inline_dl: %u\n", list_id, list_id_usage,
		tdll, sdll, inline_dl);

	/*
	 * skip over the target descriptors until segment descriptors
	 * have been passed - CSCD ids are needed to determine src and dest.
	 */
	seg_desc = &p[16] + tdll;

	rc = target_xcopy_parse_segment_descriptors(se_cmd, xop, seg_desc,
						    sdll, &ret);
	if (rc <= 0)
		goto out;

	pr_debug("XCOPY: Processed %d segment descriptors, length: %u\n", rc,
				rc * XCOPY_SEGMENT_DESC_LEN);

	rc = target_xcopy_parse_target_descriptors(se_cmd, xop, &p[16], tdll, &ret);
	if (rc <= 0)
		goto out;
@@ -911,18 +976,8 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)

	pr_debug("XCOPY: Processed %d target descriptors, length: %u\n", rc,
				rc * XCOPY_TARGET_DESC_LEN);
	seg_desc = &p[16];
	seg_desc += (rc * XCOPY_TARGET_DESC_LEN);

	rc = target_xcopy_parse_segment_descriptors(se_cmd, xop, seg_desc, sdll);
	if (rc <= 0) {
		xcopy_pt_undepend_remotedev(xop);
		goto out;
	}
	transport_kunmap_data_sg(se_cmd);

	pr_debug("XCOPY: Processed %d segment descriptors, length: %u\n", rc,
				rc * XCOPY_SEGMENT_DESC_LEN);
	INIT_WORK(&xop->xop_work, target_xcopy_do_work);
	queue_work(xcopy_wq, &xop->xop_work);
	return TCM_NO_SENSE;
+7 −0
Original line number Diff line number Diff line
#include <target/target_core_base.h>

#define XCOPY_HDR_LEN			16
#define XCOPY_TARGET_DESC_LEN		32
#define XCOPY_SEGMENT_DESC_LEN		28
#define XCOPY_NAA_IEEE_REGEX_LEN	16
#define XCOPY_MAX_SECTORS		1024

/*
 * SPC4r37 6.4.6.1
 * Table 150 — CSCD descriptor ID values
 */
#define XCOPY_CSCD_DESC_ID_LIST_OFF_MAX	0x07FF

enum xcopy_origin_list {
	XCOL_SOURCE_RECV_OP = 0x01,
	XCOL_DEST_RECV_OP = 0x02,
+4 −0
Original line number Diff line number Diff line
@@ -174,6 +174,10 @@ enum tcm_sense_reason_table {
	TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED	= R(0x16),
	TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED	= R(0x17),
	TCM_COPY_TARGET_DEVICE_NOT_REACHABLE	= R(0x18),
	TCM_TOO_MANY_TARGET_DESCS		= R(0x19),
	TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE	= R(0x1a),
	TCM_TOO_MANY_SEGMENT_DESCS		= R(0x1b),
	TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE	= R(0x1c),
#undef R
};