diff options
-rw-r--r-- | drivers/target/target_core_xcopy.c | 79 |
1 files changed, 48 insertions, 31 deletions
diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index 41a2a8ad1046..2595c1eb9e91 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c | |||
@@ -98,7 +98,7 @@ static int target_xcopy_locate_se_dev_e4(const unsigned char *dev_wwn, | |||
98 | } | 98 | } |
99 | 99 | ||
100 | static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op *xop, | 100 | static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op *xop, |
101 | unsigned char *p, bool src) | 101 | unsigned char *p, unsigned short cscd_index) |
102 | { | 102 | { |
103 | unsigned char *desc = p; | 103 | unsigned char *desc = p; |
104 | unsigned short ript; | 104 | unsigned short ript; |
@@ -143,7 +143,13 @@ static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op | |||
143 | return -EINVAL; | 143 | return -EINVAL; |
144 | } | 144 | } |
145 | 145 | ||
146 | if (src) { | 146 | if (cscd_index != xop->stdi && cscd_index != xop->dtdi) { |
147 | pr_debug("XCOPY 0xe4: ignoring CSCD entry %d - neither src nor " | ||
148 | "dest\n", cscd_index); | ||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | if (cscd_index == xop->stdi) { | ||
147 | memcpy(&xop->src_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN); | 153 | memcpy(&xop->src_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN); |
148 | /* | 154 | /* |
149 | * Determine if the source designator matches the local device | 155 | * Determine if the source designator matches the local device |
@@ -155,10 +161,15 @@ static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op | |||
155 | pr_debug("XCOPY 0xe4: Set xop->src_dev %p from source" | 161 | pr_debug("XCOPY 0xe4: Set xop->src_dev %p from source" |
156 | " received xop\n", xop->src_dev); | 162 | " received xop\n", xop->src_dev); |
157 | } | 163 | } |
158 | } else { | 164 | } |
165 | |||
166 | if (cscd_index == xop->dtdi) { | ||
159 | memcpy(&xop->dst_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN); | 167 | memcpy(&xop->dst_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN); |
160 | /* | 168 | /* |
161 | * Determine if the destination designator matches the local device | 169 | * Determine if the destination designator matches the local |
170 | * device. If @cscd_index corresponds to both source (stdi) and | ||
171 | * destination (dtdi), or dtdi comes after stdi, then | ||
172 | * XCOL_DEST_RECV_OP wins. | ||
162 | */ | 173 | */ |
163 | if (!memcmp(&xop->local_dev_wwn[0], &xop->dst_tid_wwn[0], | 174 | if (!memcmp(&xop->local_dev_wwn[0], &xop->dst_tid_wwn[0], |
164 | XCOPY_NAA_IEEE_REGEX_LEN)) { | 175 | XCOPY_NAA_IEEE_REGEX_LEN)) { |
@@ -178,9 +189,9 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd, | |||
178 | { | 189 | { |
179 | struct se_device *local_dev = se_cmd->se_dev; | 190 | struct se_device *local_dev = se_cmd->se_dev; |
180 | unsigned char *desc = p; | 191 | unsigned char *desc = p; |
181 | int offset = tdll % XCOPY_TARGET_DESC_LEN, rc, ret = 0; | 192 | int offset = tdll % XCOPY_TARGET_DESC_LEN, rc; |
193 | unsigned short cscd_index = 0; | ||
182 | unsigned short start = 0; | 194 | unsigned short start = 0; |
183 | bool src = true; | ||
184 | 195 | ||
185 | *sense_ret = TCM_INVALID_PARAMETER_LIST; | 196 | *sense_ret = TCM_INVALID_PARAMETER_LIST; |
186 | 197 | ||
@@ -206,25 +217,19 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd, | |||
206 | 217 | ||
207 | while (start < tdll) { | 218 | while (start < tdll) { |
208 | /* | 219 | /* |
209 | * Check target descriptor identification with 0xE4 type with | 220 | * Check target descriptor identification with 0xE4 type, and |
210 | * use VPD 0x83 WWPN matching .. | 221 | * compare the current index with the CSCD descriptor IDs in |
222 | * the segment descriptor. Use VPD 0x83 WWPN matching .. | ||
211 | */ | 223 | */ |
212 | switch (desc[0]) { | 224 | switch (desc[0]) { |
213 | case 0xe4: | 225 | case 0xe4: |
214 | rc = target_xcopy_parse_tiddesc_e4(se_cmd, xop, | 226 | rc = target_xcopy_parse_tiddesc_e4(se_cmd, xop, |
215 | &desc[0], src); | 227 | &desc[0], cscd_index); |
216 | if (rc != 0) | 228 | if (rc != 0) |
217 | goto out; | 229 | goto out; |
218 | /* | ||
219 | * Assume target descriptors are in source -> destination order.. | ||
220 | */ | ||
221 | if (src) | ||
222 | src = false; | ||
223 | else | ||
224 | src = true; | ||
225 | start += XCOPY_TARGET_DESC_LEN; | 230 | start += XCOPY_TARGET_DESC_LEN; |
226 | desc += XCOPY_TARGET_DESC_LEN; | 231 | desc += XCOPY_TARGET_DESC_LEN; |
227 | ret++; | 232 | cscd_index++; |
228 | break; | 233 | break; |
229 | default: | 234 | default: |
230 | pr_err("XCOPY unsupported descriptor type code:" | 235 | pr_err("XCOPY unsupported descriptor type code:" |
@@ -234,12 +239,21 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd, | |||
234 | } | 239 | } |
235 | } | 240 | } |
236 | 241 | ||
237 | if (xop->op_origin == XCOL_SOURCE_RECV_OP) | 242 | switch (xop->op_origin) { |
243 | case XCOL_SOURCE_RECV_OP: | ||
238 | rc = target_xcopy_locate_se_dev_e4(xop->dst_tid_wwn, | 244 | rc = target_xcopy_locate_se_dev_e4(xop->dst_tid_wwn, |
239 | &xop->dst_dev); | 245 | &xop->dst_dev); |
240 | else | 246 | break; |
247 | case XCOL_DEST_RECV_OP: | ||
241 | rc = target_xcopy_locate_se_dev_e4(xop->src_tid_wwn, | 248 | rc = target_xcopy_locate_se_dev_e4(xop->src_tid_wwn, |
242 | &xop->src_dev); | 249 | &xop->src_dev); |
250 | break; | ||
251 | default: | ||
252 | pr_err("XCOPY CSCD descriptor IDs not found in CSCD list - " | ||
253 | "stdi: %hu dtdi: %hu\n", xop->stdi, xop->dtdi); | ||
254 | rc = -EINVAL; | ||
255 | break; | ||
256 | } | ||
243 | /* | 257 | /* |
244 | * If a matching IEEE NAA 0x83 descriptor for the requested device | 258 | * If a matching IEEE NAA 0x83 descriptor for the requested device |
245 | * is not located on this node, return COPY_ABORTED with ASQ/ASQC | 259 | * is not located on this node, return COPY_ABORTED with ASQ/ASQC |
@@ -256,7 +270,7 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd, | |||
256 | pr_debug("XCOPY TGT desc: Dest dev: %p NAA IEEE WWN: 0x%16phN\n", | 270 | pr_debug("XCOPY TGT desc: Dest dev: %p NAA IEEE WWN: 0x%16phN\n", |
257 | xop->dst_dev, &xop->dst_tid_wwn[0]); | 271 | xop->dst_dev, &xop->dst_tid_wwn[0]); |
258 | 272 | ||
259 | return ret; | 273 | return cscd_index; |
260 | 274 | ||
261 | out: | 275 | out: |
262 | return -EINVAL; | 276 | return -EINVAL; |
@@ -913,6 +927,20 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd) | |||
913 | " tdll: %hu sdll: %u inline_dl: %u\n", list_id, list_id_usage, | 927 | " tdll: %hu sdll: %u inline_dl: %u\n", list_id, list_id_usage, |
914 | tdll, sdll, inline_dl); | 928 | tdll, sdll, inline_dl); |
915 | 929 | ||
930 | /* | ||
931 | * skip over the target descriptors until segment descriptors | ||
932 | * have been passed - CSCD ids are needed to determine src and dest. | ||
933 | */ | ||
934 | seg_desc = &p[16] + tdll; | ||
935 | |||
936 | rc = target_xcopy_parse_segment_descriptors(se_cmd, xop, seg_desc, | ||
937 | sdll, &ret); | ||
938 | if (rc <= 0) | ||
939 | goto out; | ||
940 | |||
941 | pr_debug("XCOPY: Processed %d segment descriptors, length: %u\n", rc, | ||
942 | rc * XCOPY_SEGMENT_DESC_LEN); | ||
943 | |||
916 | rc = target_xcopy_parse_target_descriptors(se_cmd, xop, &p[16], tdll, &ret); | 944 | rc = target_xcopy_parse_target_descriptors(se_cmd, xop, &p[16], tdll, &ret); |
917 | if (rc <= 0) | 945 | if (rc <= 0) |
918 | goto out; | 946 | goto out; |
@@ -930,19 +958,8 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd) | |||
930 | 958 | ||
931 | pr_debug("XCOPY: Processed %d target descriptors, length: %u\n", rc, | 959 | pr_debug("XCOPY: Processed %d target descriptors, length: %u\n", rc, |
932 | rc * XCOPY_TARGET_DESC_LEN); | 960 | rc * XCOPY_TARGET_DESC_LEN); |
933 | seg_desc = &p[16]; | ||
934 | seg_desc += (rc * XCOPY_TARGET_DESC_LEN); | ||
935 | |||
936 | rc = target_xcopy_parse_segment_descriptors(se_cmd, xop, seg_desc, | ||
937 | sdll, &ret); | ||
938 | if (rc <= 0) { | ||
939 | xcopy_pt_undepend_remotedev(xop); | ||
940 | goto out; | ||
941 | } | ||
942 | transport_kunmap_data_sg(se_cmd); | 961 | transport_kunmap_data_sg(se_cmd); |
943 | 962 | ||
944 | pr_debug("XCOPY: Processed %d segment descriptors, length: %u\n", rc, | ||
945 | rc * XCOPY_SEGMENT_DESC_LEN); | ||
946 | INIT_WORK(&xop->xop_work, target_xcopy_do_work); | 963 | INIT_WORK(&xop->xop_work, target_xcopy_do_work); |
947 | queue_work(xcopy_wq, &xop->xop_work); | 964 | queue_work(xcopy_wq, &xop->xop_work); |
948 | return TCM_NO_SENSE; | 965 | return TCM_NO_SENSE; |