Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*******************************************************************************
0003  * Filename: target_core_xcopy.c
0004  *
0005  * This file contains support for SPC-4 Extended-Copy offload with generic
0006  * TCM backends.
0007  *
0008  * Copyright (c) 2011-2013 Datera, Inc. All rights reserved.
0009  *
0010  * Author:
0011  * Nicholas A. Bellinger <nab@daterainc.com>
0012  *
0013  ******************************************************************************/
0014 
0015 #include <linux/slab.h>
0016 #include <linux/spinlock.h>
0017 #include <linux/list.h>
0018 #include <linux/configfs.h>
0019 #include <linux/ratelimit.h>
0020 #include <scsi/scsi_proto.h>
0021 #include <asm/unaligned.h>
0022 
0023 #include <target/target_core_base.h>
0024 #include <target/target_core_backend.h>
0025 #include <target/target_core_fabric.h>
0026 
0027 #include "target_core_internal.h"
0028 #include "target_core_pr.h"
0029 #include "target_core_ua.h"
0030 #include "target_core_xcopy.h"
0031 
0032 static struct workqueue_struct *xcopy_wq = NULL;
0033 
0034 static sense_reason_t target_parse_xcopy_cmd(struct xcopy_op *xop);
0035 
0036 /**
0037  * target_xcopy_locate_se_dev_e4_iter - compare XCOPY NAA device identifiers
0038  *
0039  * @se_dev: device being considered for match
0040  * @dev_wwn: XCOPY requested NAA dev_wwn
0041  * @return: 1 on match, 0 on no-match
0042  */
0043 static int target_xcopy_locate_se_dev_e4_iter(struct se_device *se_dev,
0044                           const unsigned char *dev_wwn)
0045 {
0046     unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN];
0047     int rc;
0048 
0049     if (!se_dev->dev_attrib.emulate_3pc) {
0050         pr_debug("XCOPY: emulate_3pc disabled on se_dev %p\n", se_dev);
0051         return 0;
0052     }
0053 
0054     memset(&tmp_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN);
0055     spc_gen_naa_6h_vendor_specific(se_dev, &tmp_dev_wwn[0]);
0056 
0057     rc = memcmp(&tmp_dev_wwn[0], dev_wwn, XCOPY_NAA_IEEE_REGEX_LEN);
0058     if (rc != 0) {
0059         pr_debug("XCOPY: skip non-matching: %*ph\n",
0060              XCOPY_NAA_IEEE_REGEX_LEN, tmp_dev_wwn);
0061         return 0;
0062     }
0063     pr_debug("XCOPY 0xe4: located se_dev: %p\n", se_dev);
0064 
0065     return 1;
0066 }
0067 
0068 static int target_xcopy_locate_se_dev_e4(struct se_session *sess,
0069                     const unsigned char *dev_wwn,
0070                     struct se_device **_found_dev,
0071                     struct percpu_ref **_found_lun_ref)
0072 {
0073     struct se_dev_entry *deve;
0074     struct se_node_acl *nacl;
0075     struct se_lun *this_lun = NULL;
0076     struct se_device *found_dev = NULL;
0077 
0078     /* cmd with NULL sess indicates no associated $FABRIC_MOD */
0079     if (!sess)
0080         goto err_out;
0081 
0082     pr_debug("XCOPY 0xe4: searching for: %*ph\n",
0083          XCOPY_NAA_IEEE_REGEX_LEN, dev_wwn);
0084 
0085     nacl = sess->se_node_acl;
0086     rcu_read_lock();
0087     hlist_for_each_entry_rcu(deve, &nacl->lun_entry_hlist, link) {
0088         struct se_device *this_dev;
0089         int rc;
0090 
0091         this_lun = deve->se_lun;
0092         this_dev = rcu_dereference_raw(this_lun->lun_se_dev);
0093 
0094         rc = target_xcopy_locate_se_dev_e4_iter(this_dev, dev_wwn);
0095         if (rc) {
0096             if (percpu_ref_tryget_live(&this_lun->lun_ref))
0097                 found_dev = this_dev;
0098             break;
0099         }
0100     }
0101     rcu_read_unlock();
0102     if (found_dev == NULL)
0103         goto err_out;
0104 
0105     pr_debug("lun_ref held for se_dev: %p se_dev->se_dev_group: %p\n",
0106          found_dev, &found_dev->dev_group);
0107     *_found_dev = found_dev;
0108     *_found_lun_ref = &this_lun->lun_ref;
0109     return 0;
0110 err_out:
0111     pr_debug_ratelimited("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n");
0112     return -EINVAL;
0113 }
0114 
0115 static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op *xop,
0116                 unsigned char *p, unsigned short cscd_index)
0117 {
0118     unsigned char *desc = p;
0119     unsigned short ript;
0120     u8 desig_len;
0121     /*
0122      * Extract RELATIVE INITIATOR PORT IDENTIFIER
0123      */
0124     ript = get_unaligned_be16(&desc[2]);
0125     pr_debug("XCOPY 0xe4: RELATIVE INITIATOR PORT IDENTIFIER: %hu\n", ript);
0126     /*
0127      * Check for supported code set, association, and designator type
0128      */
0129     if ((desc[4] & 0x0f) != 0x1) {
0130         pr_err("XCOPY 0xe4: code set of non binary type not supported\n");
0131         return -EINVAL;
0132     }
0133     if ((desc[5] & 0x30) != 0x00) {
0134         pr_err("XCOPY 0xe4: association other than LUN not supported\n");
0135         return -EINVAL;
0136     }
0137     if ((desc[5] & 0x0f) != 0x3) {
0138         pr_err("XCOPY 0xe4: designator type unsupported: 0x%02x\n",
0139                 (desc[5] & 0x0f));
0140         return -EINVAL;
0141     }
0142     /*
0143      * Check for matching 16 byte length for NAA IEEE Registered Extended
0144      * Assigned designator
0145      */
0146     desig_len = desc[7];
0147     if (desig_len != XCOPY_NAA_IEEE_REGEX_LEN) {
0148         pr_err("XCOPY 0xe4: invalid desig_len: %d\n", (int)desig_len);
0149         return -EINVAL;
0150     }
0151     pr_debug("XCOPY 0xe4: desig_len: %d\n", (int)desig_len);
0152     /*
0153      * Check for NAA IEEE Registered Extended Assigned header..
0154      */
0155     if ((desc[8] & 0xf0) != 0x60) {
0156         pr_err("XCOPY 0xe4: Unsupported DESIGNATOR TYPE: 0x%02x\n",
0157                     (desc[8] & 0xf0));
0158         return -EINVAL;
0159     }
0160 
0161     if (cscd_index != xop->stdi && cscd_index != xop->dtdi) {
0162         pr_debug("XCOPY 0xe4: ignoring CSCD entry %d - neither src nor "
0163              "dest\n", cscd_index);
0164         return 0;
0165     }
0166 
0167     if (cscd_index == xop->stdi) {
0168         memcpy(&xop->src_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN);
0169         /*
0170          * Determine if the source designator matches the local device
0171          */
0172         if (!memcmp(&xop->local_dev_wwn[0], &xop->src_tid_wwn[0],
0173                 XCOPY_NAA_IEEE_REGEX_LEN)) {
0174             xop->op_origin = XCOL_SOURCE_RECV_OP;
0175             xop->src_dev = se_cmd->se_dev;
0176             pr_debug("XCOPY 0xe4: Set xop->src_dev %p from source"
0177                     " received xop\n", xop->src_dev);
0178         }
0179     }
0180 
0181     if (cscd_index == xop->dtdi) {
0182         memcpy(&xop->dst_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN);
0183         /*
0184          * Determine if the destination designator matches the local
0185          * device. If @cscd_index corresponds to both source (stdi) and
0186          * destination (dtdi), or dtdi comes after stdi, then
0187          * XCOL_DEST_RECV_OP wins.
0188          */
0189         if (!memcmp(&xop->local_dev_wwn[0], &xop->dst_tid_wwn[0],
0190                 XCOPY_NAA_IEEE_REGEX_LEN)) {
0191             xop->op_origin = XCOL_DEST_RECV_OP;
0192             xop->dst_dev = se_cmd->se_dev;
0193             pr_debug("XCOPY 0xe4: Set xop->dst_dev: %p from destination"
0194                 " received xop\n", xop->dst_dev);
0195         }
0196     }
0197 
0198     return 0;
0199 }
0200 
0201 static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
0202                 struct xcopy_op *xop, unsigned char *p,
0203                 unsigned short tdll, sense_reason_t *sense_ret)
0204 {
0205     struct se_device *local_dev = se_cmd->se_dev;
0206     unsigned char *desc = p;
0207     int offset = tdll % XCOPY_TARGET_DESC_LEN, rc;
0208     unsigned short cscd_index = 0;
0209     unsigned short start = 0;
0210 
0211     *sense_ret = TCM_INVALID_PARAMETER_LIST;
0212 
0213     if (offset != 0) {
0214         pr_err("XCOPY target descriptor list length is not"
0215             " multiple of %d\n", XCOPY_TARGET_DESC_LEN);
0216         *sense_ret = TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE;
0217         return -EINVAL;
0218     }
0219     if (tdll > RCR_OP_MAX_TARGET_DESC_COUNT * XCOPY_TARGET_DESC_LEN) {
0220         pr_err("XCOPY target descriptor supports a maximum"
0221             " two src/dest descriptors, tdll: %hu too large..\n", tdll);
0222         /* spc4r37 6.4.3.4 CSCD DESCRIPTOR LIST LENGTH field */
0223         *sense_ret = TCM_TOO_MANY_TARGET_DESCS;
0224         return -EINVAL;
0225     }
0226     /*
0227      * Generate an IEEE Registered Extended designator based upon the
0228      * se_device the XCOPY was received upon..
0229      */
0230     memset(&xop->local_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN);
0231     spc_gen_naa_6h_vendor_specific(local_dev, &xop->local_dev_wwn[0]);
0232 
0233     while (start < tdll) {
0234         /*
0235          * Check target descriptor identification with 0xE4 type, and
0236          * compare the current index with the CSCD descriptor IDs in
0237          * the segment descriptor. Use VPD 0x83 WWPN matching ..
0238          */
0239         switch (desc[0]) {
0240         case 0xe4:
0241             rc = target_xcopy_parse_tiddesc_e4(se_cmd, xop,
0242                             &desc[0], cscd_index);
0243             if (rc != 0)
0244                 goto out;
0245             start += XCOPY_TARGET_DESC_LEN;
0246             desc += XCOPY_TARGET_DESC_LEN;
0247             cscd_index++;
0248             break;
0249         default:
0250             pr_err("XCOPY unsupported descriptor type code:"
0251                     " 0x%02x\n", desc[0]);
0252             *sense_ret = TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE;
0253             goto out;
0254         }
0255     }
0256 
0257     switch (xop->op_origin) {
0258     case XCOL_SOURCE_RECV_OP:
0259         rc = target_xcopy_locate_se_dev_e4(se_cmd->se_sess,
0260                         xop->dst_tid_wwn,
0261                         &xop->dst_dev,
0262                         &xop->remote_lun_ref);
0263         break;
0264     case XCOL_DEST_RECV_OP:
0265         rc = target_xcopy_locate_se_dev_e4(se_cmd->se_sess,
0266                         xop->src_tid_wwn,
0267                         &xop->src_dev,
0268                         &xop->remote_lun_ref);
0269         break;
0270     default:
0271         pr_err("XCOPY CSCD descriptor IDs not found in CSCD list - "
0272             "stdi: %hu dtdi: %hu\n", xop->stdi, xop->dtdi);
0273         rc = -EINVAL;
0274         break;
0275     }
0276     /*
0277      * If a matching IEEE NAA 0x83 descriptor for the requested device
0278      * is not located on this node, return COPY_ABORTED with ASQ/ASQC
0279      * 0x0d/0x02 - COPY_TARGET_DEVICE_NOT_REACHABLE to request the
0280      * initiator to fall back to normal copy method.
0281      */
0282     if (rc < 0) {
0283         *sense_ret = TCM_COPY_TARGET_DEVICE_NOT_REACHABLE;
0284         goto out;
0285     }
0286 
0287     pr_debug("XCOPY TGT desc: Source dev: %p NAA IEEE WWN: 0x%16phN\n",
0288          xop->src_dev, &xop->src_tid_wwn[0]);
0289     pr_debug("XCOPY TGT desc: Dest dev: %p NAA IEEE WWN: 0x%16phN\n",
0290          xop->dst_dev, &xop->dst_tid_wwn[0]);
0291 
0292     return cscd_index;
0293 
0294 out:
0295     return -EINVAL;
0296 }
0297 
0298 static int target_xcopy_parse_segdesc_02(struct xcopy_op *xop, unsigned char *p)
0299 {
0300     unsigned char *desc = p;
0301     int dc = (desc[1] & 0x02);
0302     unsigned short desc_len;
0303 
0304     desc_len = get_unaligned_be16(&desc[2]);
0305     if (desc_len != 0x18) {
0306         pr_err("XCOPY segment desc 0x02: Illegal desc_len:"
0307                 " %hu\n", desc_len);
0308         return -EINVAL;
0309     }
0310 
0311     xop->stdi = get_unaligned_be16(&desc[4]);
0312     xop->dtdi = get_unaligned_be16(&desc[6]);
0313 
0314     if (xop->stdi > XCOPY_CSCD_DESC_ID_LIST_OFF_MAX ||
0315         xop->dtdi > XCOPY_CSCD_DESC_ID_LIST_OFF_MAX) {
0316         pr_err("XCOPY segment desc 0x02: unsupported CSCD ID > 0x%x; stdi: %hu dtdi: %hu\n",
0317             XCOPY_CSCD_DESC_ID_LIST_OFF_MAX, xop->stdi, xop->dtdi);
0318         return -EINVAL;
0319     }
0320 
0321     pr_debug("XCOPY seg desc 0x02: desc_len: %hu stdi: %hu dtdi: %hu, DC: %d\n",
0322         desc_len, xop->stdi, xop->dtdi, dc);
0323 
0324     xop->nolb = get_unaligned_be16(&desc[10]);
0325     xop->src_lba = get_unaligned_be64(&desc[12]);
0326     xop->dst_lba = get_unaligned_be64(&desc[20]);
0327     pr_debug("XCOPY seg desc 0x02: nolb: %hu src_lba: %llu dst_lba: %llu\n",
0328         xop->nolb, (unsigned long long)xop->src_lba,
0329         (unsigned long long)xop->dst_lba);
0330 
0331     return 0;
0332 }
0333 
0334 static int target_xcopy_parse_segment_descriptors(struct xcopy_op *xop,
0335                 unsigned char *p, unsigned int sdll,
0336                 sense_reason_t *sense_ret)
0337 {
0338     unsigned char *desc = p;
0339     unsigned int start = 0;
0340     int offset = sdll % XCOPY_SEGMENT_DESC_LEN, rc, ret = 0;
0341 
0342     *sense_ret = TCM_INVALID_PARAMETER_LIST;
0343 
0344     if (offset != 0) {
0345         pr_err("XCOPY segment descriptor list length is not"
0346             " multiple of %d\n", XCOPY_SEGMENT_DESC_LEN);
0347         *sense_ret = TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE;
0348         return -EINVAL;
0349     }
0350     if (sdll > RCR_OP_MAX_SG_DESC_COUNT * XCOPY_SEGMENT_DESC_LEN) {
0351         pr_err("XCOPY supports %u segment descriptor(s), sdll: %u too"
0352             " large..\n", RCR_OP_MAX_SG_DESC_COUNT, sdll);
0353         /* spc4r37 6.4.3.5 SEGMENT DESCRIPTOR LIST LENGTH field */
0354         *sense_ret = TCM_TOO_MANY_SEGMENT_DESCS;
0355         return -EINVAL;
0356     }
0357 
0358     while (start < sdll) {
0359         /*
0360          * Check segment descriptor type code for block -> block
0361          */
0362         switch (desc[0]) {
0363         case 0x02:
0364             rc = target_xcopy_parse_segdesc_02(xop, desc);
0365             if (rc < 0)
0366                 goto out;
0367 
0368             ret++;
0369             start += XCOPY_SEGMENT_DESC_LEN;
0370             desc += XCOPY_SEGMENT_DESC_LEN;
0371             break;
0372         default:
0373             pr_err("XCOPY unsupported segment descriptor"
0374                 "type: 0x%02x\n", desc[0]);
0375             *sense_ret = TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE;
0376             goto out;
0377         }
0378     }
0379 
0380     return ret;
0381 
0382 out:
0383     return -EINVAL;
0384 }
0385 
0386 /*
0387  * Start xcopy_pt ops
0388  */
0389 
0390 struct xcopy_pt_cmd {
0391     struct se_cmd se_cmd;
0392     struct completion xpt_passthrough_sem;
0393     unsigned char sense_buffer[TRANSPORT_SENSE_BUFFER];
0394 };
0395 
0396 struct se_portal_group xcopy_pt_tpg;
0397 static struct se_session xcopy_pt_sess;
0398 static struct se_node_acl xcopy_pt_nacl;
0399 
0400 static int xcopy_pt_get_cmd_state(struct se_cmd *se_cmd)
0401 {
0402         return 0;
0403 }
0404 
0405 static void xcopy_pt_undepend_remotedev(struct xcopy_op *xop)
0406 {
0407     if (xop->op_origin == XCOL_SOURCE_RECV_OP)
0408         pr_debug("putting dst lun_ref for %p\n", xop->dst_dev);
0409     else
0410         pr_debug("putting src lun_ref for %p\n", xop->src_dev);
0411 
0412     percpu_ref_put(xop->remote_lun_ref);
0413 }
0414 
0415 static void xcopy_pt_release_cmd(struct se_cmd *se_cmd)
0416 {
0417     struct xcopy_pt_cmd *xpt_cmd = container_of(se_cmd,
0418                 struct xcopy_pt_cmd, se_cmd);
0419 
0420     /* xpt_cmd is on the stack, nothing to free here */
0421     pr_debug("xpt_cmd done: %p\n", xpt_cmd);
0422 }
0423 
0424 static int xcopy_pt_check_stop_free(struct se_cmd *se_cmd)
0425 {
0426     struct xcopy_pt_cmd *xpt_cmd = container_of(se_cmd,
0427                 struct xcopy_pt_cmd, se_cmd);
0428 
0429     complete(&xpt_cmd->xpt_passthrough_sem);
0430     return 0;
0431 }
0432 
0433 static int xcopy_pt_write_pending(struct se_cmd *se_cmd)
0434 {
0435     return 0;
0436 }
0437 
0438 static int xcopy_pt_queue_data_in(struct se_cmd *se_cmd)
0439 {
0440     return 0;
0441 }
0442 
0443 static int xcopy_pt_queue_status(struct se_cmd *se_cmd)
0444 {
0445     return 0;
0446 }
0447 
0448 static const struct target_core_fabric_ops xcopy_pt_tfo = {
0449     .fabric_name        = "xcopy-pt",
0450     .get_cmd_state      = xcopy_pt_get_cmd_state,
0451     .release_cmd        = xcopy_pt_release_cmd,
0452     .check_stop_free    = xcopy_pt_check_stop_free,
0453     .write_pending      = xcopy_pt_write_pending,
0454     .queue_data_in      = xcopy_pt_queue_data_in,
0455     .queue_status       = xcopy_pt_queue_status,
0456 };
0457 
0458 /*
0459  * End xcopy_pt_ops
0460  */
0461 
0462 int target_xcopy_setup_pt(void)
0463 {
0464     int ret;
0465 
0466     xcopy_wq = alloc_workqueue("xcopy_wq", WQ_MEM_RECLAIM, 0);
0467     if (!xcopy_wq) {
0468         pr_err("Unable to allocate xcopy_wq\n");
0469         return -ENOMEM;
0470     }
0471 
0472     memset(&xcopy_pt_tpg, 0, sizeof(struct se_portal_group));
0473     INIT_LIST_HEAD(&xcopy_pt_tpg.acl_node_list);
0474     INIT_LIST_HEAD(&xcopy_pt_tpg.tpg_sess_list);
0475 
0476     xcopy_pt_tpg.se_tpg_tfo = &xcopy_pt_tfo;
0477 
0478     memset(&xcopy_pt_nacl, 0, sizeof(struct se_node_acl));
0479     INIT_LIST_HEAD(&xcopy_pt_nacl.acl_list);
0480     INIT_LIST_HEAD(&xcopy_pt_nacl.acl_sess_list);
0481     memset(&xcopy_pt_sess, 0, sizeof(struct se_session));
0482     ret = transport_init_session(&xcopy_pt_sess);
0483     if (ret < 0)
0484         goto destroy_wq;
0485 
0486     xcopy_pt_nacl.se_tpg = &xcopy_pt_tpg;
0487     xcopy_pt_nacl.nacl_sess = &xcopy_pt_sess;
0488 
0489     xcopy_pt_sess.se_tpg = &xcopy_pt_tpg;
0490     xcopy_pt_sess.se_node_acl = &xcopy_pt_nacl;
0491 
0492     return 0;
0493 
0494 destroy_wq:
0495     destroy_workqueue(xcopy_wq);
0496     xcopy_wq = NULL;
0497     return ret;
0498 }
0499 
0500 void target_xcopy_release_pt(void)
0501 {
0502     if (xcopy_wq) {
0503         destroy_workqueue(xcopy_wq);
0504         transport_uninit_session(&xcopy_pt_sess);
0505     }
0506 }
0507 
0508 /*
0509  * target_xcopy_setup_pt_cmd - set up a pass-through command
0510  * @xpt_cmd:     Data structure to initialize.
0511  * @xop:     Describes the XCOPY operation received from an initiator.
0512  * @se_dev:  Backend device to associate with @xpt_cmd if
0513  *       @remote_port == true.
0514  * @cdb:     SCSI CDB to be copied into @xpt_cmd.
0515  * @remote_port: If false, use the LUN through which the XCOPY command has
0516  *       been received. If true, use @se_dev->xcopy_lun.
0517  *
0518  * Set up a SCSI command (READ or WRITE) that will be used to execute an
0519  * XCOPY command.
0520  */
0521 static int target_xcopy_setup_pt_cmd(
0522     struct xcopy_pt_cmd *xpt_cmd,
0523     struct xcopy_op *xop,
0524     struct se_device *se_dev,
0525     unsigned char *cdb,
0526     bool remote_port)
0527 {
0528     struct se_cmd *cmd = &xpt_cmd->se_cmd;
0529 
0530     /*
0531      * Setup LUN+port to honor reservations based upon xop->op_origin for
0532      * X-COPY PUSH or X-COPY PULL based upon where the CDB was received.
0533      */
0534     if (remote_port) {
0535         cmd->se_lun = &se_dev->xcopy_lun;
0536         cmd->se_dev = se_dev;
0537     } else {
0538         cmd->se_lun = xop->xop_se_cmd->se_lun;
0539         cmd->se_dev = xop->xop_se_cmd->se_dev;
0540     }
0541     cmd->se_cmd_flags |= SCF_SE_LUN_CMD;
0542 
0543     if (target_cmd_init_cdb(cmd, cdb, GFP_KERNEL))
0544         return -EINVAL;
0545 
0546     cmd->tag = 0;
0547     if (target_cmd_parse_cdb(cmd))
0548         return -EINVAL;
0549 
0550     if (transport_generic_map_mem_to_cmd(cmd, xop->xop_data_sg,
0551                     xop->xop_data_nents, NULL, 0))
0552         return -EINVAL;
0553 
0554     pr_debug("Setup PASSTHROUGH_NOALLOC t_data_sg: %p t_data_nents:"
0555          " %u\n", cmd->t_data_sg, cmd->t_data_nents);
0556 
0557     return 0;
0558 }
0559 
0560 static int target_xcopy_issue_pt_cmd(struct xcopy_pt_cmd *xpt_cmd)
0561 {
0562     struct se_cmd *se_cmd = &xpt_cmd->se_cmd;
0563     sense_reason_t sense_rc;
0564 
0565     sense_rc = transport_generic_new_cmd(se_cmd);
0566     if (sense_rc)
0567         return -EINVAL;
0568 
0569     if (se_cmd->data_direction == DMA_TO_DEVICE)
0570         target_execute_cmd(se_cmd);
0571 
0572     wait_for_completion_interruptible(&xpt_cmd->xpt_passthrough_sem);
0573 
0574     pr_debug("target_xcopy_issue_pt_cmd(): SCSI status: 0x%02x\n",
0575             se_cmd->scsi_status);
0576 
0577     return (se_cmd->scsi_status) ? -EINVAL : 0;
0578 }
0579 
0580 static int target_xcopy_read_source(
0581     struct se_cmd *ec_cmd,
0582     struct xcopy_op *xop,
0583     struct se_device *src_dev,
0584     sector_t src_lba,
0585     u32 src_sectors)
0586 {
0587     struct xcopy_pt_cmd xpt_cmd;
0588     struct se_cmd *se_cmd = &xpt_cmd.se_cmd;
0589     u32 length = (src_sectors * src_dev->dev_attrib.block_size);
0590     int rc;
0591     unsigned char cdb[16];
0592     bool remote_port = (xop->op_origin == XCOL_DEST_RECV_OP);
0593 
0594     memset(&xpt_cmd, 0, sizeof(xpt_cmd));
0595     init_completion(&xpt_cmd.xpt_passthrough_sem);
0596 
0597     memset(&cdb[0], 0, 16);
0598     cdb[0] = READ_16;
0599     put_unaligned_be64(src_lba, &cdb[2]);
0600     put_unaligned_be32(src_sectors, &cdb[10]);
0601     pr_debug("XCOPY: Built READ_16: LBA: %llu Sectors: %u Length: %u\n",
0602         (unsigned long long)src_lba, src_sectors, length);
0603 
0604     __target_init_cmd(se_cmd, &xcopy_pt_tfo, &xcopy_pt_sess, length,
0605               DMA_FROM_DEVICE, 0, &xpt_cmd.sense_buffer[0], 0);
0606 
0607     rc = target_xcopy_setup_pt_cmd(&xpt_cmd, xop, src_dev, &cdb[0],
0608                 remote_port);
0609     if (rc < 0) {
0610         ec_cmd->scsi_status = se_cmd->scsi_status;
0611         goto out;
0612     }
0613 
0614     pr_debug("XCOPY-READ: Saved xop->xop_data_sg: %p, num: %u for READ"
0615         " memory\n", xop->xop_data_sg, xop->xop_data_nents);
0616 
0617     rc = target_xcopy_issue_pt_cmd(&xpt_cmd);
0618     if (rc < 0)
0619         ec_cmd->scsi_status = se_cmd->scsi_status;
0620 out:
0621     transport_generic_free_cmd(se_cmd, 0);
0622     return rc;
0623 }
0624 
0625 static int target_xcopy_write_destination(
0626     struct se_cmd *ec_cmd,
0627     struct xcopy_op *xop,
0628     struct se_device *dst_dev,
0629     sector_t dst_lba,
0630     u32 dst_sectors)
0631 {
0632     struct xcopy_pt_cmd xpt_cmd;
0633     struct se_cmd *se_cmd = &xpt_cmd.se_cmd;
0634     u32 length = (dst_sectors * dst_dev->dev_attrib.block_size);
0635     int rc;
0636     unsigned char cdb[16];
0637     bool remote_port = (xop->op_origin == XCOL_SOURCE_RECV_OP);
0638 
0639     memset(&xpt_cmd, 0, sizeof(xpt_cmd));
0640     init_completion(&xpt_cmd.xpt_passthrough_sem);
0641 
0642     memset(&cdb[0], 0, 16);
0643     cdb[0] = WRITE_16;
0644     put_unaligned_be64(dst_lba, &cdb[2]);
0645     put_unaligned_be32(dst_sectors, &cdb[10]);
0646     pr_debug("XCOPY: Built WRITE_16: LBA: %llu Sectors: %u Length: %u\n",
0647         (unsigned long long)dst_lba, dst_sectors, length);
0648 
0649     __target_init_cmd(se_cmd, &xcopy_pt_tfo, &xcopy_pt_sess, length,
0650               DMA_TO_DEVICE, 0, &xpt_cmd.sense_buffer[0], 0);
0651 
0652     rc = target_xcopy_setup_pt_cmd(&xpt_cmd, xop, dst_dev, &cdb[0],
0653                 remote_port);
0654     if (rc < 0) {
0655         ec_cmd->scsi_status = se_cmd->scsi_status;
0656         goto out;
0657     }
0658 
0659     rc = target_xcopy_issue_pt_cmd(&xpt_cmd);
0660     if (rc < 0)
0661         ec_cmd->scsi_status = se_cmd->scsi_status;
0662 out:
0663     transport_generic_free_cmd(se_cmd, 0);
0664     return rc;
0665 }
0666 
0667 static void target_xcopy_do_work(struct work_struct *work)
0668 {
0669     struct xcopy_op *xop = container_of(work, struct xcopy_op, xop_work);
0670     struct se_cmd *ec_cmd = xop->xop_se_cmd;
0671     struct se_device *src_dev, *dst_dev;
0672     sector_t src_lba, dst_lba, end_lba;
0673     unsigned int max_sectors;
0674     int rc = 0;
0675     unsigned short nolb, max_nolb, copied_nolb = 0;
0676     sense_reason_t sense_rc;
0677 
0678     sense_rc = target_parse_xcopy_cmd(xop);
0679     if (sense_rc != TCM_NO_SENSE)
0680         goto err_free;
0681 
0682     if (WARN_ON_ONCE(!xop->src_dev) || WARN_ON_ONCE(!xop->dst_dev)) {
0683         sense_rc = TCM_INVALID_PARAMETER_LIST;
0684         goto err_free;
0685     }
0686 
0687     src_dev = xop->src_dev;
0688     dst_dev = xop->dst_dev;
0689     src_lba = xop->src_lba;
0690     dst_lba = xop->dst_lba;
0691     nolb = xop->nolb;
0692     end_lba = src_lba + nolb;
0693     /*
0694      * Break up XCOPY I/O into hw_max_sectors sized I/O based on the
0695      * smallest max_sectors between src_dev + dev_dev, or
0696      */
0697     max_sectors = min(src_dev->dev_attrib.hw_max_sectors,
0698               dst_dev->dev_attrib.hw_max_sectors);
0699     max_sectors = min_t(u32, max_sectors, XCOPY_MAX_SECTORS);
0700 
0701     max_nolb = min_t(u16, max_sectors, ((u16)(~0U)));
0702 
0703     pr_debug("target_xcopy_do_work: nolb: %hu, max_nolb: %hu end_lba: %llu\n",
0704             nolb, max_nolb, (unsigned long long)end_lba);
0705     pr_debug("target_xcopy_do_work: Starting src_lba: %llu, dst_lba: %llu\n",
0706             (unsigned long long)src_lba, (unsigned long long)dst_lba);
0707 
0708     while (src_lba < end_lba) {
0709         unsigned short cur_nolb = min(nolb, max_nolb);
0710         u32 cur_bytes = cur_nolb * src_dev->dev_attrib.block_size;
0711 
0712         if (cur_bytes != xop->xop_data_bytes) {
0713             /*
0714              * (Re)allocate a buffer large enough to hold the XCOPY
0715              * I/O size, which can be reused each read / write loop.
0716              */
0717             target_free_sgl(xop->xop_data_sg, xop->xop_data_nents);
0718             rc = target_alloc_sgl(&xop->xop_data_sg,
0719                           &xop->xop_data_nents,
0720                           cur_bytes,
0721                           false, false);
0722             if (rc < 0)
0723                 goto out;
0724             xop->xop_data_bytes = cur_bytes;
0725         }
0726 
0727         pr_debug("target_xcopy_do_work: Calling read src_dev: %p src_lba: %llu,"
0728             " cur_nolb: %hu\n", src_dev, (unsigned long long)src_lba, cur_nolb);
0729 
0730         rc = target_xcopy_read_source(ec_cmd, xop, src_dev, src_lba, cur_nolb);
0731         if (rc < 0)
0732             goto out;
0733 
0734         src_lba += cur_nolb;
0735         pr_debug("target_xcopy_do_work: Incremented READ src_lba to %llu\n",
0736                 (unsigned long long)src_lba);
0737 
0738         pr_debug("target_xcopy_do_work: Calling write dst_dev: %p dst_lba: %llu,"
0739             " cur_nolb: %hu\n", dst_dev, (unsigned long long)dst_lba, cur_nolb);
0740 
0741         rc = target_xcopy_write_destination(ec_cmd, xop, dst_dev,
0742                         dst_lba, cur_nolb);
0743         if (rc < 0)
0744             goto out;
0745 
0746         dst_lba += cur_nolb;
0747         pr_debug("target_xcopy_do_work: Incremented WRITE dst_lba to %llu\n",
0748                 (unsigned long long)dst_lba);
0749 
0750         copied_nolb += cur_nolb;
0751         nolb -= cur_nolb;
0752     }
0753 
0754     xcopy_pt_undepend_remotedev(xop);
0755     target_free_sgl(xop->xop_data_sg, xop->xop_data_nents);
0756     kfree(xop);
0757 
0758     pr_debug("target_xcopy_do_work: Final src_lba: %llu, dst_lba: %llu\n",
0759         (unsigned long long)src_lba, (unsigned long long)dst_lba);
0760     pr_debug("target_xcopy_do_work: Blocks copied: %hu, Bytes Copied: %u\n",
0761         copied_nolb, copied_nolb * dst_dev->dev_attrib.block_size);
0762 
0763     pr_debug("target_xcopy_do_work: Setting X-COPY GOOD status -> sending response\n");
0764     target_complete_cmd(ec_cmd, SAM_STAT_GOOD);
0765     return;
0766 
0767 out:
0768     /*
0769      * The XCOPY command was aborted after some data was transferred.
0770      * Terminate command with CHECK CONDITION status, with the sense key
0771      * set to COPY ABORTED.
0772      */
0773     sense_rc = TCM_COPY_TARGET_DEVICE_NOT_REACHABLE;
0774     xcopy_pt_undepend_remotedev(xop);
0775     target_free_sgl(xop->xop_data_sg, xop->xop_data_nents);
0776 
0777 err_free:
0778     kfree(xop);
0779     pr_warn_ratelimited("target_xcopy_do_work: rc: %d, sense: %u, XCOPY operation failed\n",
0780                rc, sense_rc);
0781     target_complete_cmd_with_sense(ec_cmd, SAM_STAT_CHECK_CONDITION, sense_rc);
0782 }
0783 
0784 /*
0785  * Returns TCM_NO_SENSE upon success or a sense code != TCM_NO_SENSE if parsing
0786  * fails.
0787  */
0788 static sense_reason_t target_parse_xcopy_cmd(struct xcopy_op *xop)
0789 {
0790     struct se_cmd *se_cmd = xop->xop_se_cmd;
0791     unsigned char *p = NULL, *seg_desc;
0792     unsigned int list_id, list_id_usage, sdll, inline_dl;
0793     sense_reason_t ret = TCM_INVALID_PARAMETER_LIST;
0794     int rc;
0795     unsigned short tdll;
0796 
0797     p = transport_kmap_data_sg(se_cmd);
0798     if (!p) {
0799         pr_err("transport_kmap_data_sg() failed in target_do_xcopy\n");
0800         return TCM_OUT_OF_RESOURCES;
0801     }
0802 
0803     list_id = p[0];
0804     list_id_usage = (p[1] & 0x18) >> 3;
0805 
0806     /*
0807      * Determine TARGET DESCRIPTOR LIST LENGTH + SEGMENT DESCRIPTOR LIST LENGTH
0808      */
0809     tdll = get_unaligned_be16(&p[2]);
0810     sdll = get_unaligned_be32(&p[8]);
0811     if (tdll + sdll > RCR_OP_MAX_DESC_LIST_LEN) {
0812         pr_err("XCOPY descriptor list length %u exceeds maximum %u\n",
0813                tdll + sdll, RCR_OP_MAX_DESC_LIST_LEN);
0814         ret = TCM_PARAMETER_LIST_LENGTH_ERROR;
0815         goto out;
0816     }
0817 
0818     inline_dl = get_unaligned_be32(&p[12]);
0819     if (inline_dl != 0) {
0820         pr_err("XCOPY with non zero inline data length\n");
0821         goto out;
0822     }
0823 
0824     if (se_cmd->data_length < (XCOPY_HDR_LEN + tdll + sdll + inline_dl)) {
0825         pr_err("XCOPY parameter truncation: data length %u too small "
0826             "for tdll: %hu sdll: %u inline_dl: %u\n",
0827             se_cmd->data_length, tdll, sdll, inline_dl);
0828         ret = TCM_PARAMETER_LIST_LENGTH_ERROR;
0829         goto out;
0830     }
0831 
0832     pr_debug("Processing XCOPY with list_id: 0x%02x list_id_usage: 0x%02x"
0833         " tdll: %hu sdll: %u inline_dl: %u\n", list_id, list_id_usage,
0834         tdll, sdll, inline_dl);
0835 
0836     /*
0837      * skip over the target descriptors until segment descriptors
0838      * have been passed - CSCD ids are needed to determine src and dest.
0839      */
0840     seg_desc = &p[16] + tdll;
0841 
0842     rc = target_xcopy_parse_segment_descriptors(xop, seg_desc, sdll, &ret);
0843     if (rc <= 0)
0844         goto out;
0845 
0846     pr_debug("XCOPY: Processed %d segment descriptors, length: %u\n", rc,
0847                 rc * XCOPY_SEGMENT_DESC_LEN);
0848 
0849     rc = target_xcopy_parse_target_descriptors(se_cmd, xop, &p[16], tdll, &ret);
0850     if (rc <= 0)
0851         goto out;
0852 
0853     if (xop->src_dev->dev_attrib.block_size !=
0854         xop->dst_dev->dev_attrib.block_size) {
0855         pr_err("XCOPY: Non matching src_dev block_size: %u + dst_dev"
0856                " block_size: %u currently unsupported\n",
0857             xop->src_dev->dev_attrib.block_size,
0858             xop->dst_dev->dev_attrib.block_size);
0859         xcopy_pt_undepend_remotedev(xop);
0860         ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
0861         goto out;
0862     }
0863 
0864     pr_debug("XCOPY: Processed %d target descriptors, length: %u\n", rc,
0865                 rc * XCOPY_TARGET_DESC_LEN);
0866     transport_kunmap_data_sg(se_cmd);
0867     return TCM_NO_SENSE;
0868 
0869 out:
0870     if (p)
0871         transport_kunmap_data_sg(se_cmd);
0872     return ret;
0873 }
0874 
0875 sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
0876 {
0877     struct se_device *dev = se_cmd->se_dev;
0878     struct xcopy_op *xop;
0879     unsigned int sa;
0880 
0881     if (!dev->dev_attrib.emulate_3pc) {
0882         pr_err("EXTENDED_COPY operation explicitly disabled\n");
0883         return TCM_UNSUPPORTED_SCSI_OPCODE;
0884     }
0885 
0886     sa = se_cmd->t_task_cdb[1] & 0x1f;
0887     if (sa != 0x00) {
0888         pr_err("EXTENDED_COPY(LID4) not supported\n");
0889         return TCM_UNSUPPORTED_SCSI_OPCODE;
0890     }
0891 
0892     if (se_cmd->data_length == 0) {
0893         target_complete_cmd(se_cmd, SAM_STAT_GOOD);
0894         return TCM_NO_SENSE;
0895     }
0896     if (se_cmd->data_length < XCOPY_HDR_LEN) {
0897         pr_err("XCOPY parameter truncation: length %u < hdr_len %u\n",
0898                 se_cmd->data_length, XCOPY_HDR_LEN);
0899         return TCM_PARAMETER_LIST_LENGTH_ERROR;
0900     }
0901 
0902     xop = kzalloc(sizeof(struct xcopy_op), GFP_KERNEL);
0903     if (!xop)
0904         goto err;
0905     xop->xop_se_cmd = se_cmd;
0906     INIT_WORK(&xop->xop_work, target_xcopy_do_work);
0907     if (WARN_ON_ONCE(!queue_work(xcopy_wq, &xop->xop_work)))
0908         goto free;
0909     return TCM_NO_SENSE;
0910 
0911 free:
0912     kfree(xop);
0913 
0914 err:
0915     return TCM_OUT_OF_RESOURCES;
0916 }
0917 
0918 static sense_reason_t target_rcr_operating_parameters(struct se_cmd *se_cmd)
0919 {
0920     unsigned char *p;
0921 
0922     p = transport_kmap_data_sg(se_cmd);
0923     if (!p) {
0924         pr_err("transport_kmap_data_sg failed in"
0925                " target_rcr_operating_parameters\n");
0926         return TCM_OUT_OF_RESOURCES;
0927     }
0928 
0929     if (se_cmd->data_length < 54) {
0930         pr_err("Receive Copy Results Op Parameters length"
0931                " too small: %u\n", se_cmd->data_length);
0932         transport_kunmap_data_sg(se_cmd);
0933         return TCM_INVALID_CDB_FIELD;
0934     }
0935     /*
0936      * Set SNLID=1 (Supports no List ID)
0937      */
0938     p[4] = 0x1;
0939     /*
0940      * MAXIMUM TARGET DESCRIPTOR COUNT
0941      */
0942     put_unaligned_be16(RCR_OP_MAX_TARGET_DESC_COUNT, &p[8]);
0943     /*
0944      * MAXIMUM SEGMENT DESCRIPTOR COUNT
0945      */
0946     put_unaligned_be16(RCR_OP_MAX_SG_DESC_COUNT, &p[10]);
0947     /*
0948      * MAXIMUM DESCRIPTOR LIST LENGTH
0949      */
0950     put_unaligned_be32(RCR_OP_MAX_DESC_LIST_LEN, &p[12]);
0951     /*
0952      * MAXIMUM SEGMENT LENGTH
0953      */
0954     put_unaligned_be32(RCR_OP_MAX_SEGMENT_LEN, &p[16]);
0955     /*
0956      * MAXIMUM INLINE DATA LENGTH for SA 0x04 (NOT SUPPORTED)
0957      */
0958     put_unaligned_be32(0x0, &p[20]);
0959     /*
0960      * HELD DATA LIMIT
0961      */
0962     put_unaligned_be32(0x0, &p[24]);
0963     /*
0964      * MAXIMUM STREAM DEVICE TRANSFER SIZE
0965      */
0966     put_unaligned_be32(0x0, &p[28]);
0967     /*
0968      * TOTAL CONCURRENT COPIES
0969      */
0970     put_unaligned_be16(RCR_OP_TOTAL_CONCURR_COPIES, &p[34]);
0971     /*
0972      * MAXIMUM CONCURRENT COPIES
0973      */
0974     p[36] = RCR_OP_MAX_CONCURR_COPIES;
0975     /*
0976      * DATA SEGMENT GRANULARITY (log 2)
0977      */
0978     p[37] = RCR_OP_DATA_SEG_GRAN_LOG2;
0979     /*
0980      * INLINE DATA GRANULARITY log 2)
0981      */
0982     p[38] = RCR_OP_INLINE_DATA_GRAN_LOG2;
0983     /*
0984      * HELD DATA GRANULARITY
0985      */
0986     p[39] = RCR_OP_HELD_DATA_GRAN_LOG2;
0987     /*
0988      * IMPLEMENTED DESCRIPTOR LIST LENGTH
0989      */
0990     p[43] = 0x2;
0991     /*
0992      * List of implemented descriptor type codes (ordered)
0993      */
0994     p[44] = 0x02; /* Copy Block to Block device */
0995     p[45] = 0xe4; /* Identification descriptor target descriptor */
0996 
0997     /*
0998      * AVAILABLE DATA (n-3)
0999      */
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 
1008 sense_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 }