aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/target/target_core_xcopy.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/target/target_core_xcopy.c')
-rw-r--r--drivers/target/target_core_xcopy.c184
1 files changed, 111 insertions, 73 deletions
diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c
index cac5a20a4de0..9ee89e00cd77 100644
--- a/drivers/target/target_core_xcopy.c
+++ b/drivers/target/target_core_xcopy.c
@@ -40,6 +40,8 @@
40 40
41static struct workqueue_struct *xcopy_wq = NULL; 41static struct workqueue_struct *xcopy_wq = NULL;
42 42
43static sense_reason_t target_parse_xcopy_cmd(struct xcopy_op *xop);
44
43static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf) 45static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf)
44{ 46{
45 int off = 0; 47 int off = 0;
@@ -53,48 +55,60 @@ static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf)
53 return 0; 55 return 0;
54} 56}
55 57
56static int target_xcopy_locate_se_dev_e4(const unsigned char *dev_wwn, 58struct xcopy_dev_search_info {
57 struct se_device **found_dev) 59 const unsigned char *dev_wwn;
60 struct se_device *found_dev;
61};
62
63static int target_xcopy_locate_se_dev_e4_iter(struct se_device *se_dev,
64 void *data)
58{ 65{
59 struct se_device *se_dev; 66 struct xcopy_dev_search_info *info = data;
60 unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN]; 67 unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN];
61 int rc; 68 int rc;
62 69
63 mutex_lock(&g_device_mutex); 70 if (!se_dev->dev_attrib.emulate_3pc)
64 list_for_each_entry(se_dev, &g_device_list, g_dev_node) { 71 return 0;
65 72
66 if (!se_dev->dev_attrib.emulate_3pc) 73 memset(&tmp_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN);
67 continue; 74 target_xcopy_gen_naa_ieee(se_dev, &tmp_dev_wwn[0]);
68 75
69 memset(&tmp_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN); 76 rc = memcmp(&tmp_dev_wwn[0], info->dev_wwn, XCOPY_NAA_IEEE_REGEX_LEN);
70 target_xcopy_gen_naa_ieee(se_dev, &tmp_dev_wwn[0]); 77 if (rc != 0)
78 return 0;
71 79
72 rc = memcmp(&tmp_dev_wwn[0], dev_wwn, XCOPY_NAA_IEEE_REGEX_LEN); 80 info->found_dev = se_dev;
73 if (rc != 0) 81 pr_debug("XCOPY 0xe4: located se_dev: %p\n", se_dev);
74 continue;
75 82
76 *found_dev = se_dev; 83 rc = target_depend_item(&se_dev->dev_group.cg_item);
77 pr_debug("XCOPY 0xe4: located se_dev: %p\n", se_dev); 84 if (rc != 0) {
85 pr_err("configfs_depend_item attempt failed: %d for se_dev: %p\n",
86 rc, se_dev);
87 return rc;
88 }
78 89
79 rc = target_depend_item(&se_dev->dev_group.cg_item); 90 pr_debug("Called configfs_depend_item for se_dev: %p se_dev->se_dev_group: %p\n",
80 if (rc != 0) { 91 se_dev, &se_dev->dev_group);
81 pr_err("configfs_depend_item attempt failed:" 92 return 1;
82 " %d for se_dev: %p\n", rc, se_dev); 93}
83 mutex_unlock(&g_device_mutex);
84 return rc;
85 }
86 94
87 pr_debug("Called configfs_depend_item for se_dev: %p" 95static int target_xcopy_locate_se_dev_e4(const unsigned char *dev_wwn,
88 " se_dev->se_dev_group: %p\n", se_dev, 96 struct se_device **found_dev)
89 &se_dev->dev_group); 97{
98 struct xcopy_dev_search_info info;
99 int ret;
100
101 memset(&info, 0, sizeof(info));
102 info.dev_wwn = dev_wwn;
90 103
91 mutex_unlock(&g_device_mutex); 104 ret = target_for_each_device(target_xcopy_locate_se_dev_e4_iter, &info);
105 if (ret == 1) {
106 *found_dev = info.found_dev;
92 return 0; 107 return 0;
108 } else {
109 pr_debug_ratelimited("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n");
110 return -EINVAL;
93 } 111 }
94 mutex_unlock(&g_device_mutex);
95
96 pr_debug_ratelimited("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n");
97 return -EINVAL;
98} 112}
99 113
100static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op *xop, 114static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op *xop,
@@ -311,9 +325,7 @@ static int target_xcopy_parse_segdesc_02(struct se_cmd *se_cmd, struct xcopy_op
311 (unsigned long long)xop->dst_lba); 325 (unsigned long long)xop->dst_lba);
312 326
313 if (dc != 0) { 327 if (dc != 0) {
314 xop->dbl = (desc[29] & 0xff) << 16; 328 xop->dbl = get_unaligned_be24(&desc[29]);
315 xop->dbl |= (desc[30] & 0xff) << 8;
316 xop->dbl |= desc[31] & 0xff;
317 329
318 pr_debug("XCOPY seg desc 0x02: DC=1 w/ dbl: %u\n", xop->dbl); 330 pr_debug("XCOPY seg desc 0x02: DC=1 w/ dbl: %u\n", xop->dbl);
319 } 331 }
@@ -781,13 +793,24 @@ static int target_xcopy_write_destination(
781static void target_xcopy_do_work(struct work_struct *work) 793static void target_xcopy_do_work(struct work_struct *work)
782{ 794{
783 struct xcopy_op *xop = container_of(work, struct xcopy_op, xop_work); 795 struct xcopy_op *xop = container_of(work, struct xcopy_op, xop_work);
784 struct se_device *src_dev = xop->src_dev, *dst_dev = xop->dst_dev;
785 struct se_cmd *ec_cmd = xop->xop_se_cmd; 796 struct se_cmd *ec_cmd = xop->xop_se_cmd;
786 sector_t src_lba = xop->src_lba, dst_lba = xop->dst_lba, end_lba; 797 struct se_device *src_dev, *dst_dev;
798 sector_t src_lba, dst_lba, end_lba;
787 unsigned int max_sectors; 799 unsigned int max_sectors;
788 int rc; 800 int rc = 0;
789 unsigned short nolb = xop->nolb, cur_nolb, max_nolb, copied_nolb = 0; 801 unsigned short nolb, cur_nolb, max_nolb, copied_nolb = 0;
802
803 if (target_parse_xcopy_cmd(xop) != TCM_NO_SENSE)
804 goto err_free;
790 805
806 if (WARN_ON_ONCE(!xop->src_dev) || WARN_ON_ONCE(!xop->dst_dev))
807 goto err_free;
808
809 src_dev = xop->src_dev;
810 dst_dev = xop->dst_dev;
811 src_lba = xop->src_lba;
812 dst_lba = xop->dst_lba;
813 nolb = xop->nolb;
791 end_lba = src_lba + nolb; 814 end_lba = src_lba + nolb;
792 /* 815 /*
793 * Break up XCOPY I/O into hw_max_sectors sized I/O based on the 816 * Break up XCOPY I/O into hw_max_sectors sized I/O based on the
@@ -855,6 +878,8 @@ static void target_xcopy_do_work(struct work_struct *work)
855 878
856out: 879out:
857 xcopy_pt_undepend_remotedev(xop); 880 xcopy_pt_undepend_remotedev(xop);
881
882err_free:
858 kfree(xop); 883 kfree(xop);
859 /* 884 /*
860 * Don't override an error scsi status if it has already been set 885 * Don't override an error scsi status if it has already been set
@@ -867,48 +892,22 @@ out:
867 target_complete_cmd(ec_cmd, ec_cmd->scsi_status); 892 target_complete_cmd(ec_cmd, ec_cmd->scsi_status);
868} 893}
869 894
870sense_reason_t target_do_xcopy(struct se_cmd *se_cmd) 895/*
896 * Returns TCM_NO_SENSE upon success or a sense code != TCM_NO_SENSE if parsing
897 * fails.
898 */
899static sense_reason_t target_parse_xcopy_cmd(struct xcopy_op *xop)
871{ 900{
872 struct se_device *dev = se_cmd->se_dev; 901 struct se_cmd *se_cmd = xop->xop_se_cmd;
873 struct xcopy_op *xop = NULL;
874 unsigned char *p = NULL, *seg_desc; 902 unsigned char *p = NULL, *seg_desc;
875 unsigned int list_id, list_id_usage, sdll, inline_dl, sa; 903 unsigned int list_id, list_id_usage, sdll, inline_dl;
876 sense_reason_t ret = TCM_INVALID_PARAMETER_LIST; 904 sense_reason_t ret = TCM_INVALID_PARAMETER_LIST;
877 int rc; 905 int rc;
878 unsigned short tdll; 906 unsigned short tdll;
879 907
880 if (!dev->dev_attrib.emulate_3pc) {
881 pr_err("EXTENDED_COPY operation explicitly disabled\n");
882 return TCM_UNSUPPORTED_SCSI_OPCODE;
883 }
884
885 sa = se_cmd->t_task_cdb[1] & 0x1f;
886 if (sa != 0x00) {
887 pr_err("EXTENDED_COPY(LID4) not supported\n");
888 return TCM_UNSUPPORTED_SCSI_OPCODE;
889 }
890
891 if (se_cmd->data_length == 0) {
892 target_complete_cmd(se_cmd, SAM_STAT_GOOD);
893 return TCM_NO_SENSE;
894 }
895 if (se_cmd->data_length < XCOPY_HDR_LEN) {
896 pr_err("XCOPY parameter truncation: length %u < hdr_len %u\n",
897 se_cmd->data_length, XCOPY_HDR_LEN);
898 return TCM_PARAMETER_LIST_LENGTH_ERROR;
899 }
900
901 xop = kzalloc(sizeof(struct xcopy_op), GFP_KERNEL);
902 if (!xop) {
903 pr_err("Unable to allocate xcopy_op\n");
904 return TCM_OUT_OF_RESOURCES;
905 }
906 xop->xop_se_cmd = se_cmd;
907
908 p = transport_kmap_data_sg(se_cmd); 908 p = transport_kmap_data_sg(se_cmd);
909 if (!p) { 909 if (!p) {
910 pr_err("transport_kmap_data_sg() failed in target_do_xcopy\n"); 910 pr_err("transport_kmap_data_sg() failed in target_do_xcopy\n");
911 kfree(xop);
912 return TCM_OUT_OF_RESOURCES; 911 return TCM_OUT_OF_RESOURCES;
913 } 912 }
914 913
@@ -977,18 +976,57 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
977 pr_debug("XCOPY: Processed %d target descriptors, length: %u\n", rc, 976 pr_debug("XCOPY: Processed %d target descriptors, length: %u\n", rc,
978 rc * XCOPY_TARGET_DESC_LEN); 977 rc * XCOPY_TARGET_DESC_LEN);
979 transport_kunmap_data_sg(se_cmd); 978 transport_kunmap_data_sg(se_cmd);
980
981 INIT_WORK(&xop->xop_work, target_xcopy_do_work);
982 queue_work(xcopy_wq, &xop->xop_work);
983 return TCM_NO_SENSE; 979 return TCM_NO_SENSE;
984 980
985out: 981out:
986 if (p) 982 if (p)
987 transport_kunmap_data_sg(se_cmd); 983 transport_kunmap_data_sg(se_cmd);
988 kfree(xop);
989 return ret; 984 return ret;
990} 985}
991 986
987sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
988{
989 struct se_device *dev = se_cmd->se_dev;
990 struct xcopy_op *xop;
991 unsigned int sa;
992
993 if (!dev->dev_attrib.emulate_3pc) {
994 pr_err("EXTENDED_COPY operation explicitly disabled\n");
995 return TCM_UNSUPPORTED_SCSI_OPCODE;
996 }
997
998 sa = se_cmd->t_task_cdb[1] & 0x1f;
999 if (sa != 0x00) {
1000 pr_err("EXTENDED_COPY(LID4) not supported\n");
1001 return TCM_UNSUPPORTED_SCSI_OPCODE;
1002 }
1003
1004 if (se_cmd->data_length == 0) {
1005 target_complete_cmd(se_cmd, SAM_STAT_GOOD);
1006 return TCM_NO_SENSE;
1007 }
1008 if (se_cmd->data_length < XCOPY_HDR_LEN) {
1009 pr_err("XCOPY parameter truncation: length %u < hdr_len %u\n",
1010 se_cmd->data_length, XCOPY_HDR_LEN);
1011 return TCM_PARAMETER_LIST_LENGTH_ERROR;
1012 }
1013
1014 xop = kzalloc(sizeof(struct xcopy_op), GFP_KERNEL);
1015 if (!xop)
1016 goto err;
1017 xop->xop_se_cmd = se_cmd;
1018 INIT_WORK(&xop->xop_work, target_xcopy_do_work);
1019 if (WARN_ON_ONCE(!queue_work(xcopy_wq, &xop->xop_work)))
1020 goto free;
1021 return TCM_NO_SENSE;
1022
1023free:
1024 kfree(xop);
1025
1026err:
1027 return TCM_OUT_OF_RESOURCES;
1028}
1029
992static sense_reason_t target_rcr_operating_parameters(struct se_cmd *se_cmd) 1030static sense_reason_t target_rcr_operating_parameters(struct se_cmd *se_cmd)
993{ 1031{
994 unsigned char *p; 1032 unsigned char *p;