Added headers and macros required by NVME target
[compat-rdma/compat.git] / include / linux / scatterlist.h
1 #ifndef _COMPAT_LINUX_SCATTERLIST_H
2 #define _COMPAT_LINUX_SCATTERLIST_H
3
4 #include "../../compat/config.h"
5 #include <linux/version.h>
6
7 #include_next <linux/scatterlist.h>
8
9 #if (KERNEL_VERSION(4, 8, 0) <= LINUX_VERSION_CODE) || \
10         (defined(RHEL_MAJOR) && RHEL_MAJOR -0 == 7 && RHEL_MINOR -0 >= 4)
11 #ifndef HAVE_SG_ZERO_BUFFER
12 /**
13  * sg_zero_buffer - Zero-out a part of a SG list
14  * @sgl:                 The SG list
15  * @nents:               Number of SG entries
16  * @buflen:              The number of bytes to zero out
17  * @skip:                Number of bytes to skip before zeroing
18  *
19  * Returns the number of bytes zeroed.
20  **/
21 static inline size_t sg_zero_buffer(struct scatterlist *sgl, unsigned int nents,
22                        size_t buflen, off_t skip)
23 {
24         unsigned int offset = 0;
25         struct sg_mapping_iter miter;
26         unsigned int sg_flags = SG_MITER_ATOMIC | SG_MITER_TO_SG;
27
28         sg_miter_start(&miter, sgl, nents, sg_flags);
29
30         if (!sg_miter_skip(&miter, skip))
31                 return false;
32
33         while (offset < buflen && sg_miter_next(&miter)) {
34                 unsigned int len;
35
36                 len = min(miter.length, buflen - offset);
37                 memset(miter.addr, 0, len);
38
39                 offset += len;
40         }
41
42         sg_miter_stop(&miter);
43         return offset;
44 }
45 #endif /* HAVE_SG_ZERO_BUFFER */
46
47 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0) */
48
49 #if defined(RHEL_MAJOR) && RHEL_MAJOR -0 == 7 && RHEL_MINOR -0 >= 2
50 #if !defined(HAVE_SG_ALLOC_TABLE_CHAINED_4_PARAMS) && \
51     !defined(HAVE_SG_ALLOC_TABLE_CHAINED_3_PARAMS)
52
53 #include <scsi/scsi.h>
54 #include <linux/mempool.h>
55
56 struct sg_pool {
57         size_t          size;
58         char            *name;
59         struct kmem_cache       *slab;
60         mempool_t       *pool;
61 };
62
63 #define SP(x) { .size = x, "sgpool-" __stringify(x) }
64 #if (SCSI_MAX_SG_SEGMENTS < 32)
65 #error SCSI_MAX_SG_SEGMENTS is too small (must be 32 or greater)
66 #endif
67 static struct sg_pool sg_pools[] = {
68         SP(8),
69         SP(16),
70 #if (SCSI_MAX_SG_SEGMENTS > 32)
71         SP(32),
72 #if (SCSI_MAX_SG_SEGMENTS > 64)
73         SP(64),
74 #if (SCSI_MAX_SG_SEGMENTS > 128)
75         SP(128),
76 #if (SCSI_MAX_SG_SEGMENTS > 256)
77 #error SCSI_MAX_SG_SEGMENTS is too large (256 MAX)
78 #endif
79 #endif
80 #endif
81 #endif
82         SP(SCSI_MAX_SG_SEGMENTS)
83 };
84 #undef SP
85
86 static inline unsigned int sg_pool_index(unsigned short nents)
87 {
88         unsigned int index;
89
90         BUG_ON(nents > SCSI_MAX_SG_SEGMENTS);
91
92         if (nents <= 8)
93                 index = 0;
94         else
95                 index = get_count_order(nents) - 3;
96
97         return index;
98 }
99
100 static inline void sg_pool_free(struct scatterlist *sgl, unsigned int nents)
101 {
102         struct sg_pool *sgp;
103
104         sgp = sg_pools + sg_pool_index(nents);
105         mempool_free(sgl, sgp->pool);
106 }
107
108 static inline struct scatterlist *sg_pool_alloc(unsigned int nents, gfp_t gfp_mask)
109 {
110         struct sg_pool *sgp;
111
112         sgp = sg_pools + sg_pool_index(nents);
113         return mempool_alloc(sgp->pool, gfp_mask);
114 }
115
116 static inline void sg_free_table_chained(struct sg_table *table, bool first_chunk)
117 {
118         if (first_chunk && table->orig_nents <= SCSI_MAX_SG_SEGMENTS)
119                 return;
120         __sg_free_table(table, SCSI_MAX_SG_SEGMENTS, first_chunk, sg_pool_free);
121 }
122
123 static inline int sg_alloc_table_chained(struct sg_table *table, int nents,
124                 struct scatterlist *first_chunk)
125 {
126         int ret;
127
128         BUG_ON(!nents);
129
130         if (first_chunk) {
131                 if (nents <= SCSI_MAX_SG_SEGMENTS) {
132                         table->nents = table->orig_nents = nents;
133                         sg_init_table(table->sgl, nents);
134                         return 0;
135                 }
136         }
137
138         ret = __sg_alloc_table(table, nents, SCSI_MAX_SG_SEGMENTS,
139                                first_chunk, GFP_ATOMIC, sg_pool_alloc);
140         if (unlikely(ret))
141                 sg_free_table_chained(table, (bool)first_chunk);
142         return ret;
143 }
144 #endif
145 #endif /* defined(RHEL_MAJOR) && RHEL_MAJOR -0 == 7 && RHEL_MINOR -0 >= 2 */
146
147 #endif /* _COMPAT_LINUX_SCATTERLIST_H */