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 86ef1400f27e..1a83456a65a0 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c | |||
@@ -306,24 +306,50 @@ static void free_data_area(struct tcmu_dev *udev, struct tcmu_cmd *cmd) | |||
306 | DATA_BLOCK_BITS); | 306 | DATA_BLOCK_BITS); |
307 | } | 307 | } |
308 | 308 | ||
309 | static void gather_data_area(struct tcmu_dev *udev, unsigned long *cmd_bitmap, | 309 | static void gather_data_area(struct tcmu_dev *udev, struct tcmu_cmd *cmd, |
310 | struct scatterlist *data_sg, unsigned int data_nents) | 310 | bool bidi) |
311 | { | 311 | { |
312 | struct se_cmd *se_cmd = cmd->se_cmd; | ||
312 | int i, block; | 313 | int i, block; |
313 | int block_remaining = 0; | 314 | int block_remaining = 0; |
314 | void *from, *to; | 315 | void *from, *to; |
315 | size_t copy_bytes, from_offset; | 316 | size_t copy_bytes, from_offset; |
316 | struct scatterlist *sg; | 317 | struct scatterlist *sg, *data_sg; |
318 | unsigned int data_nents; | ||
319 | DECLARE_BITMAP(bitmap, DATA_BLOCK_BITS); | ||
320 | |||
321 | bitmap_copy(bitmap, cmd->data_bitmap, DATA_BLOCK_BITS); | ||
322 | |||
323 | if (!bidi) { | ||
324 | data_sg = se_cmd->t_data_sg; | ||
325 | data_nents = se_cmd->t_data_nents; | ||
326 | } else { | ||
327 | uint32_t count; | ||
328 | |||
329 | /* | ||
330 | * For bidi case, the first count blocks are for Data-Out | ||
331 | * buffer blocks, and before gathering the Data-In buffer | ||
332 | * the Data-Out buffer blocks should be discarded. | ||
333 | */ | ||
334 | count = DIV_ROUND_UP(se_cmd->data_length, DATA_BLOCK_SIZE); | ||
335 | while (count--) { | ||
336 | block = find_first_bit(bitmap, DATA_BLOCK_BITS); | ||
337 | clear_bit(block, bitmap); | ||
338 | } | ||
339 | |||
340 | data_sg = se_cmd->t_bidi_data_sg; | ||
341 | data_nents = se_cmd->t_bidi_data_nents; | ||
342 | } | ||
317 | 343 | ||
318 | for_each_sg(data_sg, sg, data_nents, i) { | 344 | for_each_sg(data_sg, sg, data_nents, i) { |
319 | int sg_remaining = sg->length; | 345 | int sg_remaining = sg->length; |
320 | to = kmap_atomic(sg_page(sg)) + sg->offset; | 346 | to = kmap_atomic(sg_page(sg)) + sg->offset; |
321 | while (sg_remaining > 0) { | 347 | while (sg_remaining > 0) { |
322 | if (block_remaining == 0) { | 348 | if (block_remaining == 0) { |
323 | block = find_first_bit(cmd_bitmap, | 349 | block = find_first_bit(bitmap, |
324 | DATA_BLOCK_BITS); | 350 | DATA_BLOCK_BITS); |
325 | block_remaining = DATA_BLOCK_SIZE; | 351 | block_remaining = DATA_BLOCK_SIZE; |
326 | clear_bit(block, cmd_bitmap); | 352 | clear_bit(block, bitmap); |
327 | } | 353 | } |
328 | copy_bytes = min_t(size_t, sg_remaining, | 354 | copy_bytes = min_t(size_t, sg_remaining, |
329 | block_remaining); | 355 | block_remaining); |
@@ -600,19 +626,11 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry * | |||
600 | se_cmd->scsi_sense_length); | 626 | se_cmd->scsi_sense_length); |
601 | free_data_area(udev, cmd); | 627 | free_data_area(udev, cmd); |
602 | } else if (se_cmd->se_cmd_flags & SCF_BIDI) { | 628 | } else if (se_cmd->se_cmd_flags & SCF_BIDI) { |
603 | DECLARE_BITMAP(bitmap, DATA_BLOCK_BITS); | ||
604 | |||
605 | /* Get Data-In buffer before clean up */ | 629 | /* Get Data-In buffer before clean up */ |
606 | bitmap_copy(bitmap, cmd->data_bitmap, DATA_BLOCK_BITS); | 630 | gather_data_area(udev, cmd, true); |
607 | gather_data_area(udev, bitmap, | ||
608 | se_cmd->t_bidi_data_sg, se_cmd->t_bidi_data_nents); | ||
609 | free_data_area(udev, cmd); | 631 | free_data_area(udev, cmd); |
610 | } else if (se_cmd->data_direction == DMA_FROM_DEVICE) { | 632 | } else if (se_cmd->data_direction == DMA_FROM_DEVICE) { |
611 | DECLARE_BITMAP(bitmap, DATA_BLOCK_BITS); | 633 | gather_data_area(udev, cmd, false); |
612 | |||
613 | bitmap_copy(bitmap, cmd->data_bitmap, DATA_BLOCK_BITS); | ||
614 | gather_data_area(udev, bitmap, | ||
615 | se_cmd->t_data_sg, se_cmd->t_data_nents); | ||
616 | free_data_area(udev, cmd); | 634 | free_data_area(udev, cmd); |
617 | } else if (se_cmd->data_direction == DMA_TO_DEVICE) { | 635 | } else if (se_cmd->data_direction == DMA_TO_DEVICE) { |
618 | free_data_area(udev, cmd); | 636 | free_data_area(udev, cmd); |