0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
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
0038
0039
0040
0041
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
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
0123
0124 ript = get_unaligned_be16(&desc[2]);
0125 pr_debug("XCOPY 0xe4: RELATIVE INITIATOR PORT IDENTIFIER: %hu\n", ript);
0126
0127
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
0144
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
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
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
0185
0186
0187
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
0223 *sense_ret = TCM_TOO_MANY_TARGET_DESCS;
0224 return -EINVAL;
0225 }
0226
0227
0228
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
0236
0237
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
0278
0279
0280
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
0354 *sense_ret = TCM_TOO_MANY_SEGMENT_DESCS;
0355 return -EINVAL;
0356 }
0357
0358 while (start < sdll) {
0359
0360
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
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
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
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
0510
0511
0512
0513
0514
0515
0516
0517
0518
0519
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
0532
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
0695
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
0715
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
0770
0771
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
0786
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
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
0838
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
0937
0938 p[4] = 0x1;
0939
0940
0941
0942 put_unaligned_be16(RCR_OP_MAX_TARGET_DESC_COUNT, &p[8]);
0943
0944
0945
0946 put_unaligned_be16(RCR_OP_MAX_SG_DESC_COUNT, &p[10]);
0947
0948
0949
0950 put_unaligned_be32(RCR_OP_MAX_DESC_LIST_LEN, &p[12]);
0951
0952
0953
0954 put_unaligned_be32(RCR_OP_MAX_SEGMENT_LEN, &p[16]);
0955
0956
0957
0958 put_unaligned_be32(0x0, &p[20]);
0959
0960
0961
0962 put_unaligned_be32(0x0, &p[24]);
0963
0964
0965
0966 put_unaligned_be32(0x0, &p[28]);
0967
0968
0969
0970 put_unaligned_be16(RCR_OP_TOTAL_CONCURR_COPIES, &p[34]);
0971
0972
0973
0974 p[36] = RCR_OP_MAX_CONCURR_COPIES;
0975
0976
0977
0978 p[37] = RCR_OP_DATA_SEG_GRAN_LOG2;
0979
0980
0981
0982 p[38] = RCR_OP_INLINE_DATA_GRAN_LOG2;
0983
0984
0985
0986 p[39] = RCR_OP_HELD_DATA_GRAN_LOG2;
0987
0988
0989
0990 p[43] = 0x2;
0991
0992
0993
0994 p[44] = 0x02;
0995 p[45] = 0xe4;
0996
0997
0998
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 }