1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include <linux/t10-pi.h>
25#include <linux/blkdev.h>
26#include <linux/crc-t10dif.h>
27#include <net/checksum.h>
28
29typedef __be16 (csum_fn) (void *, unsigned int);
30
31static __be16 t10_pi_crc_fn(void *data, unsigned int len)
32{
33 return cpu_to_be16(crc_t10dif(data, len));
34}
35
36static __be16 t10_pi_ip_fn(void *data, unsigned int len)
37{
38 return (__force __be16)ip_compute_csum(data, len);
39}
40
41
42
43
44
45
46static blk_status_t t10_pi_generate(struct blk_integrity_iter *iter,
47 csum_fn *fn, enum t10_dif_type type)
48{
49 unsigned int i;
50
51 for (i = 0 ; i < iter->data_size ; i += iter->interval) {
52 struct t10_pi_tuple *pi = iter->prot_buf;
53
54 pi->guard_tag = fn(iter->data_buf, iter->interval);
55 pi->app_tag = 0;
56
57 if (type == T10_PI_TYPE1_PROTECTION)
58 pi->ref_tag = cpu_to_be32(lower_32_bits(iter->seed));
59 else
60 pi->ref_tag = 0;
61
62 iter->data_buf += iter->interval;
63 iter->prot_buf += sizeof(struct t10_pi_tuple);
64 iter->seed++;
65 }
66
67 return BLK_STS_OK;
68}
69
70static blk_status_t t10_pi_verify(struct blk_integrity_iter *iter,
71 csum_fn *fn, enum t10_dif_type type)
72{
73 unsigned int i;
74
75 BUG_ON(type == T10_PI_TYPE0_PROTECTION);
76
77 for (i = 0 ; i < iter->data_size ; i += iter->interval) {
78 struct t10_pi_tuple *pi = iter->prot_buf;
79 __be16 csum;
80
81 if (type == T10_PI_TYPE1_PROTECTION ||
82 type == T10_PI_TYPE2_PROTECTION) {
83 if (pi->app_tag == T10_PI_APP_ESCAPE)
84 goto next;
85
86 if (be32_to_cpu(pi->ref_tag) !=
87 lower_32_bits(iter->seed)) {
88 pr_err("%s: ref tag error at location %llu " \
89 "(rcvd %u)\n", iter->disk_name,
90 (unsigned long long)
91 iter->seed, be32_to_cpu(pi->ref_tag));
92 return BLK_STS_PROTECTION;
93 }
94 } else if (type == T10_PI_TYPE3_PROTECTION) {
95 if (pi->app_tag == T10_PI_APP_ESCAPE &&
96 pi->ref_tag == T10_PI_REF_ESCAPE)
97 goto next;
98 }
99
100 csum = fn(iter->data_buf, iter->interval);
101
102 if (pi->guard_tag != csum) {
103 pr_err("%s: guard tag error at sector %llu " \
104 "(rcvd %04x, want %04x)\n", iter->disk_name,
105 (unsigned long long)iter->seed,
106 be16_to_cpu(pi->guard_tag), be16_to_cpu(csum));
107 return BLK_STS_PROTECTION;
108 }
109
110next:
111 iter->data_buf += iter->interval;
112 iter->prot_buf += sizeof(struct t10_pi_tuple);
113 iter->seed++;
114 }
115
116 return BLK_STS_OK;
117}
118
119static blk_status_t t10_pi_type1_generate_crc(struct blk_integrity_iter *iter)
120{
121 return t10_pi_generate(iter, t10_pi_crc_fn, T10_PI_TYPE1_PROTECTION);
122}
123
124static blk_status_t t10_pi_type1_generate_ip(struct blk_integrity_iter *iter)
125{
126 return t10_pi_generate(iter, t10_pi_ip_fn, T10_PI_TYPE1_PROTECTION);
127}
128
129static blk_status_t t10_pi_type1_verify_crc(struct blk_integrity_iter *iter)
130{
131 return t10_pi_verify(iter, t10_pi_crc_fn, T10_PI_TYPE1_PROTECTION);
132}
133
134static blk_status_t t10_pi_type1_verify_ip(struct blk_integrity_iter *iter)
135{
136 return t10_pi_verify(iter, t10_pi_ip_fn, T10_PI_TYPE1_PROTECTION);
137}
138
139
140
141
142
143
144
145
146
147
148
149static void t10_pi_type1_prepare(struct request *rq)
150{
151 const int tuple_sz = rq->q->integrity.tuple_size;
152 u32 ref_tag = t10_pi_ref_tag(rq);
153 struct bio *bio;
154
155 __rq_for_each_bio(bio, rq) {
156 struct bio_integrity_payload *bip = bio_integrity(bio);
157 u32 virt = bip_get_seed(bip) & 0xffffffff;
158 struct bio_vec iv;
159 struct bvec_iter iter;
160
161
162 if (bip->bip_flags & BIP_MAPPED_INTEGRITY)
163 break;
164
165 bip_for_each_vec(iv, bip, iter) {
166 void *p, *pmap;
167 unsigned int j;
168
169 pmap = kmap_atomic(iv.bv_page);
170 p = pmap + iv.bv_offset;
171 for (j = 0; j < iv.bv_len; j += tuple_sz) {
172 struct t10_pi_tuple *pi = p;
173
174 if (be32_to_cpu(pi->ref_tag) == virt)
175 pi->ref_tag = cpu_to_be32(ref_tag);
176 virt++;
177 ref_tag++;
178 p += tuple_sz;
179 }
180
181 kunmap_atomic(pmap);
182 }
183
184 bip->bip_flags |= BIP_MAPPED_INTEGRITY;
185 }
186}
187
188
189
190
191
192
193
194
195
196
197
198
199
200static void t10_pi_type1_complete(struct request *rq, unsigned int nr_bytes)
201{
202 unsigned intervals = nr_bytes >> rq->q->integrity.interval_exp;
203 const int tuple_sz = rq->q->integrity.tuple_size;
204 u32 ref_tag = t10_pi_ref_tag(rq);
205 struct bio *bio;
206
207 __rq_for_each_bio(bio, rq) {
208 struct bio_integrity_payload *bip = bio_integrity(bio);
209 u32 virt = bip_get_seed(bip) & 0xffffffff;
210 struct bio_vec iv;
211 struct bvec_iter iter;
212
213 bip_for_each_vec(iv, bip, iter) {
214 void *p, *pmap;
215 unsigned int j;
216
217 pmap = kmap_atomic(iv.bv_page);
218 p = pmap + iv.bv_offset;
219 for (j = 0; j < iv.bv_len && intervals; j += tuple_sz) {
220 struct t10_pi_tuple *pi = p;
221
222 if (be32_to_cpu(pi->ref_tag) == ref_tag)
223 pi->ref_tag = cpu_to_be32(virt);
224 virt++;
225 ref_tag++;
226 intervals--;
227 p += tuple_sz;
228 }
229
230 kunmap_atomic(pmap);
231 }
232 }
233}
234
235static blk_status_t t10_pi_type3_generate_crc(struct blk_integrity_iter *iter)
236{
237 return t10_pi_generate(iter, t10_pi_crc_fn, T10_PI_TYPE3_PROTECTION);
238}
239
240static blk_status_t t10_pi_type3_generate_ip(struct blk_integrity_iter *iter)
241{
242 return t10_pi_generate(iter, t10_pi_ip_fn, T10_PI_TYPE3_PROTECTION);
243}
244
245static blk_status_t t10_pi_type3_verify_crc(struct blk_integrity_iter *iter)
246{
247 return t10_pi_verify(iter, t10_pi_crc_fn, T10_PI_TYPE3_PROTECTION);
248}
249
250static blk_status_t t10_pi_type3_verify_ip(struct blk_integrity_iter *iter)
251{
252 return t10_pi_verify(iter, t10_pi_ip_fn, T10_PI_TYPE3_PROTECTION);
253}
254
255
256static void t10_pi_type3_prepare(struct request *rq)
257{
258}
259
260
261static void t10_pi_type3_complete(struct request *rq, unsigned int nr_bytes)
262{
263}
264
265static const struct blk_integrity_profile_ext_ops t10_pi_type1_ops = {
266 .prepare_fn = t10_pi_type1_prepare,
267 .complete_fn = t10_pi_type1_complete,
268};
269
270const struct blk_integrity_profile t10_pi_type1_crc = {
271 .name = "T10-DIF-TYPE1-CRC",
272 .generate_fn = t10_pi_type1_generate_crc,
273 .verify_fn = t10_pi_type1_verify_crc,
274 .ext_ops = &t10_pi_type1_ops,
275};
276EXPORT_SYMBOL(t10_pi_type1_crc);
277
278const struct blk_integrity_profile t10_pi_type1_ip = {
279 .name = "T10-DIF-TYPE1-IP",
280 .generate_fn = t10_pi_type1_generate_ip,
281 .verify_fn = t10_pi_type1_verify_ip,
282 .ext_ops = &t10_pi_type1_ops,
283};
284EXPORT_SYMBOL(t10_pi_type1_ip);
285
286static const struct blk_integrity_profile_ext_ops t10_pi_type3_ops = {
287 .prepare_fn = t10_pi_type3_prepare,
288 .complete_fn = t10_pi_type3_complete,
289};
290
291const struct blk_integrity_profile t10_pi_type3_crc = {
292 .name = "T10-DIF-TYPE3-CRC",
293 .generate_fn = t10_pi_type3_generate_crc,
294 .verify_fn = t10_pi_type3_verify_crc,
295 .ext_ops = &t10_pi_type3_ops,
296};
297EXPORT_SYMBOL(t10_pi_type3_crc);
298
299const struct blk_integrity_profile t10_pi_type3_ip = {
300 .name = "T10-DIF-TYPE3-IP",
301 .generate_fn = t10_pi_type3_generate_ip,
302 .verify_fn = t10_pi_type3_verify_ip,
303 .ext_ops = &t10_pi_type3_ops,
304};
305EXPORT_SYMBOL(t10_pi_type3_ip);
306