// SPDX-License-Identifier: GPL-2.0-or-later /******************************************************************************* * Filename: target_core_xcopy.c * * This file contains support for SPC-4 Extended-Copy offload with generic * TCM backends. * * Copyright (c) 2011-2013 Datera, Inc. All rights reserved. * * Author: * Nicholas A. Bellinger <nab@daterainc.com> *
******************************************************************************/
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
*/ if (!memcmp(&xop->local_dev_wwn[0], &xop->src_tid_wwn[0],
XCOPY_NAA_IEEE_REGEX_LEN)) {
xop->op_origin = XCOL_SOURCE_RECV_OP;
xop->src_dev = se_cmd->se_dev;
pr_debug("XCOPY 0xe4: Set xop->src_dev %p from source" " received xop\n", xop->src_dev);
}
}
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. 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)) {
xop->op_origin = XCOL_DEST_RECV_OP;
xop->dst_dev = se_cmd->se_dev;
pr_debug("XCOPY 0xe4: Set xop->dst_dev: %p from destination" " received xop\n", xop->dst_dev);
}
}
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 > 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;
} /* * Generate an IEEE Registered Extended designator based upon the * se_device the XCOPY was received upon..
*/
memset(&xop->local_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN);
spc_gen_naa_6h_vendor_specific(local_dev, &xop->local_dev_wwn[0]);
while (start < tdll) { /* * 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], cscd_index); if (rc != 0) goto out;
start += XCOPY_TARGET_DESC_LEN;
desc += XCOPY_TARGET_DESC_LEN;
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;
}
}
switch (xop->op_origin) { case XCOL_SOURCE_RECV_OP:
rc = target_xcopy_locate_se_dev_e4(se_cmd->se_sess,
xop->dst_tid_wwn,
&xop->dst_dev,
&xop->remote_lun_ref); break; case XCOL_DEST_RECV_OP:
rc = target_xcopy_locate_se_dev_e4(se_cmd->se_sess,
xop->src_tid_wwn,
&xop->src_dev,
&xop->remote_lun_ref); 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 * 0x0d/0x02 - COPY_TARGET_DEVICE_NOT_REACHABLE to request the * initiator to fall back to normal copy method.
*/ if (rc < 0) {
*sense_ret = TCM_COPY_TARGET_DEVICE_NOT_REACHABLE; goto out;
}
void target_xcopy_release_pt(void)
{ if (xcopy_wq)
destroy_workqueue(xcopy_wq);
}
/* * target_xcopy_setup_pt_cmd - set up a pass-through command * @xpt_cmd: Data structure to initialize. * @xop: Describes the XCOPY operation received from an initiator. * @se_dev: Backend device to associate with @xpt_cmd if * @remote_port == true. * @cdb: SCSI CDB to be copied into @xpt_cmd. * @remote_port: If false, use the LUN through which the XCOPY command has * been received. If true, use @se_dev->xcopy_lun. * * Set up a SCSI command (READ or WRITE) that will be used to execute an * XCOPY command.
*/ staticint target_xcopy_setup_pt_cmd( struct xcopy_pt_cmd *xpt_cmd, struct xcopy_op *xop, struct se_device *se_dev, unsignedchar *cdb, bool remote_port)
{ struct se_cmd *cmd = &xpt_cmd->se_cmd;
/* * Setup LUN+port to honor reservations based upon xop->op_origin for * X-COPY PUSH or X-COPY PULL based upon where the CDB was received.
*/ if (remote_port) {
cmd->se_lun = &se_dev->xcopy_lun;
cmd->se_dev = se_dev;
} else {
cmd->se_lun = xop->xop_se_cmd->se_lun;
cmd->se_dev = xop->xop_se_cmd->se_dev;
}
cmd->se_cmd_flags |= SCF_SE_LUN_CMD;
if (target_cmd_init_cdb(cmd, cdb, GFP_KERNEL)) return -EINVAL;
cmd->tag = 0; if (target_cmd_parse_cdb(cmd)) return -EINVAL;
if (transport_generic_map_mem_to_cmd(cmd, xop->xop_data_sg,
xop->xop_data_nents, NULL, 0)) return -EINVAL;
/* * Using shift instead of the division because otherwise GCC * generates __udivdi3 that is missing on i386
*/
max_blocks = max_bytes >> ilog2(src_dev->dev_attrib.block_size);
if (cur_bytes != xop->xop_data_bytes) { /* * (Re)allocate a buffer large enough to hold the XCOPY * I/O size, which can be reused each read / write loop.
*/
target_free_sgl(xop->xop_data_sg, xop->xop_data_nents);
rc = target_alloc_sgl(&xop->xop_data_sg,
&xop->xop_data_nents,
cur_bytes, false, false); if (rc < 0) goto out;
xop->xop_data_bytes = cur_bytes;
}
pr_debug("%s: Setting X-COPY GOOD status -> sending response\n", __func__);
target_complete_cmd(ec_cmd, SAM_STAT_GOOD); return;
out: /* * The XCOPY command was aborted after some data was transferred. * Terminate command with CHECK CONDITION status, with the sense key * set to COPY ABORTED.
*/
sense_rc = TCM_COPY_TARGET_DEVICE_NOT_REACHABLE;
xcopy_pt_undepend_remotedev(xop);
target_free_sgl(xop->xop_data_sg, xop->xop_data_nents);
/* * 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;
pr_debug("Entering target_do_receive_copy_results: SA: 0x%02x, List ID:" " 0x%02x, AL: %u\n", sa, list_id, se_cmd->data_length);
if (list_id != 0) {
pr_err("Receive Copy Results with non zero list identifier" " not supported\n"); return TCM_INVALID_CDB_FIELD;
}
switch (sa) { case RCR_SA_OPERATING_PARAMETERS:
rc = target_rcr_operating_parameters(se_cmd); break; case RCR_SA_COPY_STATUS: case RCR_SA_RECEIVE_DATA: case RCR_SA_FAILED_SEGMENT_DETAILS: default:
pr_err("Unsupported SA for receive copy results: 0x%02x\n", sa); return TCM_INVALID_CDB_FIELD;
}
return rc;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.24 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.