diff options
| -rw-r--r-- | drivers/infiniband/ulp/iser/iscsi_iser.h | 8 | ||||
| -rw-r--r-- | drivers/infiniband/ulp/iser/iser_initiator.c | 8 | ||||
| -rw-r--r-- | drivers/infiniband/ulp/iser/iser_memory.c | 209 |
3 files changed, 137 insertions, 88 deletions
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index a39645a54d82..262ba1f8ee50 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h | |||
| @@ -222,12 +222,9 @@ enum iser_data_dir { | |||
| 222 | * @size: num entries of this sg | 222 | * @size: num entries of this sg |
| 223 | * @data_len: total beffer byte len | 223 | * @data_len: total beffer byte len |
| 224 | * @dma_nents: returned by dma_map_sg | 224 | * @dma_nents: returned by dma_map_sg |
| 225 | * @copy_buf: allocated copy buf for SGs unaligned | ||
| 226 | * for rdma which are copied | ||
| 227 | * @orig_sg: pointer to the original sg list (in case | 225 | * @orig_sg: pointer to the original sg list (in case |
| 228 | * we used a copy) | 226 | * we used a copy) |
| 229 | * @sg_single: SG-ified clone of a non SG SC or | 227 | * @orig_size: num entris of orig sg list |
| 230 | * unaligned SG | ||
| 231 | */ | 228 | */ |
| 232 | struct iser_data_buf { | 229 | struct iser_data_buf { |
| 233 | struct scatterlist *sg; | 230 | struct scatterlist *sg; |
| @@ -235,8 +232,7 @@ struct iser_data_buf { | |||
| 235 | unsigned long data_len; | 232 | unsigned long data_len; |
| 236 | unsigned int dma_nents; | 233 | unsigned int dma_nents; |
| 237 | struct scatterlist *orig_sg; | 234 | struct scatterlist *orig_sg; |
| 238 | char *copy_buf; | 235 | unsigned int orig_size; |
| 239 | struct scatterlist sg_single; | ||
| 240 | }; | 236 | }; |
| 241 | 237 | ||
| 242 | /* fwd declarations */ | 238 | /* fwd declarations */ |
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index b2e3b77340b5..3e2118e8ed87 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c | |||
| @@ -674,28 +674,28 @@ void iser_task_rdma_finalize(struct iscsi_iser_task *iser_task) | |||
| 674 | /* if we were reading, copy back to unaligned sglist, | 674 | /* if we were reading, copy back to unaligned sglist, |
| 675 | * anyway dma_unmap and free the copy | 675 | * anyway dma_unmap and free the copy |
| 676 | */ | 676 | */ |
| 677 | if (iser_task->data[ISER_DIR_IN].copy_buf) { | 677 | if (iser_task->data[ISER_DIR_IN].orig_sg) { |
| 678 | is_rdma_data_aligned = 0; | 678 | is_rdma_data_aligned = 0; |
| 679 | iser_finalize_rdma_unaligned_sg(iser_task, | 679 | iser_finalize_rdma_unaligned_sg(iser_task, |
| 680 | &iser_task->data[ISER_DIR_IN], | 680 | &iser_task->data[ISER_DIR_IN], |
| 681 | ISER_DIR_IN); | 681 | ISER_DIR_IN); |
| 682 | } | 682 | } |
| 683 | 683 | ||
| 684 | if (iser_task->data[ISER_DIR_OUT].copy_buf) { | 684 | if (iser_task->data[ISER_DIR_OUT].orig_sg) { |
| 685 | is_rdma_data_aligned = 0; | 685 | is_rdma_data_aligned = 0; |
| 686 | iser_finalize_rdma_unaligned_sg(iser_task, | 686 | iser_finalize_rdma_unaligned_sg(iser_task, |
| 687 | &iser_task->data[ISER_DIR_OUT], | 687 | &iser_task->data[ISER_DIR_OUT], |
| 688 | ISER_DIR_OUT); | 688 | ISER_DIR_OUT); |
| 689 | } | 689 | } |
| 690 | 690 | ||
| 691 | if (iser_task->prot[ISER_DIR_IN].copy_buf) { | 691 | if (iser_task->prot[ISER_DIR_IN].orig_sg) { |
| 692 | is_rdma_prot_aligned = 0; | 692 | is_rdma_prot_aligned = 0; |
| 693 | iser_finalize_rdma_unaligned_sg(iser_task, | 693 | iser_finalize_rdma_unaligned_sg(iser_task, |
| 694 | &iser_task->prot[ISER_DIR_IN], | 694 | &iser_task->prot[ISER_DIR_IN], |
| 695 | ISER_DIR_IN); | 695 | ISER_DIR_IN); |
| 696 | } | 696 | } |
| 697 | 697 | ||
| 698 | if (iser_task->prot[ISER_DIR_OUT].copy_buf) { | 698 | if (iser_task->prot[ISER_DIR_OUT].orig_sg) { |
| 699 | is_rdma_prot_aligned = 0; | 699 | is_rdma_prot_aligned = 0; |
| 700 | iser_finalize_rdma_unaligned_sg(iser_task, | 700 | iser_finalize_rdma_unaligned_sg(iser_task, |
| 701 | &iser_task->prot[ISER_DIR_OUT], | 701 | &iser_task->prot[ISER_DIR_OUT], |
diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index abc979e62ae1..f0cdc961eb11 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c | |||
| @@ -39,7 +39,112 @@ | |||
| 39 | 39 | ||
| 40 | #include "iscsi_iser.h" | 40 | #include "iscsi_iser.h" |
| 41 | 41 | ||
| 42 | #define ISER_KMALLOC_THRESHOLD 0x20000 /* 128K - kmalloc limit */ | 42 | static void |
| 43 | iser_free_bounce_sg(struct iser_data_buf *data) | ||
| 44 | { | ||
| 45 | struct scatterlist *sg; | ||
| 46 | int count; | ||
| 47 | |||
| 48 | for_each_sg(data->sg, sg, data->size, count) | ||
| 49 | __free_page(sg_page(sg)); | ||
| 50 | |||
| 51 | kfree(data->sg); | ||
| 52 | |||
| 53 | data->sg = data->orig_sg; | ||
| 54 | data->size = data->orig_size; | ||
| 55 | data->orig_sg = NULL; | ||
| 56 | data->orig_size = 0; | ||
| 57 | } | ||
| 58 | |||
| 59 | static int | ||
| 60 | iser_alloc_bounce_sg(struct iser_data_buf *data) | ||
| 61 | { | ||
| 62 | struct scatterlist *sg; | ||
| 63 | struct page *page; | ||
| 64 | unsigned long length = data->data_len; | ||
| 65 | int i = 0, nents = DIV_ROUND_UP(length, PAGE_SIZE); | ||
| 66 | |||
| 67 | sg = kcalloc(nents, sizeof(*sg), GFP_ATOMIC); | ||
| 68 | if (!sg) | ||
| 69 | goto err; | ||
| 70 | |||
| 71 | sg_init_table(sg, nents); | ||
| 72 | while (length) { | ||
| 73 | u32 page_len = min_t(u32, length, PAGE_SIZE); | ||
| 74 | |||
| 75 | page = alloc_page(GFP_ATOMIC); | ||
| 76 | if (!page) | ||
| 77 | goto err; | ||
| 78 | |||
| 79 | sg_set_page(&sg[i], page, page_len, 0); | ||
| 80 | length -= page_len; | ||
| 81 | i++; | ||
| 82 | } | ||
| 83 | |||
| 84 | data->orig_sg = data->sg; | ||
| 85 | data->orig_size = data->size; | ||
| 86 | data->sg = sg; | ||
| 87 | data->size = nents; | ||
| 88 | |||
| 89 | return 0; | ||
| 90 | |||
| 91 | err: | ||
| 92 | for (; i > 0; i--) | ||
| 93 | __free_page(sg_page(&sg[i - 1])); | ||
| 94 | kfree(sg); | ||
| 95 | |||
| 96 | return -ENOMEM; | ||
| 97 | } | ||
| 98 | |||
| 99 | static void | ||
| 100 | iser_copy_bounce(struct iser_data_buf *data, bool to_buffer) | ||
| 101 | { | ||
| 102 | struct scatterlist *osg, *bsg = data->sg; | ||
| 103 | void *oaddr, *baddr; | ||
| 104 | unsigned int left = data->data_len; | ||
| 105 | unsigned int bsg_off = 0; | ||
| 106 | int i; | ||
| 107 | |||
| 108 | for_each_sg(data->orig_sg, osg, data->orig_size, i) { | ||
| 109 | unsigned int copy_len, osg_off = 0; | ||
| 110 | |||
| 111 | oaddr = kmap_atomic(sg_page(osg)) + osg->offset; | ||
| 112 | copy_len = min(left, osg->length); | ||
| 113 | while (copy_len) { | ||
| 114 | unsigned int len = min(copy_len, bsg->length - bsg_off); | ||
| 115 | |||
| 116 | baddr = kmap_atomic(sg_page(bsg)) + bsg->offset; | ||
| 117 | if (to_buffer) | ||
| 118 | memcpy(baddr + bsg_off, oaddr + osg_off, len); | ||
| 119 | else | ||
| 120 | memcpy(oaddr + osg_off, baddr + bsg_off, len); | ||
| 121 | |||
| 122 | kunmap_atomic(baddr - bsg->offset); | ||
| 123 | osg_off += len; | ||
| 124 | bsg_off += len; | ||
| 125 | copy_len -= len; | ||
| 126 | |||
| 127 | if (bsg_off >= bsg->length) { | ||
| 128 | bsg = sg_next(bsg); | ||
| 129 | bsg_off = 0; | ||
| 130 | } | ||
| 131 | } | ||
| 132 | kunmap_atomic(oaddr - osg->offset); | ||
| 133 | left -= osg_off; | ||
| 134 | } | ||
| 135 | } | ||
| 136 | |||
| 137 | static inline void | ||
| 138 | iser_copy_from_bounce(struct iser_data_buf *data) | ||
| 139 | { | ||
| 140 | iser_copy_bounce(data, false); | ||
| 141 | } | ||
| 142 | |||
| 143 | static inline void | ||
| 144 | iser_copy_to_bounce(struct iser_data_buf *data) | ||
| 145 | { | ||
| 146 | iser_copy_bounce(data, true); | ||
| 147 | } | ||
| 43 | 148 | ||
| 44 | struct fast_reg_descriptor * | 149 | struct fast_reg_descriptor * |
| 45 | iser_reg_desc_get(struct ib_conn *ib_conn) | 150 | iser_reg_desc_get(struct ib_conn *ib_conn) |
| @@ -75,52 +180,32 @@ static int iser_start_rdma_unali | |||
