diff options
-rw-r--r-- | drivers/target/target_core_user.c | 48 |
1 files changed, 33 insertions, 15 deletions
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 9885d1b521fe..f615c3bbb73e 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c | |||
@@ -311,24 +311,50 @@ static void free_data_area(struct tcmu_dev *udev, struct tcmu_cmd *cmd) | |||
311 | DATA_BLOCK_BITS); | 311 | DATA_BLOCK_BITS); |
312 | } | 312 | } |
313 | 313 | ||
314 | static void gather_data_area(struct tcmu_dev *udev, unsigned long *cmd_bitmap, | 314 | static void gather_data_area(struct tcmu_dev *udev, struct tcmu_cmd *cmd, |
315 | struct scatterlist *data_sg, unsigned int data_nents) | 315 | bool bidi) |
316 | { | 316 | { |
317 | struct se_cmd *se_cmd = cmd->se_cmd; | ||
317 | int i, block; | 318 | int i, block; |
318 | int block_remaining = 0; | 319 | int block_remaining = 0; |
319 | void *from, *to; | 320 | void *from, *to; |
320 | size_t copy_bytes, from_offset; | 321 | size_t copy_bytes, from_offset; |
321 | struct scatterlist *sg; | 322 | struct scatterlist *sg, *data_sg; |
323 | unsigned int data_nents; | ||
324 | DECLARE_BITMAP(bitmap, DATA_BLOCK_BITS); | ||
325 | |||
326 | bitmap_copy(bitmap, cmd->data_bitmap, DATA_BLOCK_BITS); | ||
327 | |||
328 | if (!bidi) { | ||
329 | data_sg = se_cmd->t_data_sg; | ||
330 | data_nents = se_cmd->t_data_nents; | ||
331 | } else { | ||
332 | uint32_t count; | ||
333 | |||
334 | /* | ||
335 | * For bidi case, the first count blocks are for Data-Out | ||
336 | * buffer blocks, and before gathering the Data-In buffer | ||
337 | * the Data-Out buffer blocks should be discarded. | ||
338 | */ | ||
339 | count = DIV_ROUND_UP(se_cmd->data_length, DATA_BLOCK_SIZE); | ||
340 | while (count--) { | ||
341 | block = find_first_bit(bitmap, DATA_BLOCK_BITS); | ||
342 | clear_bit(block, bitmap); | ||
343 | } | ||
344 | |||
345 | data_sg = se_cmd->t_bidi_data_sg; | ||
346 | data_nents = se_cmd->t_bidi_data_nents; | ||
347 | } | ||
322 | 348 | ||
323 | for_each_sg(data_sg, sg, data_nents, i) { | 349 | for_each_sg(data_sg, sg, data_nents, i) { |
324 | int sg_remaining = sg->length; | 350 | int sg_remaining = sg->length; |
325 | to = kmap_atomic(sg_page(sg)) + sg->offset; | 351 | to = kmap_atomic(sg_page(sg)) + sg->offset; |
326 | while (sg_remaining > 0) { | 352 | while (sg_remaining > 0) { |
327 | if (block_remaining == 0) { | 353 | if (block_remaining == 0) { |
328 | block = find_first_bit(cmd_bitmap, | 354 | block = find_first_bit(bitmap, |
329 | DATA_BLOCK_BITS); | 355 | DATA_BLOCK_BITS); |
330 | block_remaining = DATA_BLOCK_SIZE; | 356 | block_remaining = DATA_BLOCK_SIZE; |
331 | clear_bit(block, cmd_bitmap); | 357 | clear_bit(block, bitmap); |
332 | } | 358 | } |
333 | copy_bytes = min_t(size_t, sg_remaining, | 359 | copy_bytes = min_t(size_t, sg_remaining, |
334 | block_remaining); | 360 | block_remaining); |
@@ -610,19 +636,11 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry * | |||
610 | se_cmd->scsi_sense_length); | 636 | se_cmd->scsi_sense_length); |
611 | free_data_area(udev, cmd); | 637 | free_data_area(udev, cmd); |
612 | } else if (se_cmd->se_cmd_flags & SCF_BIDI) { | 638 | } else if (se_cmd->se_cmd_flags & SCF_BIDI) { |
613 | DECLARE_BITMAP(bitmap, DATA_BLOCK_BITS); | ||
614 | |||
615 | /* Get Data-In buffer before clean up */ | 639 | /* Get Data-In buffer before clean up */ |
616 | bitmap_copy(bitmap, cmd->data_bitmap, DATA_BLOCK_BITS); | 640 | gather_data_area(udev, cmd, true); |
617 | gather_data_area(udev, bitmap, | ||
618 | se_cmd->t_bidi_data_sg, se_cmd->t_bidi_data_nents); | ||
619 | free_data_area(udev, cmd); | 641 | free_data_area(udev, cmd); |
620 | } else if (se_cmd->data_direction == DMA_FROM_DEVICE) { | 642 | } else if (se_cmd->data_direction == DMA_FROM_DEVICE) { |
621 | DECLARE_BITMAP(bitmap, DATA_BLOCK_BITS); | 643 | gather_data_area(udev, cmd, false); |
622 | |||
623 | bitmap_copy(bitmap, cmd->data_bitmap, DATA_BLOCK_BITS); | ||
624 | gather_data_area(udev, bitmap, | ||
625 | se_cmd->t_data_sg, se_cmd->t_data_nents); | ||
626 | free_data_area(udev, cmd); | 644 | free_data_area(udev, cmd); |
627 | } else if (se_cmd->data_direction == DMA_TO_DEVICE) { | 645 | } else if (se_cmd->data_direction == DMA_TO_DEVICE) { |
628 | free_data_area(udev, cmd); | 646 | free_data_area(udev, cmd); |