diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-01-12 13:41:20 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-01-12 13:41:20 -0500 |
commit | cb38b45346f17f4b0a105b9315b030a2e24fb7e6 (patch) | |
tree | e91ecc715863928d8e3a33bf875423e19d1e7ba6 | |
parent | 607ae5f26920b8dfedbbf882c0f9edd3b9aa6cf7 (diff) | |
parent | 7c9d8d0c41b3e24473ac7648a7fc2d644ccf08ff (diff) |
Merge branch 'scsi-target-for-v4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/bvanassche/linux
Pull scsi target fixes from Bart Van Assche:
- a series of bug fixes for the XCOPY implementation from David
Disseldorp
- one bug fix for the ibmvscsis driver, a driver that is used for
communication between partitions on IBM POWER systems.
* 'scsi-target-for-v4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/bvanassche/linux:
ibmvscsis: Fix srp_transfer_data fail return code
target: support XCOPY requests without parameters
target: check for XCOPY parameter truncation
target: use XCOPY segment descriptor CSCD IDs
target: check XCOPY segment descriptor CSCD IDs
target: simplify XCOPY wwn->se_dev lookup helper
target: return UNSUPPORTED TARGET/SEGMENT DESC TYPE CODE sense
target: bounds check XCOPY total descriptor list length
target: bounds check XCOPY segment descriptor list
target: use XCOPY TOO MANY TARGET DESCRIPTORS sense
target: add XCOPY target/segment desc sense codes
-rw-r--r-- | drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c | 2 | ||||
-rw-r--r-- | drivers/target/target_core_transport.c | 24 | ||||
-rw-r--r-- | drivers/target/target_core_xcopy.c | 157 | ||||
-rw-r--r-- | drivers/target/target_core_xcopy.h | 7 | ||||
-rw-r--r-- | include/target/target_core_base.h | 4 |
5 files changed, 142 insertions, 52 deletions
diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c index 3d3768aaab4f..8fb5c54c7dd3 100644 --- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c +++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c | |||
@@ -3585,7 +3585,7 @@ static int ibmvscsis_write_pending(struct se_cmd *se_cmd) | |||
3585 | 1, 1); | 3585 | 1, 1); |
3586 | if (rc) { | 3586 | if (rc) { |
3587 | pr_err("srp_transfer_data() failed: %d\n", rc); | 3587 | pr_err("srp_transfer_data() failed: %d\n", rc); |
3588 | return -EAGAIN; | 3588 | return -EIO; |
3589 | } | 3589 | } |
3590 | /* | 3590 | /* |
3591 | * We now tell TCM to add this WRITE CDB directly into the TCM storage | 3591 | * We now tell TCM to add this WRITE CDB directly into the TCM storage |
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 7dfefd66df93..1cadc9eefa21 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
@@ -1693,6 +1693,10 @@ void transport_generic_request_failure(struct se_cmd *cmd, | |||
1693 | case TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED: | 1693 | case TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED: |
1694 | case TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED: | 1694 | case TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED: |
1695 | case TCM_COPY_TARGET_DEVICE_NOT_REACHABLE: | 1695 | case TCM_COPY_TARGET_DEVICE_NOT_REACHABLE: |
1696 | case TCM_TOO_MANY_TARGET_DESCS: | ||
1697 | case TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE: | ||
1698 | case TCM_TOO_MANY_SEGMENT_DESCS: | ||
1699 | case TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE: | ||
1696 | break; | 1700 | break; |
1697 | case TCM_OUT_OF_RESOURCES: | 1701 | case TCM_OUT_OF_RESOURCES: |
1698 | sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 1702 | sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
@@ -2808,6 +2812,26 @@ static const struct sense_info sense_info_table[] = { | |||
2808 | .key = ILLEGAL_REQUEST, | 2812 | .key = ILLEGAL_REQUEST, |
2809 | .asc = 0x26, /* INVALID FIELD IN PARAMETER LIST */ | 2813 | .asc = 0x26, /* INVALID FIELD IN PARAMETER LIST */ |
2810 | }, | 2814 | }, |
2815 | [TCM_TOO_MANY_TARGET_DESCS] = { | ||
2816 | .key = ILLEGAL_REQUEST, | ||
2817 | .asc = 0x26, | ||
2818 | .ascq = 0x06, /* TOO MANY TARGET DESCRIPTORS */ | ||
2819 | }, | ||
2820 | [TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE] = { | ||
2821 | .key = ILLEGAL_REQUEST, | ||
2822 | .asc = 0x26, | ||
2823 | .ascq = 0x07, /* UNSUPPORTED TARGET DESCRIPTOR TYPE CODE */ | ||
2824 | }, | ||
2825 | [TCM_TOO_MANY_SEGMENT_DESCS] = { | ||
2826 | .key = ILLEGAL_REQUEST, | ||
2827 | .asc = 0x26, | ||
2828 | .ascq = 0x08, /* TOO MANY SEGMENT DESCRIPTORS */ | ||
2829 | }, | ||
2830 | [TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE] = { | ||
2831 | .key = ILLEGAL_REQUEST, | ||
2832 | .asc = 0x26, | ||
2833 | .ascq = 0x09, /* UNSUPPORTED SEGMENT DESCRIPTOR TYPE CODE */ | ||
2834 | }, | ||
2811 | [TCM_PARAMETER_LIST_LENGTH_ERROR] = { | 2835 | [TCM_PARAMETER_LIST_LENGTH_ERROR] = { |
2812 | .key = ILLEGAL_REQUEST, | 2836 | .key = ILLEGAL_REQUEST, |
2813 | .asc = 0x1a, /* PARAMETER LIST LENGTH ERROR */ | 2837 | .asc = 0x1a, /* PARAMETER LIST LENGTH ERROR */ |
diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index 37d5caebffa6..d828b3b5000b 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c | |||
@@ -53,18 +53,13 @@ static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf) | |||
53 | return 0; | 53 | return 0; |
54 | } | 54 | } |
55 | 55 | ||
56 | static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op *xop, | 56 | static int target_xcopy_locate_se_dev_e4(const unsigned char *dev_wwn, |
57 | bool src) | 57 | struct se_device **found_dev) |
58 | { | 58 | { |
59 | struct se_device *se_dev; | 59 | struct se_device *se_dev; |
60 | unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN], *dev_wwn; | 60 | unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN]; |
61 | int rc; | 61 | int rc; |
62 | 62 | ||
63 | if (src) | ||
64 | dev_wwn = &xop->dst_tid_wwn[0]; | ||
65 | else | ||
66 | dev_wwn = &xop->src_tid_wwn[0]; | ||
67 | |||
68 | mutex_lock(&g_device_mutex); | 63 | mutex_lock(&g_device_mutex); |
69 | list_for_each_entry(se_dev, &g_device_list, g_dev_node) { | 64 | list_for_each_entry(se_dev, &g_device_list, g_dev_node) { |
70 | 65 | ||
@@ -78,15 +73,8 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op | |||
78 | if (rc != 0) | 73 | if (rc != 0) |
79 | continue; | 74 | continue; |
80 | 75 | ||
81 | if (src) { | 76 | *found_dev = se_dev; |
82 | xop->dst_dev = se_dev; | 77 | pr_debug("XCOPY 0xe4: located se_dev: %p\n", se_dev); |
83 | pr_debug("XCOPY 0xe4: Setting xop->dst_dev: %p from located" | ||
84 | " se_dev\n", xop->dst_dev); | ||
85 | } else { | ||
86 | xop->src_dev = se_dev; | ||
87 | pr_debug("XCOPY 0xe4: Setting xop->src_dev: %p from located" | ||
88 | " se_dev\n", xop->src_dev); | ||
89 | } | ||
90 | 78 | ||
91 | rc = target_depend_item(&se_dev->dev_group.cg_item); | 79 | rc = target_depend_item(&se_dev->dev_group.cg_item); |
92 | if (rc != 0) { | 80 | if (rc != 0) { |
@@ -110,7 +98,7 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op | |||
110 | } | 98 | } |
111 | 99 | ||
112 | 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, |
113 | unsigned char *p, bool src) | 101 | unsigned char *p, unsigned short cscd_index) |
114 | { | 102 | { |
115 | unsigned char *desc = p; | 103 | unsigned char *desc = p; |
116 | unsigned short ript; | 104 | unsigned short ript; |
@@ -155,7 +143,13 @@ static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op | |||
155 | return -EINVAL; | 143 | return -EINVAL; |
156 | } | 144 | } |
157 | 145 | ||
158 | 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) { | ||
159 | 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); |
160 | /* | 154 | /* |
161 | * Determine if the source designator matches the local device | 155 | * Determine if the source designator matches the local device |
@@ -167,10 +161,15 @@ static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op | |||
167 | pr_debug("XCOPY 0xe4: Set xop->src_dev %p from source" | 161 | pr_debug("XCOPY 0xe4: Set xop->src_dev %p from source" |
168 | " received xop\n", xop->src_dev); | 162 | " received xop\n", xop->src_dev); |
169 | } | 163 | } |
170 | } else { | 164 | } |
165 | |||
166 | if (cscd_index == xop->dtdi) { | ||
171 | 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); |
172 | /* | 168 | /* |
173 | * 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. | ||
174 | */ | 173 | */ |
175 | 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], |
176 | XCOPY_NAA_IEEE_REGEX_LEN)) { | 175 | XCOPY_NAA_IEEE_REGEX_LEN)) { |
@@ -190,20 +189,23 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd, | |||
190 | { | 189 | { |
191 | struct se_device *local_dev = se_cmd->se_dev; | 190 | struct se_device *local_dev = se_cmd->se_dev; |
192 | unsigned char *desc = p; | 191 | unsigned char *desc = p; |
193 | 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; | ||
194 | unsigned short start = 0; | 194 | unsigned short start = 0; |
195 | bool src = true; | ||
196 | 195 | ||
197 | *sense_ret = TCM_INVALID_PARAMETER_LIST; | 196 | *sense_ret = TCM_INVALID_PARAMETER_LIST; |
198 | 197 | ||
199 | if (offset != 0) { | 198 | if (offset != 0) { |
200 | pr_err("XCOPY target descriptor list length is not" | 199 | pr_err("XCOPY target descriptor list length is not" |
201 | " multiple of %d\n", XCOPY_TARGET_DESC_LEN); | 200 | " multiple of %d\n", XCOPY_TARGET_DESC_LEN); |
201 | *sense_ret = TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE; | ||
202 | return -EINVAL; | 202 | return -EINVAL; |
203 | } | 203 | } |
204 | if (tdll > 64) { | 204 | if (tdll > RCR_OP_MAX_TARGET_DESC_COUNT * XCOPY_TARGET_DESC_LEN) { |
205 | pr_err("XCOPY target descriptor supports a maximum" | 205 | pr_err("XCOPY target descriptor supports a maximum" |
206 | " two src/dest descriptors, tdll: %hu too large..\n", tdll); | 206 | " two src/dest descriptors, tdll: %hu too large..\n", tdll); |
207 | /* spc4r37 6.4.3.4 CSCD DESCRIPTOR LIST LENGTH field */ | ||
208 | *sense_ret = TCM_TOO_MANY_TARGET_DESCS; | ||
207 | return -EINVAL; | 209 | return -EINVAL; |
208 | } | 210 | } |
209 | /* | 211 | /* |
@@ -215,37 +217,43 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd, | |||
215 | 217 | ||
216 | while (start < tdll) { | 218 | while (start < tdll) { |
217 | /* | 219 | /* |
218 | * Check target descriptor identification with 0xE4 type with | 220 | * Check target descriptor identification with 0xE4 type, and |
219 | * 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 .. | ||
220 | */ | 223 | */ |
221 | switch (desc[0]) { | 224 | switch (desc[0]) { |
222 | case 0xe4: | 225 | case 0xe4: |
223 | rc = target_xcopy_parse_tiddesc_e4(se_cmd, xop, | 226 | rc = target_xcopy_parse_tiddesc_e4(se_cmd, xop, |
224 | &desc[0], src); | 227 | &desc[0], cscd_index); |
225 | if (rc != 0) | 228 | if (rc != 0) |
226 | goto out; | 229 | goto out; |
227 | /* | ||
228 | * Assume target descriptors are in source -> destination order.. | ||
229 | */ | ||
230 | if (src) | ||
231 | src = false; | ||
232 | else | ||
233 | src = true; | ||
234 | start += XCOPY_TARGET_DESC_LEN; | 230 | start += XCOPY_TARGET_DESC_LEN; |
235 | desc += XCOPY_TARGET_DESC_LEN; | 231 | desc += XCOPY_TARGET_DESC_LEN; |
236 | ret++; | 232 | cscd_index++; |
237 | break; | 233 | break; |
238 | default: | 234 | default: |
239 | pr_err("XCOPY unsupported descriptor type code:" | 235 | pr_err("XCOPY unsupported descriptor type code:" |
240 | " 0x%02x\n", desc[0]); | 236 | " 0x%02x\n", desc[0]); |
237 | *sense_ret = TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE; | ||
241 | goto out; | 238 | goto out; |
242 | } | 239 | } |
243 | } | 240 | } |
244 | 241 | ||
245 | if (xop->op_origin == XCOL_SOURCE_RECV_OP) | 242 | switch (xop->op_origin) { |
246 | rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, true); | 243 | case XCOL_SOURCE_RECV_OP: |
247 | else | 244 | rc = target_xcopy_locate_se_dev_e4(xop->dst_tid_wwn, |
248 | rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, false); | 245 | &xop->dst_dev); |
246 | break; | ||
247 | case XCOL_DEST_RECV_OP: | ||
248 | rc = target_xcopy_locate_se_dev_e4(xop->src_tid_wwn, | ||
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 | } | ||
249 | /* | 257 | /* |
250 | * If a matching IEEE NAA 0x83 descriptor for the requested device | 258 | * If a matching IEEE NAA 0x83 descriptor for the requested device |
251 | * 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 |
@@ -262,7 +270,7 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd, | |||
262 | 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", |
263 | xop->dst_dev, &xop->dst_tid_wwn[0]); | 271 | xop->dst_dev, &xop->dst_tid_wwn[0]); |
264 | 272 | ||
265 | return ret; | 273 | return cscd_index; |
266 | 274 | ||
267 | out: | 275 | out: |
268 | return -EINVAL; | 276 | return -EINVAL; |
@@ -284,6 +292,14 @@ static int target_xcopy_parse_segdesc_02(struct se_cmd *se_cmd, struct xcopy_op | |||
284 | 292 | ||
285 | xop->stdi = get_unaligned_be16(&desc[4]); | 293 | xop->stdi = get_unaligned_be16(&desc[4]); |
286 | xop->dtdi = get_unaligned_be16(&desc[6]); | 294 | xop->dtdi = get_unaligned_be16(&desc[6]); |
295 | |||
296 | if (xop->stdi > XCOPY_CSCD_DESC_ID_LIST_OFF_MAX || | ||
297 | xop->dtdi > XCOPY_CSCD_DESC_ID_LIST_OFF_MAX) { | ||
298 | pr_err("XCOPY segment desc 0x02: unsupported CSCD ID > 0x%x; stdi: %hu dtdi: %hu\n", | ||
299 | XCOPY_CSCD_DESC_ID_LIST_OFF_MAX, xop->stdi, xop->dtdi); | ||
300 | return -EINVAL; | ||
301 | } | ||
302 | |||
287 | pr_debug("XCOPY seg desc 0x02: desc_len: %hu stdi: %hu dtdi: %hu, DC: %d\n", | 303 | pr_debug("XCOPY seg desc 0x02: desc_len: %hu stdi: %hu dtdi: %hu, DC: %d\n", |
288 | desc_len, xop->stdi, xop->dtdi, dc); | 304 | desc_len, xop->stdi, xop->dtdi, dc); |
289 | 305 | ||
@@ -306,15 +322,25 @@ static int target_xcopy_parse_segdesc_02(struct se_cmd *se_cmd, struct xcopy_op | |||
306 | 322 | ||
307 | static int target_xcopy_parse_segment_descriptors(struct se_cmd *se_cmd, | 323 | static int target_xcopy_parse_segment_descriptors(struct se_cmd *se_cmd, |
308 | struct xcopy_op *xop, unsigned char *p, | 324 | struct xcopy_op *xop, unsigned char *p, |
309 | unsigned int sdll) | 325 | unsigned int sdll, sense_reason_t *sense_ret) |
310 | { | 326 | { |
311 | unsigned char *desc = p; | 327 | unsigned char *desc = p; |
312 | unsigned int start = 0; | 328 | unsigned int start = 0; |
313 | int offset = sdll % XCOPY_SEGMENT_DESC_LEN, rc, ret = 0; | 329 | int offset = sdll % XCOPY_SEGMENT_DESC_LEN, rc, ret = 0; |
314 | 330 | ||
331 | *sense_ret = TCM_INVALID_PARAMETER_LIST; | ||
332 | |||
315 | if (offset != 0) { | 333 | if (offset != 0) { |
316 | pr_err("XCOPY segment descriptor list length is not" | 334 | pr_err("XCOPY segment descriptor list length is not" |
317 | " multiple of %d\n", XCOPY_SEGMENT_DESC_LEN); | 335 | " multiple of %d\n", XCOPY_SEGMENT_DESC_LEN); |
336 | *sense_ret = TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE; | ||
337 | return -EINVAL; | ||
338 | } | ||
339 | if (sdll > RCR_OP_MAX_SG_DESC_COUNT * XCOPY_SEGMENT_DESC_LEN) { | ||
340 | pr_err("XCOPY supports %u segment descriptor(s), sdll: %u too" | ||
341 | " large..\n", RCR_OP_MAX_SG_DESC_COUNT, sdll); | ||
342 | /* spc4r37 6.4.3.5 SEGMENT DESCRIPTOR LIST LENGTH field */ | ||
343 | *sense_ret = TCM_TOO_MANY_SEGMENT_DESCS; | ||
318 | return -EINVAL; | 344 | return -EINVAL; |
319 | } | 345 | } |
320 | 346 | ||
@@ -335,6 +361,7 @@ static int target_xcopy_parse_segment_descriptors(struct se_cmd *se_cmd, | |||
335 | default: | 361 | default: |
336 | pr_err("XCOPY unsupported segment descriptor" | 362 | pr_err("XCOPY unsupported segment descriptor" |
337 | "type: 0x%02x\n", desc[0]); | 363 | "type: 0x%02x\n", desc[0]); |
364 | *sense_ret = TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE; | ||
338 | goto out; | 365 | goto out; |
339 | } | 366 | } |
340 | } | 367 | } |
@@ -861,6 +888,16 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd) | |||
861 | return TCM_UNSUPPORTED_SCSI_OPCODE; | 888 | return TCM_UNSUPPORTED_SCSI_OPCODE; |
862 | } | 889 | } |
863 | 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 | |||
864 | xop = kzalloc(sizeof(struct xcopy_op), GFP_KERNEL); | 901 | xop = kzalloc(sizeof(struct xcopy_op), GFP_KERNEL); |
865 | if (!xop) { | 902 | if (!xop) { |
866 | pr_err("Unable to allocate xcopy_op\n"); | 903 | pr_err("Unable to allocate xcopy_op\n"); |
@@ -883,6 +920,12 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd) | |||
883 | */ | 920 | */ |
884 | tdll = get_unaligned_be16(&p[2]); | 921 | tdll = get_unaligned_be16(&p[2]); |
885 | sdll = get_unaligned_be32(&p[8]); | 922 | sdll = get_unaligned_be32(&p[8]); |
923 | if (tdll + sdll > RCR_OP_MAX_DESC_LIST_LEN) { | ||
924 | pr_err("XCOPY descriptor list length %u exceeds maximum %u\n", | ||
925 | tdll + sdll, RCR_OP_MAX_DESC_LIST_LEN); | ||
926 | ret = TCM_PARAMETER_LIST_LENGTH_ERROR; | ||
927 | goto out; | ||
928 | } | ||
886 | 929 | ||
887 | inline_dl = get_unaligned_be32(&p[12]); | 930 | inline_dl = get_unaligned_be32(&p[12]); |
888 | if (inline_dl != 0) { | 931 | if (inline_dl != 0) { |
@@ -890,10 +933,32 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd) | |||
890 | goto out; | 933 | goto out; |
891 | } | 934 | } |
892 | 935 | ||
936 | if (se_cmd->data_length < (XCOPY_HDR_LEN + tdll + sdll + inline_dl)) { | ||
937 | pr_err("XCOPY parameter truncation: data length %u too small " | ||
938 | "for tdll: %hu sdll: %u inline_dl: %u\n", | ||
939 | se_cmd->data_length, tdll, sdll, inline_dl); | ||
940 | ret = TCM_PARAMETER_LIST_LENGTH_ERROR; | ||
941 | goto out; | ||
942 | } | ||
943 | |||
893 | pr_debug("Processing XCOPY with list_id: 0x%02x list_id_usage: 0x%02x" | 944 | pr_debug("Processing XCOPY with list_id: 0x%02x list_id_usage: 0x%02x" |
894 | " tdll: %hu sdll: %u inline_dl: %u\n", list_id, list_id_usage, | 945 | " tdll: %hu sdll: %u inline_dl: %u\n", list_id, list_id_usage, |
895 | tdll, sdll, inline_dl); | 946 | tdll, sdll, inline_dl); |
896 | 947 | ||
948 | /* | ||
949 | * skip over the target descriptors until segment descriptors | ||
950 | * have been passed - CSCD ids are needed to determine src and dest. | ||
951 | */ | ||
952 | seg_desc = &p[16] + tdll; | ||
953 | |||
954 | rc = target_xcopy_parse_segment_descriptors(se_cmd, xop, seg_desc, | ||
955 | sdll, &ret); | ||
956 | if (rc <= 0) | ||
957 | goto out; | ||
958 | |||
959 | pr_debug("XCOPY: Processed %d segment descriptors, length: %u\n", rc, | ||
960 | rc * XCOPY_SEGMENT_DESC_LEN); | ||
961 | |||
897 | rc = target_xcopy_parse_target_descriptors(se_cmd, xop, &p[16], tdll, &ret); | 962 | rc = target_xcopy_parse_target_descriptors(se_cmd, xop, &p[16], tdll, &ret); |
898 | if (rc <= 0) | 963 | if (rc <= 0) |
899 | goto out; | 964 | goto out; |
@@ -911,18 +976,8 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd) | |||
911 | 976 | ||
912 | pr_debug("XCOPY: Processed %d target descriptors, length: %u\n", rc, | 977 | pr_debug("XCOPY: Processed %d target descriptors, length: %u\n", rc, |
913 | rc * XCOPY_TARGET_DESC_LEN); | 978 | rc * XCOPY_TARGET_DESC_LEN); |
914 | seg_desc = &p[16]; | ||
915 | seg_desc += (rc * XCOPY_TARGET_DESC_LEN); | ||
916 | |||
917 | rc = target_xcopy_parse_segment_descriptors(se_cmd, xop, seg_desc, sdll); | ||
918 | if (rc <= 0) { | ||
919 | xcopy_pt_undepend_remotedev(xop); | ||
920 | goto out; | ||
921 | } | ||
922 | transport_kunmap_data_sg(se_cmd); | 979 | transport_kunmap_data_sg(se_cmd); |
923 | 980 | ||
924 | pr_debug("XCOPY: Processed %d segment descriptors, length: %u\n", rc, | ||
925 | rc * XCOPY_SEGMENT_DESC_LEN); | ||
926 | INIT_WORK(&xop->xop_work, target_xcopy_do_work); | 981 | INIT_WORK(&xop->xop_work, target_xcopy_do_work); |
927 | queue_work(xcopy_wq, &xop->xop_work); | 982 | queue_work(xcopy_wq, &xop->xop_work); |
928 | return TCM_NO_SENSE; | 983 | return TCM_NO_SENSE; |
diff --git a/drivers/target/target_core_xcopy.h b/drivers/target/target_core_xcopy.h index 4d3d4dd060f2..7c0b105cbe1b 100644 --- a/drivers/target/target_core_xcopy.h +++ b/drivers/target/target_core_xcopy.h | |||
@@ -1,10 +1,17 @@ | |||
1 | #include <target/target_core_base.h> | 1 | #include <target/target_core_base.h> |
2 | 2 | ||
3 | #define XCOPY_HDR_LEN 16 | ||
3 | #define XCOPY_TARGET_DESC_LEN 32 | 4 | #define XCOPY_TARGET_DESC_LEN 32 |
4 | #define XCOPY_SEGMENT_DESC_LEN 28 | 5 | #define XCOPY_SEGMENT_DESC_LEN 28 |
5 | #define XCOPY_NAA_IEEE_REGEX_LEN 16 | 6 | #define XCOPY_NAA_IEEE_REGEX_LEN 16 |
6 | #define XCOPY_MAX_SECTORS 1024 | 7 | #define XCOPY_MAX_SECTORS 1024 |
7 | 8 | ||
9 | /* | ||
10 | * SPC4r37 6.4.6.1 | ||
11 | * Table 150 — CSCD descriptor ID values | ||
12 | */ | ||
13 | #define XCOPY_CSCD_DESC_ID_LIST_OFF_MAX 0x07FF | ||
14 | |||
8 | enum xcopy_origin_list { | 15 | enum xcopy_origin_list { |
9 | XCOL_SOURCE_RECV_OP = 0x01, | 16 | XCOL_SOURCE_RECV_OP = 0x01, |
10 | XCOL_DEST_RECV_OP = 0x02, | 17 | XCOL_DEST_RECV_OP = 0x02, |
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 29e6858bb164..43edf82e54ff 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h | |||
@@ -174,6 +174,10 @@ enum tcm_sense_reason_table { | |||
174 | TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED = R(0x16), | 174 | TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED = R(0x16), |
175 | TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED = R(0x17), | 175 | TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED = R(0x17), |
176 | TCM_COPY_TARGET_DEVICE_NOT_REACHABLE = R(0x18), | 176 | TCM_COPY_TARGET_DEVICE_NOT_REACHABLE = R(0x18), |
177 | TCM_TOO_MANY_TARGET_DESCS = R(0x19), | ||
178 | TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE = R(0x1a), | ||
179 | TCM_TOO_MANY_SEGMENT_DESCS = R(0x1b), | ||
180 | TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE = R(0x1c), | ||
177 | #undef R | 181 | #undef R |
178 | }; | 182 | }; |
179 | 183 | ||