cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

target_core_xcopy.c (28474B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*******************************************************************************
      3 * Filename: target_core_xcopy.c
      4 *
      5 * This file contains support for SPC-4 Extended-Copy offload with generic
      6 * TCM backends.
      7 *
      8 * Copyright (c) 2011-2013 Datera, Inc. All rights reserved.
      9 *
     10 * Author:
     11 * Nicholas A. Bellinger <nab@daterainc.com>
     12 *
     13 ******************************************************************************/
     14
     15#include <linux/slab.h>
     16#include <linux/spinlock.h>
     17#include <linux/list.h>
     18#include <linux/configfs.h>
     19#include <linux/ratelimit.h>
     20#include <scsi/scsi_proto.h>
     21#include <asm/unaligned.h>
     22
     23#include <target/target_core_base.h>
     24#include <target/target_core_backend.h>
     25#include <target/target_core_fabric.h>
     26
     27#include "target_core_internal.h"
     28#include "target_core_pr.h"
     29#include "target_core_ua.h"
     30#include "target_core_xcopy.h"
     31
     32static struct workqueue_struct *xcopy_wq = NULL;
     33
     34static sense_reason_t target_parse_xcopy_cmd(struct xcopy_op *xop);
     35
     36/**
     37 * target_xcopy_locate_se_dev_e4_iter - compare XCOPY NAA device identifiers
     38 *
     39 * @se_dev: device being considered for match
     40 * @dev_wwn: XCOPY requested NAA dev_wwn
     41 * @return: 1 on match, 0 on no-match
     42 */
     43static int target_xcopy_locate_se_dev_e4_iter(struct se_device *se_dev,
     44					      const unsigned char *dev_wwn)
     45{
     46	unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN];
     47	int rc;
     48
     49	if (!se_dev->dev_attrib.emulate_3pc) {
     50		pr_debug("XCOPY: emulate_3pc disabled on se_dev %p\n", se_dev);
     51		return 0;
     52	}
     53
     54	memset(&tmp_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN);
     55	spc_gen_naa_6h_vendor_specific(se_dev, &tmp_dev_wwn[0]);
     56
     57	rc = memcmp(&tmp_dev_wwn[0], dev_wwn, XCOPY_NAA_IEEE_REGEX_LEN);
     58	if (rc != 0) {
     59		pr_debug("XCOPY: skip non-matching: %*ph\n",
     60			 XCOPY_NAA_IEEE_REGEX_LEN, tmp_dev_wwn);
     61		return 0;
     62	}
     63	pr_debug("XCOPY 0xe4: located se_dev: %p\n", se_dev);
     64
     65	return 1;
     66}
     67
     68static int target_xcopy_locate_se_dev_e4(struct se_session *sess,
     69					const unsigned char *dev_wwn,
     70					struct se_device **_found_dev,
     71					struct percpu_ref **_found_lun_ref)
     72{
     73	struct se_dev_entry *deve;
     74	struct se_node_acl *nacl;
     75	struct se_lun *this_lun = NULL;
     76	struct se_device *found_dev = NULL;
     77
     78	/* cmd with NULL sess indicates no associated $FABRIC_MOD */
     79	if (!sess)
     80		goto err_out;
     81
     82	pr_debug("XCOPY 0xe4: searching for: %*ph\n",
     83		 XCOPY_NAA_IEEE_REGEX_LEN, dev_wwn);
     84
     85	nacl = sess->se_node_acl;
     86	rcu_read_lock();
     87	hlist_for_each_entry_rcu(deve, &nacl->lun_entry_hlist, link) {
     88		struct se_device *this_dev;
     89		int rc;
     90
     91		this_lun = rcu_dereference(deve->se_lun);
     92		this_dev = rcu_dereference_raw(this_lun->lun_se_dev);
     93
     94		rc = target_xcopy_locate_se_dev_e4_iter(this_dev, dev_wwn);
     95		if (rc) {
     96			if (percpu_ref_tryget_live(&this_lun->lun_ref))
     97				found_dev = this_dev;
     98			break;
     99		}
    100	}
    101	rcu_read_unlock();
    102	if (found_dev == NULL)
    103		goto err_out;
    104
    105	pr_debug("lun_ref held for se_dev: %p se_dev->se_dev_group: %p\n",
    106		 found_dev, &found_dev->dev_group);
    107	*_found_dev = found_dev;
    108	*_found_lun_ref = &this_lun->lun_ref;
    109	return 0;
    110err_out:
    111	pr_debug_ratelimited("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n");
    112	return -EINVAL;
    113}
    114
    115static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op *xop,
    116				unsigned char *p, unsigned short cscd_index)
    117{
    118	unsigned char *desc = p;
    119	unsigned short ript;
    120	u8 desig_len;
    121	/*
    122	 * Extract RELATIVE INITIATOR PORT IDENTIFIER
    123	 */
    124	ript = get_unaligned_be16(&desc[2]);
    125	pr_debug("XCOPY 0xe4: RELATIVE INITIATOR PORT IDENTIFIER: %hu\n", ript);
    126	/*
    127	 * Check for supported code set, association, and designator type
    128	 */
    129	if ((desc[4] & 0x0f) != 0x1) {
    130		pr_err("XCOPY 0xe4: code set of non binary type not supported\n");
    131		return -EINVAL;
    132	}
    133	if ((desc[5] & 0x30) != 0x00) {
    134		pr_err("XCOPY 0xe4: association other than LUN not supported\n");
    135		return -EINVAL;
    136	}
    137	if ((desc[5] & 0x0f) != 0x3) {
    138		pr_err("XCOPY 0xe4: designator type unsupported: 0x%02x\n",
    139				(desc[5] & 0x0f));
    140		return -EINVAL;
    141	}
    142	/*
    143	 * Check for matching 16 byte length for NAA IEEE Registered Extended
    144	 * Assigned designator
    145	 */
    146	desig_len = desc[7];
    147	if (desig_len != XCOPY_NAA_IEEE_REGEX_LEN) {
    148		pr_err("XCOPY 0xe4: invalid desig_len: %d\n", (int)desig_len);
    149		return -EINVAL;
    150	}
    151	pr_debug("XCOPY 0xe4: desig_len: %d\n", (int)desig_len);
    152	/*
    153	 * Check for NAA IEEE Registered Extended Assigned header..
    154	 */
    155	if ((desc[8] & 0xf0) != 0x60) {
    156		pr_err("XCOPY 0xe4: Unsupported DESIGNATOR TYPE: 0x%02x\n",
    157					(desc[8] & 0xf0));
    158		return -EINVAL;
    159	}
    160
    161	if (cscd_index != xop->stdi && cscd_index != xop->dtdi) {
    162		pr_debug("XCOPY 0xe4: ignoring CSCD entry %d - neither src nor "
    163			 "dest\n", cscd_index);
    164		return 0;
    165	}
    166
    167	if (cscd_index == xop->stdi) {
    168		memcpy(&xop->src_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN);
    169		/*
    170		 * Determine if the source designator matches the local device
    171		 */
    172		if (!memcmp(&xop->local_dev_wwn[0], &xop->src_tid_wwn[0],
    173				XCOPY_NAA_IEEE_REGEX_LEN)) {
    174			xop->op_origin = XCOL_SOURCE_RECV_OP;
    175			xop->src_dev = se_cmd->se_dev;
    176			pr_debug("XCOPY 0xe4: Set xop->src_dev %p from source"
    177					" received xop\n", xop->src_dev);
    178		}
    179	}
    180
    181	if (cscd_index == xop->dtdi) {
    182		memcpy(&xop->dst_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN);
    183		/*
    184		 * Determine if the destination designator matches the local
    185		 * device. If @cscd_index corresponds to both source (stdi) and
    186		 * destination (dtdi), or dtdi comes after stdi, then
    187		 * XCOL_DEST_RECV_OP wins.
    188		 */
    189		if (!memcmp(&xop->local_dev_wwn[0], &xop->dst_tid_wwn[0],
    190				XCOPY_NAA_IEEE_REGEX_LEN)) {
    191			xop->op_origin = XCOL_DEST_RECV_OP;
    192			xop->dst_dev = se_cmd->se_dev;
    193			pr_debug("XCOPY 0xe4: Set xop->dst_dev: %p from destination"
    194				" received xop\n", xop->dst_dev);
    195		}
    196	}
    197
    198	return 0;
    199}
    200
    201static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
    202				struct xcopy_op *xop, unsigned char *p,
    203				unsigned short tdll, sense_reason_t *sense_ret)
    204{
    205	struct se_device *local_dev = se_cmd->se_dev;
    206	unsigned char *desc = p;
    207	int offset = tdll % XCOPY_TARGET_DESC_LEN, rc;
    208	unsigned short cscd_index = 0;
    209	unsigned short start = 0;
    210
    211	*sense_ret = TCM_INVALID_PARAMETER_LIST;
    212
    213	if (offset != 0) {
    214		pr_err("XCOPY target descriptor list length is not"
    215			" multiple of %d\n", XCOPY_TARGET_DESC_LEN);
    216		*sense_ret = TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE;
    217		return -EINVAL;
    218	}
    219	if (tdll > RCR_OP_MAX_TARGET_DESC_COUNT * XCOPY_TARGET_DESC_LEN) {
    220		pr_err("XCOPY target descriptor supports a maximum"
    221			" two src/dest descriptors, tdll: %hu too large..\n", tdll);
    222		/* spc4r37 6.4.3.4 CSCD DESCRIPTOR LIST LENGTH field */
    223		*sense_ret = TCM_TOO_MANY_TARGET_DESCS;
    224		return -EINVAL;
    225	}
    226	/*
    227	 * Generate an IEEE Registered Extended designator based upon the
    228	 * se_device the XCOPY was received upon..
    229	 */
    230	memset(&xop->local_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN);
    231	spc_gen_naa_6h_vendor_specific(local_dev, &xop->local_dev_wwn[0]);
    232
    233	while (start < tdll) {
    234		/*
    235		 * Check target descriptor identification with 0xE4 type, and
    236		 * compare the current index with the CSCD descriptor IDs in
    237		 * the segment descriptor. Use VPD 0x83 WWPN matching ..
    238		 */
    239		switch (desc[0]) {
    240		case 0xe4:
    241			rc = target_xcopy_parse_tiddesc_e4(se_cmd, xop,
    242							&desc[0], cscd_index);
    243			if (rc != 0)
    244				goto out;
    245			start += XCOPY_TARGET_DESC_LEN;
    246			desc += XCOPY_TARGET_DESC_LEN;
    247			cscd_index++;
    248			break;
    249		default:
    250			pr_err("XCOPY unsupported descriptor type code:"
    251					" 0x%02x\n", desc[0]);
    252			*sense_ret = TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE;
    253			goto out;
    254		}
    255	}
    256
    257	switch (xop->op_origin) {
    258	case XCOL_SOURCE_RECV_OP:
    259		rc = target_xcopy_locate_se_dev_e4(se_cmd->se_sess,
    260						xop->dst_tid_wwn,
    261						&xop->dst_dev,
    262						&xop->remote_lun_ref);
    263		break;
    264	case XCOL_DEST_RECV_OP:
    265		rc = target_xcopy_locate_se_dev_e4(se_cmd->se_sess,
    266						xop->src_tid_wwn,
    267						&xop->src_dev,
    268						&xop->remote_lun_ref);
    269		break;
    270	default:
    271		pr_err("XCOPY CSCD descriptor IDs not found in CSCD list - "
    272			"stdi: %hu dtdi: %hu\n", xop->stdi, xop->dtdi);
    273		rc = -EINVAL;
    274		break;
    275	}
    276	/*
    277	 * If a matching IEEE NAA 0x83 descriptor for the requested device
    278	 * is not located on this node, return COPY_ABORTED with ASQ/ASQC
    279	 * 0x0d/0x02 - COPY_TARGET_DEVICE_NOT_REACHABLE to request the
    280	 * initiator to fall back to normal copy method.
    281	 */
    282	if (rc < 0) {
    283		*sense_ret = TCM_COPY_TARGET_DEVICE_NOT_REACHABLE;
    284		goto out;
    285	}
    286
    287	pr_debug("XCOPY TGT desc: Source dev: %p NAA IEEE WWN: 0x%16phN\n",
    288		 xop->src_dev, &xop->src_tid_wwn[0]);
    289	pr_debug("XCOPY TGT desc: Dest dev: %p NAA IEEE WWN: 0x%16phN\n",
    290		 xop->dst_dev, &xop->dst_tid_wwn[0]);
    291
    292	return cscd_index;
    293
    294out:
    295	return -EINVAL;
    296}
    297
    298static int target_xcopy_parse_segdesc_02(struct xcopy_op *xop, unsigned char *p)
    299{
    300	unsigned char *desc = p;
    301	int dc = (desc[1] & 0x02);
    302	unsigned short desc_len;
    303
    304	desc_len = get_unaligned_be16(&desc[2]);
    305	if (desc_len != 0x18) {
    306		pr_err("XCOPY segment desc 0x02: Illegal desc_len:"
    307				" %hu\n", desc_len);
    308		return -EINVAL;
    309	}
    310
    311	xop->stdi = get_unaligned_be16(&desc[4]);
    312	xop->dtdi = get_unaligned_be16(&desc[6]);
    313
    314	if (xop->stdi > XCOPY_CSCD_DESC_ID_LIST_OFF_MAX ||
    315	    xop->dtdi > XCOPY_CSCD_DESC_ID_LIST_OFF_MAX) {
    316		pr_err("XCOPY segment desc 0x02: unsupported CSCD ID > 0x%x; stdi: %hu dtdi: %hu\n",
    317			XCOPY_CSCD_DESC_ID_LIST_OFF_MAX, xop->stdi, xop->dtdi);
    318		return -EINVAL;
    319	}
    320
    321	pr_debug("XCOPY seg desc 0x02: desc_len: %hu stdi: %hu dtdi: %hu, DC: %d\n",
    322		desc_len, xop->stdi, xop->dtdi, dc);
    323
    324	xop->nolb = get_unaligned_be16(&desc[10]);
    325	xop->src_lba = get_unaligned_be64(&desc[12]);
    326	xop->dst_lba = get_unaligned_be64(&desc[20]);
    327	pr_debug("XCOPY seg desc 0x02: nolb: %hu src_lba: %llu dst_lba: %llu\n",
    328		xop->nolb, (unsigned long long)xop->src_lba,
    329		(unsigned long long)xop->dst_lba);
    330
    331	return 0;
    332}
    333
    334static int target_xcopy_parse_segment_descriptors(struct xcopy_op *xop,
    335				unsigned char *p, unsigned int sdll,
    336				sense_reason_t *sense_ret)
    337{
    338	unsigned char *desc = p;
    339	unsigned int start = 0;
    340	int offset = sdll % XCOPY_SEGMENT_DESC_LEN, rc, ret = 0;
    341
    342	*sense_ret = TCM_INVALID_PARAMETER_LIST;
    343
    344	if (offset != 0) {
    345		pr_err("XCOPY segment descriptor list length is not"
    346			" multiple of %d\n", XCOPY_SEGMENT_DESC_LEN);
    347		*sense_ret = TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE;
    348		return -EINVAL;
    349	}
    350	if (sdll > RCR_OP_MAX_SG_DESC_COUNT * XCOPY_SEGMENT_DESC_LEN) {
    351		pr_err("XCOPY supports %u segment descriptor(s), sdll: %u too"
    352			" large..\n", RCR_OP_MAX_SG_DESC_COUNT, sdll);
    353		/* spc4r37 6.4.3.5 SEGMENT DESCRIPTOR LIST LENGTH field */
    354		*sense_ret = TCM_TOO_MANY_SEGMENT_DESCS;
    355		return -EINVAL;
    356	}
    357
    358	while (start < sdll) {
    359		/*
    360		 * Check segment descriptor type code for block -> block
    361		 */
    362		switch (desc[0]) {
    363		case 0x02:
    364			rc = target_xcopy_parse_segdesc_02(xop, desc);
    365			if (rc < 0)
    366				goto out;
    367
    368			ret++;
    369			start += XCOPY_SEGMENT_DESC_LEN;
    370			desc += XCOPY_SEGMENT_DESC_LEN;
    371			break;
    372		default:
    373			pr_err("XCOPY unsupported segment descriptor"
    374				"type: 0x%02x\n", desc[0]);
    375			*sense_ret = TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE;
    376			goto out;
    377		}
    378	}
    379
    380	return ret;
    381
    382out:
    383	return -EINVAL;
    384}
    385
    386/*
    387 * Start xcopy_pt ops
    388 */
    389
    390struct xcopy_pt_cmd {
    391	struct se_cmd se_cmd;
    392	struct completion xpt_passthrough_sem;
    393	unsigned char sense_buffer[TRANSPORT_SENSE_BUFFER];
    394};
    395
    396struct se_portal_group xcopy_pt_tpg;
    397static struct se_session xcopy_pt_sess;
    398static struct se_node_acl xcopy_pt_nacl;
    399
    400static int xcopy_pt_get_cmd_state(struct se_cmd *se_cmd)
    401{
    402        return 0;
    403}
    404
    405static void xcopy_pt_undepend_remotedev(struct xcopy_op *xop)
    406{
    407	if (xop->op_origin == XCOL_SOURCE_RECV_OP)
    408		pr_debug("putting dst lun_ref for %p\n", xop->dst_dev);
    409	else
    410		pr_debug("putting src lun_ref for %p\n", xop->src_dev);
    411
    412	percpu_ref_put(xop->remote_lun_ref);
    413}
    414
    415static void xcopy_pt_release_cmd(struct se_cmd *se_cmd)
    416{
    417	struct xcopy_pt_cmd *xpt_cmd = container_of(se_cmd,
    418				struct xcopy_pt_cmd, se_cmd);
    419
    420	/* xpt_cmd is on the stack, nothing to free here */
    421	pr_debug("xpt_cmd done: %p\n", xpt_cmd);
    422}
    423
    424static int xcopy_pt_check_stop_free(struct se_cmd *se_cmd)
    425{
    426	struct xcopy_pt_cmd *xpt_cmd = container_of(se_cmd,
    427				struct xcopy_pt_cmd, se_cmd);
    428
    429	complete(&xpt_cmd->xpt_passthrough_sem);
    430	return 0;
    431}
    432
    433static int xcopy_pt_write_pending(struct se_cmd *se_cmd)
    434{
    435	return 0;
    436}
    437
    438static int xcopy_pt_queue_data_in(struct se_cmd *se_cmd)
    439{
    440	return 0;
    441}
    442
    443static int xcopy_pt_queue_status(struct se_cmd *se_cmd)
    444{
    445	return 0;
    446}
    447
    448static const struct target_core_fabric_ops xcopy_pt_tfo = {
    449	.fabric_name		= "xcopy-pt",
    450	.get_cmd_state		= xcopy_pt_get_cmd_state,
    451	.release_cmd		= xcopy_pt_release_cmd,
    452	.check_stop_free	= xcopy_pt_check_stop_free,
    453	.write_pending		= xcopy_pt_write_pending,
    454	.queue_data_in		= xcopy_pt_queue_data_in,
    455	.queue_status		= xcopy_pt_queue_status,
    456};
    457
    458/*
    459 * End xcopy_pt_ops
    460 */
    461
    462int target_xcopy_setup_pt(void)
    463{
    464	int ret;
    465
    466	xcopy_wq = alloc_workqueue("xcopy_wq", WQ_MEM_RECLAIM, 0);
    467	if (!xcopy_wq) {
    468		pr_err("Unable to allocate xcopy_wq\n");
    469		return -ENOMEM;
    470	}
    471
    472	memset(&xcopy_pt_tpg, 0, sizeof(struct se_portal_group));
    473	INIT_LIST_HEAD(&xcopy_pt_tpg.acl_node_list);
    474	INIT_LIST_HEAD(&xcopy_pt_tpg.tpg_sess_list);
    475
    476	xcopy_pt_tpg.se_tpg_tfo = &xcopy_pt_tfo;
    477
    478	memset(&xcopy_pt_nacl, 0, sizeof(struct se_node_acl));
    479	INIT_LIST_HEAD(&xcopy_pt_nacl.acl_list);
    480	INIT_LIST_HEAD(&xcopy_pt_nacl.acl_sess_list);
    481	memset(&xcopy_pt_sess, 0, sizeof(struct se_session));
    482	ret = transport_init_session(&xcopy_pt_sess);
    483	if (ret < 0)
    484		goto destroy_wq;
    485
    486	xcopy_pt_nacl.se_tpg = &xcopy_pt_tpg;
    487	xcopy_pt_nacl.nacl_sess = &xcopy_pt_sess;
    488
    489	xcopy_pt_sess.se_tpg = &xcopy_pt_tpg;
    490	xcopy_pt_sess.se_node_acl = &xcopy_pt_nacl;
    491
    492	return 0;
    493
    494destroy_wq:
    495	destroy_workqueue(xcopy_wq);
    496	xcopy_wq = NULL;
    497	return ret;
    498}
    499
    500void target_xcopy_release_pt(void)
    501{
    502	if (xcopy_wq) {
    503		destroy_workqueue(xcopy_wq);
    504		transport_uninit_session(&xcopy_pt_sess);
    505	}
    506}
    507
    508/*
    509 * target_xcopy_setup_pt_cmd - set up a pass-through command
    510 * @xpt_cmd:	 Data structure to initialize.
    511 * @xop:	 Describes the XCOPY operation received from an initiator.
    512 * @se_dev:	 Backend device to associate with @xpt_cmd if
    513 *		 @remote_port == true.
    514 * @cdb:	 SCSI CDB to be copied into @xpt_cmd.
    515 * @remote_port: If false, use the LUN through which the XCOPY command has
    516 *		 been received. If true, use @se_dev->xcopy_lun.
    517 *
    518 * Set up a SCSI command (READ or WRITE) that will be used to execute an
    519 * XCOPY command.
    520 */
    521static int target_xcopy_setup_pt_cmd(
    522	struct xcopy_pt_cmd *xpt_cmd,
    523	struct xcopy_op *xop,
    524	struct se_device *se_dev,
    525	unsigned char *cdb,
    526	bool remote_port)
    527{
    528	struct se_cmd *cmd = &xpt_cmd->se_cmd;
    529
    530	/*
    531	 * Setup LUN+port to honor reservations based upon xop->op_origin for
    532	 * X-COPY PUSH or X-COPY PULL based upon where the CDB was received.
    533	 */
    534	if (remote_port) {
    535		cmd->se_lun = &se_dev->xcopy_lun;
    536		cmd->se_dev = se_dev;
    537	} else {
    538		cmd->se_lun = xop->xop_se_cmd->se_lun;
    539		cmd->se_dev = xop->xop_se_cmd->se_dev;
    540	}
    541	cmd->se_cmd_flags |= SCF_SE_LUN_CMD;
    542
    543	if (target_cmd_init_cdb(cmd, cdb, GFP_KERNEL))
    544		return -EINVAL;
    545
    546	cmd->tag = 0;
    547	if (target_cmd_parse_cdb(cmd))
    548		return -EINVAL;
    549
    550	if (transport_generic_map_mem_to_cmd(cmd, xop->xop_data_sg,
    551					xop->xop_data_nents, NULL, 0))
    552		return -EINVAL;
    553
    554	pr_debug("Setup PASSTHROUGH_NOALLOC t_data_sg: %p t_data_nents:"
    555		 " %u\n", cmd->t_data_sg, cmd->t_data_nents);
    556
    557	return 0;
    558}
    559
    560static int target_xcopy_issue_pt_cmd(struct xcopy_pt_cmd *xpt_cmd)
    561{
    562	struct se_cmd *se_cmd = &xpt_cmd->se_cmd;
    563	sense_reason_t sense_rc;
    564
    565	sense_rc = transport_generic_new_cmd(se_cmd);
    566	if (sense_rc)
    567		return -EINVAL;
    568
    569	if (se_cmd->data_direction == DMA_TO_DEVICE)
    570		target_execute_cmd(se_cmd);
    571
    572	wait_for_completion_interruptible(&xpt_cmd->xpt_passthrough_sem);
    573
    574	pr_debug("target_xcopy_issue_pt_cmd(): SCSI status: 0x%02x\n",
    575			se_cmd->scsi_status);
    576
    577	return (se_cmd->scsi_status) ? -EINVAL : 0;
    578}
    579
    580static int target_xcopy_read_source(
    581	struct se_cmd *ec_cmd,
    582	struct xcopy_op *xop,
    583	struct se_device *src_dev,
    584	sector_t src_lba,
    585	u32 src_sectors)
    586{
    587	struct xcopy_pt_cmd xpt_cmd;
    588	struct se_cmd *se_cmd = &xpt_cmd.se_cmd;
    589	u32 length = (src_sectors * src_dev->dev_attrib.block_size);
    590	int rc;
    591	unsigned char cdb[16];
    592	bool remote_port = (xop->op_origin == XCOL_DEST_RECV_OP);
    593
    594	memset(&xpt_cmd, 0, sizeof(xpt_cmd));
    595	init_completion(&xpt_cmd.xpt_passthrough_sem);
    596
    597	memset(&cdb[0], 0, 16);
    598	cdb[0] = READ_16;
    599	put_unaligned_be64(src_lba, &cdb[2]);
    600	put_unaligned_be32(src_sectors, &cdb[10]);
    601	pr_debug("XCOPY: Built READ_16: LBA: %llu Sectors: %u Length: %u\n",
    602		(unsigned long long)src_lba, src_sectors, length);
    603
    604	__target_init_cmd(se_cmd, &xcopy_pt_tfo, &xcopy_pt_sess, length,
    605			  DMA_FROM_DEVICE, 0, &xpt_cmd.sense_buffer[0], 0);
    606
    607	rc = target_xcopy_setup_pt_cmd(&xpt_cmd, xop, src_dev, &cdb[0],
    608				remote_port);
    609	if (rc < 0) {
    610		ec_cmd->scsi_status = se_cmd->scsi_status;
    611		goto out;
    612	}
    613
    614	pr_debug("XCOPY-READ: Saved xop->xop_data_sg: %p, num: %u for READ"
    615		" memory\n", xop->xop_data_sg, xop->xop_data_nents);
    616
    617	rc = target_xcopy_issue_pt_cmd(&xpt_cmd);
    618	if (rc < 0)
    619		ec_cmd->scsi_status = se_cmd->scsi_status;
    620out:
    621	transport_generic_free_cmd(se_cmd, 0);
    622	return rc;
    623}
    624
    625static int target_xcopy_write_destination(
    626	struct se_cmd *ec_cmd,
    627	struct xcopy_op *xop,
    628	struct se_device *dst_dev,
    629	sector_t dst_lba,
    630	u32 dst_sectors)
    631{
    632	struct xcopy_pt_cmd xpt_cmd;
    633	struct se_cmd *se_cmd = &xpt_cmd.se_cmd;
    634	u32 length = (dst_sectors * dst_dev->dev_attrib.block_size);
    635	int rc;
    636	unsigned char cdb[16];
    637	bool remote_port = (xop->op_origin == XCOL_SOURCE_RECV_OP);
    638
    639	memset(&xpt_cmd, 0, sizeof(xpt_cmd));
    640	init_completion(&xpt_cmd.xpt_passthrough_sem);
    641
    642	memset(&cdb[0], 0, 16);
    643	cdb[0] = WRITE_16;
    644	put_unaligned_be64(dst_lba, &cdb[2]);
    645	put_unaligned_be32(dst_sectors, &cdb[10]);
    646	pr_debug("XCOPY: Built WRITE_16: LBA: %llu Sectors: %u Length: %u\n",
    647		(unsigned long long)dst_lba, dst_sectors, length);
    648
    649	__target_init_cmd(se_cmd, &xcopy_pt_tfo, &xcopy_pt_sess, length,
    650			  DMA_TO_DEVICE, 0, &xpt_cmd.sense_buffer[0], 0);
    651
    652	rc = target_xcopy_setup_pt_cmd(&xpt_cmd, xop, dst_dev, &cdb[0],
    653				remote_port);
    654	if (rc < 0) {
    655		ec_cmd->scsi_status = se_cmd->scsi_status;
    656		goto out;
    657	}
    658
    659	rc = target_xcopy_issue_pt_cmd(&xpt_cmd);
    660	if (rc < 0)
    661		ec_cmd->scsi_status = se_cmd->scsi_status;
    662out:
    663	transport_generic_free_cmd(se_cmd, 0);
    664	return rc;
    665}
    666
    667static void target_xcopy_do_work(struct work_struct *work)
    668{
    669	struct xcopy_op *xop = container_of(work, struct xcopy_op, xop_work);
    670	struct se_cmd *ec_cmd = xop->xop_se_cmd;
    671	struct se_device *src_dev, *dst_dev;
    672	sector_t src_lba, dst_lba, end_lba;
    673	unsigned int max_sectors;
    674	int rc = 0;
    675	unsigned short nolb, max_nolb, copied_nolb = 0;
    676	sense_reason_t sense_rc;
    677
    678	sense_rc = target_parse_xcopy_cmd(xop);
    679	if (sense_rc != TCM_NO_SENSE)
    680		goto err_free;
    681
    682	if (WARN_ON_ONCE(!xop->src_dev) || WARN_ON_ONCE(!xop->dst_dev)) {
    683		sense_rc = TCM_INVALID_PARAMETER_LIST;
    684		goto err_free;
    685	}
    686
    687	src_dev = xop->src_dev;
    688	dst_dev = xop->dst_dev;
    689	src_lba = xop->src_lba;
    690	dst_lba = xop->dst_lba;
    691	nolb = xop->nolb;
    692	end_lba = src_lba + nolb;
    693	/*
    694	 * Break up XCOPY I/O into hw_max_sectors sized I/O based on the
    695	 * smallest max_sectors between src_dev + dev_dev, or
    696	 */
    697	max_sectors = min(src_dev->dev_attrib.hw_max_sectors,
    698			  dst_dev->dev_attrib.hw_max_sectors);
    699	max_sectors = min_t(u32, max_sectors, XCOPY_MAX_SECTORS);
    700
    701	max_nolb = min_t(u16, max_sectors, ((u16)(~0U)));
    702
    703	pr_debug("target_xcopy_do_work: nolb: %hu, max_nolb: %hu end_lba: %llu\n",
    704			nolb, max_nolb, (unsigned long long)end_lba);
    705	pr_debug("target_xcopy_do_work: Starting src_lba: %llu, dst_lba: %llu\n",
    706			(unsigned long long)src_lba, (unsigned long long)dst_lba);
    707
    708	while (src_lba < end_lba) {
    709		unsigned short cur_nolb = min(nolb, max_nolb);
    710		u32 cur_bytes = cur_nolb * src_dev->dev_attrib.block_size;
    711
    712		if (cur_bytes != xop->xop_data_bytes) {
    713			/*
    714			 * (Re)allocate a buffer large enough to hold the XCOPY
    715			 * I/O size, which can be reused each read / write loop.
    716			 */
    717			target_free_sgl(xop->xop_data_sg, xop->xop_data_nents);
    718			rc = target_alloc_sgl(&xop->xop_data_sg,
    719					      &xop->xop_data_nents,
    720					      cur_bytes,
    721					      false, false);
    722			if (rc < 0)
    723				goto out;
    724			xop->xop_data_bytes = cur_bytes;
    725		}
    726
    727		pr_debug("target_xcopy_do_work: Calling read src_dev: %p src_lba: %llu,"
    728			" cur_nolb: %hu\n", src_dev, (unsigned long long)src_lba, cur_nolb);
    729
    730		rc = target_xcopy_read_source(ec_cmd, xop, src_dev, src_lba, cur_nolb);
    731		if (rc < 0)
    732			goto out;
    733
    734		src_lba += cur_nolb;
    735		pr_debug("target_xcopy_do_work: Incremented READ src_lba to %llu\n",
    736				(unsigned long long)src_lba);
    737
    738		pr_debug("target_xcopy_do_work: Calling write dst_dev: %p dst_lba: %llu,"
    739			" cur_nolb: %hu\n", dst_dev, (unsigned long long)dst_lba, cur_nolb);
    740
    741		rc = target_xcopy_write_destination(ec_cmd, xop, dst_dev,
    742						dst_lba, cur_nolb);
    743		if (rc < 0)
    744			goto out;
    745
    746		dst_lba += cur_nolb;
    747		pr_debug("target_xcopy_do_work: Incremented WRITE dst_lba to %llu\n",
    748				(unsigned long long)dst_lba);
    749
    750		copied_nolb += cur_nolb;
    751		nolb -= cur_nolb;
    752	}
    753
    754	xcopy_pt_undepend_remotedev(xop);
    755	target_free_sgl(xop->xop_data_sg, xop->xop_data_nents);
    756	kfree(xop);
    757
    758	pr_debug("target_xcopy_do_work: Final src_lba: %llu, dst_lba: %llu\n",
    759		(unsigned long long)src_lba, (unsigned long long)dst_lba);
    760	pr_debug("target_xcopy_do_work: Blocks copied: %hu, Bytes Copied: %u\n",
    761		copied_nolb, copied_nolb * dst_dev->dev_attrib.block_size);
    762
    763	pr_debug("target_xcopy_do_work: Setting X-COPY GOOD status -> sending response\n");
    764	target_complete_cmd(ec_cmd, SAM_STAT_GOOD);
    765	return;
    766
    767out:
    768	/*
    769	 * The XCOPY command was aborted after some data was transferred.
    770	 * Terminate command with CHECK CONDITION status, with the sense key
    771	 * set to COPY ABORTED.
    772	 */
    773	sense_rc = TCM_COPY_TARGET_DEVICE_NOT_REACHABLE;
    774	xcopy_pt_undepend_remotedev(xop);
    775	target_free_sgl(xop->xop_data_sg, xop->xop_data_nents);
    776
    777err_free:
    778	kfree(xop);
    779	pr_warn_ratelimited("target_xcopy_do_work: rc: %d, sense: %u, XCOPY operation failed\n",
    780			   rc, sense_rc);
    781	target_complete_cmd_with_sense(ec_cmd, SAM_STAT_CHECK_CONDITION, sense_rc);
    782}
    783
    784/*
    785 * Returns TCM_NO_SENSE upon success or a sense code != TCM_NO_SENSE if parsing
    786 * fails.
    787 */
    788static sense_reason_t target_parse_xcopy_cmd(struct xcopy_op *xop)
    789{
    790	struct se_cmd *se_cmd = xop->xop_se_cmd;
    791	unsigned char *p = NULL, *seg_desc;
    792	unsigned int list_id, list_id_usage, sdll, inline_dl;
    793	sense_reason_t ret = TCM_INVALID_PARAMETER_LIST;
    794	int rc;
    795	unsigned short tdll;
    796
    797	p = transport_kmap_data_sg(se_cmd);
    798	if (!p) {
    799		pr_err("transport_kmap_data_sg() failed in target_do_xcopy\n");
    800		return TCM_OUT_OF_RESOURCES;
    801	}
    802
    803	list_id = p[0];
    804	list_id_usage = (p[1] & 0x18) >> 3;
    805
    806	/*
    807	 * Determine TARGET DESCRIPTOR LIST LENGTH + SEGMENT DESCRIPTOR LIST LENGTH
    808	 */
    809	tdll = get_unaligned_be16(&p[2]);
    810	sdll = get_unaligned_be32(&p[8]);
    811	if (tdll + sdll > RCR_OP_MAX_DESC_LIST_LEN) {
    812		pr_err("XCOPY descriptor list length %u exceeds maximum %u\n",
    813		       tdll + sdll, RCR_OP_MAX_DESC_LIST_LEN);
    814		ret = TCM_PARAMETER_LIST_LENGTH_ERROR;
    815		goto out;
    816	}
    817
    818	inline_dl = get_unaligned_be32(&p[12]);
    819	if (inline_dl != 0) {
    820		pr_err("XCOPY with non zero inline data length\n");
    821		goto out;
    822	}
    823
    824	if (se_cmd->data_length < (XCOPY_HDR_LEN + tdll + sdll + inline_dl)) {
    825		pr_err("XCOPY parameter truncation: data length %u too small "
    826			"for tdll: %hu sdll: %u inline_dl: %u\n",
    827			se_cmd->data_length, tdll, sdll, inline_dl);
    828		ret = TCM_PARAMETER_LIST_LENGTH_ERROR;
    829		goto out;
    830	}
    831
    832	pr_debug("Processing XCOPY with list_id: 0x%02x list_id_usage: 0x%02x"
    833		" tdll: %hu sdll: %u inline_dl: %u\n", list_id, list_id_usage,
    834		tdll, sdll, inline_dl);
    835
    836	/*
    837	 * skip over the target descriptors until segment descriptors
    838	 * have been passed - CSCD ids are needed to determine src and dest.
    839	 */
    840	seg_desc = &p[16] + tdll;
    841
    842	rc = target_xcopy_parse_segment_descriptors(xop, seg_desc, sdll, &ret);
    843	if (rc <= 0)
    844		goto out;
    845
    846	pr_debug("XCOPY: Processed %d segment descriptors, length: %u\n", rc,
    847				rc * XCOPY_SEGMENT_DESC_LEN);
    848
    849	rc = target_xcopy_parse_target_descriptors(se_cmd, xop, &p[16], tdll, &ret);
    850	if (rc <= 0)
    851		goto out;
    852
    853	if (xop->src_dev->dev_attrib.block_size !=
    854	    xop->dst_dev->dev_attrib.block_size) {
    855		pr_err("XCOPY: Non matching src_dev block_size: %u + dst_dev"
    856		       " block_size: %u currently unsupported\n",
    857			xop->src_dev->dev_attrib.block_size,
    858			xop->dst_dev->dev_attrib.block_size);
    859		xcopy_pt_undepend_remotedev(xop);
    860		ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
    861		goto out;
    862	}
    863
    864	pr_debug("XCOPY: Processed %d target descriptors, length: %u\n", rc,
    865				rc * XCOPY_TARGET_DESC_LEN);
    866	transport_kunmap_data_sg(se_cmd);
    867	return TCM_NO_SENSE;
    868
    869out:
    870	if (p)
    871		transport_kunmap_data_sg(se_cmd);
    872	return ret;
    873}
    874
    875sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
    876{
    877	struct se_device *dev = se_cmd->se_dev;
    878	struct xcopy_op *xop;
    879	unsigned int sa;
    880
    881	if (!dev->dev_attrib.emulate_3pc) {
    882		pr_err("EXTENDED_COPY operation explicitly disabled\n");
    883		return TCM_UNSUPPORTED_SCSI_OPCODE;
    884	}
    885
    886	sa = se_cmd->t_task_cdb[1] & 0x1f;
    887	if (sa != 0x00) {
    888		pr_err("EXTENDED_COPY(LID4) not supported\n");
    889		return TCM_UNSUPPORTED_SCSI_OPCODE;
    890	}
    891
    892	if (se_cmd->data_length == 0) {
    893		target_complete_cmd(se_cmd, SAM_STAT_GOOD);
    894		return TCM_NO_SENSE;
    895	}
    896	if (se_cmd->data_length < XCOPY_HDR_LEN) {
    897		pr_err("XCOPY parameter truncation: length %u < hdr_len %u\n",
    898				se_cmd->data_length, XCOPY_HDR_LEN);
    899		return TCM_PARAMETER_LIST_LENGTH_ERROR;
    900	}
    901
    902	xop = kzalloc(sizeof(struct xcopy_op), GFP_KERNEL);
    903	if (!xop)
    904		goto err;
    905	xop->xop_se_cmd = se_cmd;
    906	INIT_WORK(&xop->xop_work, target_xcopy_do_work);
    907	if (WARN_ON_ONCE(!queue_work(xcopy_wq, &xop->xop_work)))
    908		goto free;
    909	return TCM_NO_SENSE;
    910
    911free:
    912	kfree(xop);
    913
    914err:
    915	return TCM_OUT_OF_RESOURCES;
    916}
    917
    918static sense_reason_t target_rcr_operating_parameters(struct se_cmd *se_cmd)
    919{
    920	unsigned char *p;
    921
    922	p = transport_kmap_data_sg(se_cmd);
    923	if (!p) {
    924		pr_err("transport_kmap_data_sg failed in"
    925		       " target_rcr_operating_parameters\n");
    926		return TCM_OUT_OF_RESOURCES;
    927	}
    928
    929	if (se_cmd->data_length < 54) {
    930		pr_err("Receive Copy Results Op Parameters length"
    931		       " too small: %u\n", se_cmd->data_length);
    932		transport_kunmap_data_sg(se_cmd);
    933		return TCM_INVALID_CDB_FIELD;
    934	}
    935	/*
    936	 * Set SNLID=1 (Supports no List ID)
    937	 */
    938	p[4] = 0x1;
    939	/*
    940	 * MAXIMUM TARGET DESCRIPTOR COUNT
    941	 */
    942	put_unaligned_be16(RCR_OP_MAX_TARGET_DESC_COUNT, &p[8]);
    943	/*
    944	 * MAXIMUM SEGMENT DESCRIPTOR COUNT
    945	 */
    946	put_unaligned_be16(RCR_OP_MAX_SG_DESC_COUNT, &p[10]);
    947	/*
    948	 * MAXIMUM DESCRIPTOR LIST LENGTH
    949	 */
    950	put_unaligned_be32(RCR_OP_MAX_DESC_LIST_LEN, &p[12]);
    951	/*
    952	 * MAXIMUM SEGMENT LENGTH
    953	 */
    954	put_unaligned_be32(RCR_OP_MAX_SEGMENT_LEN, &p[16]);
    955	/*
    956	 * MAXIMUM INLINE DATA LENGTH for SA 0x04 (NOT SUPPORTED)
    957	 */
    958	put_unaligned_be32(0x0, &p[20]);
    959	/*
    960	 * HELD DATA LIMIT
    961	 */
    962	put_unaligned_be32(0x0, &p[24]);
    963	/*
    964	 * MAXIMUM STREAM DEVICE TRANSFER SIZE
    965	 */
    966	put_unaligned_be32(0x0, &p[28]);
    967	/*
    968	 * TOTAL CONCURRENT COPIES
    969	 */
    970	put_unaligned_be16(RCR_OP_TOTAL_CONCURR_COPIES, &p[34]);
    971	/*
    972	 * MAXIMUM CONCURRENT COPIES
    973	 */
    974	p[36] = RCR_OP_MAX_CONCURR_COPIES;
    975	/*
    976	 * DATA SEGMENT GRANULARITY (log 2)
    977	 */
    978	p[37] = RCR_OP_DATA_SEG_GRAN_LOG2;
    979	/*
    980	 * INLINE DATA GRANULARITY log 2)
    981	 */
    982	p[38] = RCR_OP_INLINE_DATA_GRAN_LOG2;
    983	/*
    984	 * HELD DATA GRANULARITY
    985	 */
    986	p[39] = RCR_OP_HELD_DATA_GRAN_LOG2;
    987	/*
    988	 * IMPLEMENTED DESCRIPTOR LIST LENGTH
    989	 */
    990	p[43] = 0x2;
    991	/*
    992	 * List of implemented descriptor type codes (ordered)
    993	 */
    994	p[44] = 0x02; /* Copy Block to Block device */
    995	p[45] = 0xe4; /* Identification descriptor target descriptor */
    996
    997	/*
    998	 * AVAILABLE DATA (n-3)
    999	 */
   1000	put_unaligned_be32(42, &p[0]);
   1001
   1002	transport_kunmap_data_sg(se_cmd);
   1003	target_complete_cmd(se_cmd, SAM_STAT_GOOD);
   1004
   1005	return TCM_NO_SENSE;
   1006}
   1007
   1008sense_reason_t target_do_receive_copy_results(struct se_cmd *se_cmd)
   1009{
   1010	unsigned char *cdb = &se_cmd->t_task_cdb[0];
   1011	int sa = (cdb[1] & 0x1f), list_id = cdb[2];
   1012	sense_reason_t rc = TCM_NO_SENSE;
   1013
   1014	pr_debug("Entering target_do_receive_copy_results: SA: 0x%02x, List ID:"
   1015		" 0x%02x, AL: %u\n", sa, list_id, se_cmd->data_length);
   1016
   1017	if (list_id != 0) {
   1018		pr_err("Receive Copy Results with non zero list identifier"
   1019		       " not supported\n");
   1020		return TCM_INVALID_CDB_FIELD;
   1021	}
   1022
   1023	switch (sa) {
   1024	case RCR_SA_OPERATING_PARAMETERS:
   1025		rc = target_rcr_operating_parameters(se_cmd);
   1026		break;
   1027	case RCR_SA_COPY_STATUS:
   1028	case RCR_SA_RECEIVE_DATA:
   1029	case RCR_SA_FAILED_SEGMENT_DETAILS:
   1030	default:
   1031		pr_err("Unsupported SA for receive copy results: 0x%02x\n", sa);
   1032		return TCM_INVALID_CDB_FIELD;
   1033	}
   1034
   1035	return rc;
   1036}