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