aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/target/target_core_user.c48
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
309static void gather_data_area(struct tcmu_dev *udev, unsigned long *cmd_bitmap, 309static 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);