18c16567dSChristoph Hellwig // SPDX-License-Identifier: GPL-2.0
22341c2f8SMartin K. Petersen /*
32341c2f8SMartin K. Petersen * t10_pi.c - Functions for generating and verifying T10 Protection
42341c2f8SMartin K. Petersen * Information.
52341c2f8SMartin K. Petersen */
62341c2f8SMartin K. Petersen
72341c2f8SMartin K. Petersen #include <linux/t10-pi.h>
8fe45e630SChristoph Hellwig #include <linux/blk-integrity.h>
92341c2f8SMartin K. Petersen #include <linux/crc-t10dif.h>
10*a7d4383fSKeith Busch #include <linux/crc64.h>
11a754bd5fSHerbert Xu #include <linux/module.h>
122341c2f8SMartin K. Petersen #include <net/checksum.h>
13*a7d4383fSKeith Busch #include <asm/unaligned.h>
142341c2f8SMartin K. Petersen
152341c2f8SMartin K. Petersen typedef __be16 (csum_fn) (void *, unsigned int);
162341c2f8SMartin K. Petersen
t10_pi_crc_fn(void * data,unsigned int len)172341c2f8SMartin K. Petersen static __be16 t10_pi_crc_fn(void *data, unsigned int len)
182341c2f8SMartin K. Petersen {
192341c2f8SMartin K. Petersen return cpu_to_be16(crc_t10dif(data, len));
202341c2f8SMartin K. Petersen }
212341c2f8SMartin K. Petersen
t10_pi_ip_fn(void * data,unsigned int len)222341c2f8SMartin K. Petersen static __be16 t10_pi_ip_fn(void *data, unsigned int len)
232341c2f8SMartin K. Petersen {
242341c2f8SMartin K. Petersen return (__force __be16)ip_compute_csum(data, len);
252341c2f8SMartin K. Petersen }
262341c2f8SMartin K. Petersen
272341c2f8SMartin K. Petersen /*
282341c2f8SMartin K. Petersen * Type 1 and Type 2 protection use the same format: 16 bit guard tag,
292341c2f8SMartin K. Petersen * 16 bit app tag, 32 bit reference tag. Type 3 does not define the ref
302341c2f8SMartin K. Petersen * tag.
312341c2f8SMartin K. Petersen */
t10_pi_generate(struct blk_integrity_iter * iter,csum_fn * fn,enum t10_dif_type type)324e4cbee9SChristoph Hellwig static blk_status_t t10_pi_generate(struct blk_integrity_iter *iter,
335eaed68dSMax Gurtovoy csum_fn *fn, enum t10_dif_type type)
342341c2f8SMartin K. Petersen {
352341c2f8SMartin K. Petersen unsigned int i;
362341c2f8SMartin K. Petersen
372341c2f8SMartin K. Petersen for (i = 0 ; i < iter->data_size ; i += iter->interval) {
382341c2f8SMartin K. Petersen struct t10_pi_tuple *pi = iter->prot_buf;
392341c2f8SMartin K. Petersen
402341c2f8SMartin K. Petersen pi->guard_tag = fn(iter->data_buf, iter->interval);
412341c2f8SMartin K. Petersen pi->app_tag = 0;
422341c2f8SMartin K. Petersen
435eaed68dSMax Gurtovoy if (type == T10_PI_TYPE1_PROTECTION)
442341c2f8SMartin K. Petersen pi->ref_tag = cpu_to_be32(lower_32_bits(iter->seed));
452341c2f8SMartin K. Petersen else
462341c2f8SMartin K. Petersen pi->ref_tag = 0;
472341c2f8SMartin K. Petersen
482341c2f8SMartin K. Petersen iter->data_buf += iter->interval;
49c340b990SKeith Busch iter->prot_buf += iter->tuple_size;
502341c2f8SMartin K. Petersen iter->seed++;
512341c2f8SMartin K. Petersen }
522341c2f8SMartin K. Petersen
534e4cbee9SChristoph Hellwig return BLK_STS_OK;
542341c2f8SMartin K. Petersen }
552341c2f8SMartin K. Petersen
t10_pi_verify(struct blk_integrity_iter * iter,csum_fn * fn,enum t10_dif_type type)564e4cbee9SChristoph Hellwig static blk_status_t t10_pi_verify(struct blk_integrity_iter *iter,
575eaed68dSMax Gurtovoy csum_fn *fn, enum t10_dif_type type)
582341c2f8SMartin K. Petersen {
592341c2f8SMartin K. Petersen unsigned int i;
602341c2f8SMartin K. Petersen
61be21683eSMax Gurtovoy BUG_ON(type == T10_PI_TYPE0_PROTECTION);
62be21683eSMax Gurtovoy
632341c2f8SMartin K. Petersen for (i = 0 ; i < iter->data_size ; i += iter->interval) {
642341c2f8SMartin K. Petersen struct t10_pi_tuple *pi = iter->prot_buf;
652341c2f8SMartin K. Petersen __be16 csum;
662341c2f8SMartin K. Petersen
67be21683eSMax Gurtovoy if (type == T10_PI_TYPE1_PROTECTION ||
68be21683eSMax Gurtovoy type == T10_PI_TYPE2_PROTECTION) {
69128b6f9fSDmitry Monakhov if (pi->app_tag == T10_PI_APP_ESCAPE)
702341c2f8SMartin K. Petersen goto next;
712341c2f8SMartin K. Petersen
722341c2f8SMartin K. Petersen if (be32_to_cpu(pi->ref_tag) !=
732341c2f8SMartin K. Petersen lower_32_bits(iter->seed)) {
742341c2f8SMartin K. Petersen pr_err("%s: ref tag error at location %llu " \
752341c2f8SMartin K. Petersen "(rcvd %u)\n", iter->disk_name,
762341c2f8SMartin K. Petersen (unsigned long long)
772341c2f8SMartin K. Petersen iter->seed, be32_to_cpu(pi->ref_tag));
78a462b950SBart Van Assche return BLK_STS_PROTECTION;
792341c2f8SMartin K. Petersen }
80be21683eSMax Gurtovoy } else if (type == T10_PI_TYPE3_PROTECTION) {
81128b6f9fSDmitry Monakhov if (pi->app_tag == T10_PI_APP_ESCAPE &&
82128b6f9fSDmitry Monakhov pi->ref_tag == T10_PI_REF_ESCAPE)
832341c2f8SMartin K. Petersen goto next;
842341c2f8SMartin K. Petersen }
852341c2f8SMartin K. Petersen
862341c2f8SMartin K. Petersen csum = fn(iter->data_buf, iter->interval);
872341c2f8SMartin K. Petersen
882341c2f8SMartin K. Petersen if (pi->guard_tag != csum) {
892341c2f8SMartin K. Petersen pr_err("%s: guard tag error at sector %llu " \
902341c2f8SMartin K. Petersen "(rcvd %04x, want %04x)\n", iter->disk_name,
912341c2f8SMartin K. Petersen (unsigned long long)iter->seed,
922341c2f8SMartin K. Petersen be16_to_cpu(pi->guard_tag), be16_to_cpu(csum));
934e4cbee9SChristoph Hellwig return BLK_STS_PROTECTION;
942341c2f8SMartin K. Petersen }
952341c2f8SMartin K. Petersen
962341c2f8SMartin K. Petersen next:
972341c2f8SMartin K. Petersen iter->data_buf += iter->interval;
98c340b990SKeith Busch iter->prot_buf += iter->tuple_size;
992341c2f8SMartin K. Petersen iter->seed++;
1002341c2f8SMartin K. Petersen }
1012341c2f8SMartin K. Petersen
1024e4cbee9SChristoph Hellwig return BLK_STS_OK;
1032341c2f8SMartin K. Petersen }
1042341c2f8SMartin K. Petersen
t10_pi_type1_generate_crc(struct blk_integrity_iter * iter)1054e4cbee9SChristoph Hellwig static blk_status_t t10_pi_type1_generate_crc(struct blk_integrity_iter *iter)
1062341c2f8SMartin K. Petersen {
1075eaed68dSMax Gurtovoy return t10_pi_generate(iter, t10_pi_crc_fn, T10_PI_TYPE1_PROTECTION);
1082341c2f8SMartin K. Petersen }
1092341c2f8SMartin K. Petersen
t10_pi_type1_generate_ip(struct blk_integrity_iter * iter)1104e4cbee9SChristoph Hellwig static blk_status_t t10_pi_type1_generate_ip(struct blk_integrity_iter *iter)
1112341c2f8SMartin K. Petersen {
1125eaed68dSMax Gurtovoy return t10_pi_generate(iter, t10_pi_ip_fn, T10_PI_TYPE1_PROTECTION);
1132341c2f8SMartin K. Petersen }
1142341c2f8SMartin K. Petersen
t10_pi_type1_verify_crc(struct blk_integrity_iter * iter)1154e4cbee9SChristoph Hellwig static blk_status_t t10_pi_type1_verify_crc(struct blk_integrity_iter *iter)
1162341c2f8SMartin K. Petersen {
1175eaed68dSMax Gurtovoy return t10_pi_verify(iter, t10_pi_crc_fn, T10_PI_TYPE1_PROTECTION);
1182341c2f8SMartin K. Petersen }
1192341c2f8SMartin K. Petersen
t10_pi_type1_verify_ip(struct blk_integrity_iter * iter)1204e4cbee9SChristoph Hellwig static blk_status_t t10_pi_type1_verify_ip(struct blk_integrity_iter *iter)
1212341c2f8SMartin K. Petersen {
1225eaed68dSMax Gurtovoy return t10_pi_verify(iter, t10_pi_ip_fn, T10_PI_TYPE1_PROTECTION);
1232341c2f8SMartin K. Petersen }
1242341c2f8SMartin K. Petersen
12510c41dddSMax Gurtovoy /**
12654d4e6abSMax Gurtovoy * t10_pi_type1_prepare - prepare PI prior submitting request to device
12710c41dddSMax Gurtovoy * @rq: request with PI that should be prepared
12810c41dddSMax Gurtovoy *
12910c41dddSMax Gurtovoy * For Type 1/Type 2, the virtual start sector is the one that was
13010c41dddSMax Gurtovoy * originally submitted by the block layer for the ref_tag usage. Due to
13110c41dddSMax Gurtovoy * partitioning, MD/DM cloning, etc. the actual physical start sector is
13210c41dddSMax Gurtovoy * likely to be different. Remap protection information to match the
13310c41dddSMax Gurtovoy * physical LBA.
13410c41dddSMax Gurtovoy */
t10_pi_type1_prepare(struct request * rq)13554d4e6abSMax Gurtovoy static void t10_pi_type1_prepare(struct request *rq)
13610c41dddSMax Gurtovoy {
13710c41dddSMax Gurtovoy const int tuple_sz = rq->q->integrity.tuple_size;
13810c41dddSMax Gurtovoy u32 ref_tag = t10_pi_ref_tag(rq);
13910c41dddSMax Gurtovoy struct bio *bio;
14010c41dddSMax Gurtovoy
14110c41dddSMax Gurtovoy __rq_for_each_bio(bio, rq) {
14210c41dddSMax Gurtovoy struct bio_integrity_payload *bip = bio_integrity(bio);
14310c41dddSMax Gurtovoy u32 virt = bip_get_seed(bip) & 0xffffffff;
14410c41dddSMax Gurtovoy struct bio_vec iv;
14510c41dddSMax Gurtovoy struct bvec_iter iter;
14610c41dddSMax Gurtovoy
14710c41dddSMax Gurtovoy /* Already remapped? */
14810c41dddSMax Gurtovoy if (bip->bip_flags & BIP_MAPPED_INTEGRITY)
14910c41dddSMax Gurtovoy break;
15010c41dddSMax Gurtovoy
15110c41dddSMax Gurtovoy bip_for_each_vec(iv, bip, iter) {
15210c41dddSMax Gurtovoy unsigned int j;
1538aec120aSChristoph Hellwig void *p;
15410c41dddSMax Gurtovoy
1558aec120aSChristoph Hellwig p = bvec_kmap_local(&iv);
15610c41dddSMax Gurtovoy for (j = 0; j < iv.bv_len; j += tuple_sz) {
15710c41dddSMax Gurtovoy struct t10_pi_tuple *pi = p;
15810c41dddSMax Gurtovoy
15910c41dddSMax Gurtovoy if (be32_to_cpu(pi->ref_tag) == virt)
16010c41dddSMax Gurtovoy pi->ref_tag = cpu_to_be32(ref_tag);
16110c41dddSMax Gurtovoy virt++;
16210c41dddSMax Gurtovoy ref_tag++;
16310c41dddSMax Gurtovoy p += tuple_sz;
16410c41dddSMax Gurtovoy }
1658aec120aSChristoph Hellwig kunmap_local(p);
16610c41dddSMax Gurtovoy }
16710c41dddSMax Gurtovoy
16810c41dddSMax Gurtovoy bip->bip_flags |= BIP_MAPPED_INTEGRITY;
16910c41dddSMax Gurtovoy }
17010c41dddSMax Gurtovoy }
17110c41dddSMax Gurtovoy
17210c41dddSMax Gurtovoy /**
17354d4e6abSMax Gurtovoy * t10_pi_type1_complete - prepare PI prior returning request to the blk layer
17410c41dddSMax Gurtovoy * @rq: request with PI that should be prepared
17554d4e6abSMax Gurtovoy * @nr_bytes: total bytes to prepare
17610c41dddSMax Gurtovoy *
17710c41dddSMax Gurtovoy * For Type 1/Type 2, the virtual start sector is the one that was
17810c41dddSMax Gurtovoy * originally submitted by the block layer for the ref_tag usage. Due to
17910c41dddSMax Gurtovoy * partitioning, MD/DM cloning, etc. the actual physical start sector is
18010c41dddSMax Gurtovoy * likely to be different. Since the physical start sector was submitted
18110c41dddSMax Gurtovoy * to the device, we should remap it back to virtual values expected by the
18210c41dddSMax Gurtovoy * block layer.
18310c41dddSMax Gurtovoy */
t10_pi_type1_complete(struct request * rq,unsigned int nr_bytes)18454d4e6abSMax Gurtovoy static void t10_pi_type1_complete(struct request *rq, unsigned int nr_bytes)
18510c41dddSMax Gurtovoy {
18654d4e6abSMax Gurtovoy unsigned intervals = nr_bytes >> rq->q->integrity.interval_exp;
18710c41dddSMax Gurtovoy const int tuple_sz = rq->q->integrity.tuple_size;
18810c41dddSMax Gurtovoy u32 ref_tag = t10_pi_ref_tag(rq);
18910c41dddSMax Gurtovoy struct bio *bio;
19010c41dddSMax Gurtovoy
19110c41dddSMax Gurtovoy __rq_for_each_bio(bio, rq) {
19210c41dddSMax Gurtovoy struct bio_integrity_payload *bip = bio_integrity(bio);
19310c41dddSMax Gurtovoy u32 virt = bip_get_seed(bip) & 0xffffffff;
19410c41dddSMax Gurtovoy struct bio_vec iv;
19510c41dddSMax Gurtovoy struct bvec_iter iter;
19610c41dddSMax Gurtovoy
19710c41dddSMax Gurtovoy bip_for_each_vec(iv, bip, iter) {
19810c41dddSMax Gurtovoy unsigned int j;
1998aec120aSChristoph Hellwig void *p;
20010c41dddSMax Gurtovoy
2018aec120aSChristoph Hellwig p = bvec_kmap_local(&iv);
20210c41dddSMax Gurtovoy for (j = 0; j < iv.bv_len && intervals; j += tuple_sz) {
20310c41dddSMax Gurtovoy struct t10_pi_tuple *pi = p;
20410c41dddSMax Gurtovoy
20510c41dddSMax Gurtovoy if (be32_to_cpu(pi->ref_tag) == ref_tag)
20610c41dddSMax Gurtovoy pi->ref_tag = cpu_to_be32(virt);
20710c41dddSMax Gurtovoy virt++;
20810c41dddSMax Gurtovoy ref_tag++;
20910c41dddSMax Gurtovoy intervals--;
21010c41dddSMax Gurtovoy p += tuple_sz;
21110c41dddSMax Gurtovoy }
2128aec120aSChristoph Hellwig kunmap_local(p);
21310c41dddSMax Gurtovoy }
21410c41dddSMax Gurtovoy }
21510c41dddSMax Gurtovoy }
21654d4e6abSMax Gurtovoy
t10_pi_type3_generate_crc(struct blk_integrity_iter * iter)21754d4e6abSMax Gurtovoy static blk_status_t t10_pi_type3_generate_crc(struct blk_integrity_iter *iter)
21854d4e6abSMax Gurtovoy {
21954d4e6abSMax Gurtovoy return t10_pi_generate(iter, t10_pi_crc_fn, T10_PI_TYPE3_PROTECTION);
22054d4e6abSMax Gurtovoy }
22154d4e6abSMax Gurtovoy
t10_pi_type3_generate_ip(struct blk_integrity_iter * iter)22254d4e6abSMax Gurtovoy static blk_status_t t10_pi_type3_generate_ip(struct blk_integrity_iter *iter)
22354d4e6abSMax Gurtovoy {
22454d4e6abSMax Gurtovoy return t10_pi_generate(iter, t10_pi_ip_fn, T10_PI_TYPE3_PROTECTION);
22554d4e6abSMax Gurtovoy }
22654d4e6abSMax Gurtovoy
t10_pi_type3_verify_crc(struct blk_integrity_iter * iter)22754d4e6abSMax Gurtovoy static blk_status_t t10_pi_type3_verify_crc(struct blk_integrity_iter *iter)
22854d4e6abSMax Gurtovoy {
22954d4e6abSMax Gurtovoy return t10_pi_verify(iter, t10_pi_crc_fn, T10_PI_TYPE3_PROTECTION);
23054d4e6abSMax Gurtovoy }
23154d4e6abSMax Gurtovoy
t10_pi_type3_verify_ip(struct blk_integrity_iter * iter)23254d4e6abSMax Gurtovoy static blk_status_t t10_pi_type3_verify_ip(struct blk_integrity_iter *iter)
23354d4e6abSMax Gurtovoy {
23454d4e6abSMax Gurtovoy return t10_pi_verify(iter, t10_pi_ip_fn, T10_PI_TYPE3_PROTECTION);
23554d4e6abSMax Gurtovoy }
23654d4e6abSMax Gurtovoy
23798e54402SBart Van Assche /* Type 3 does not have a reference tag so no remapping is required. */
t10_pi_type3_prepare(struct request * rq)23854d4e6abSMax Gurtovoy static void t10_pi_type3_prepare(struct request *rq)
23954d4e6abSMax Gurtovoy {
24054d4e6abSMax Gurtovoy }
24154d4e6abSMax Gurtovoy
24298e54402SBart Van Assche /* Type 3 does not have a reference tag so no remapping is required. */
t10_pi_type3_complete(struct request * rq,unsigned int nr_bytes)24354d4e6abSMax Gurtovoy static void t10_pi_type3_complete(struct request *rq, unsigned int nr_bytes)
24454d4e6abSMax Gurtovoy {
24554d4e6abSMax Gurtovoy }
24654d4e6abSMax Gurtovoy
24754d4e6abSMax Gurtovoy const struct blk_integrity_profile t10_pi_type1_crc = {
24854d4e6abSMax Gurtovoy .name = "T10-DIF-TYPE1-CRC",
24954d4e6abSMax Gurtovoy .generate_fn = t10_pi_type1_generate_crc,
25054d4e6abSMax Gurtovoy .verify_fn = t10_pi_type1_verify_crc,
25154d4e6abSMax Gurtovoy .prepare_fn = t10_pi_type1_prepare,
25254d4e6abSMax Gurtovoy .complete_fn = t10_pi_type1_complete,
25354d4e6abSMax Gurtovoy };
25454d4e6abSMax Gurtovoy EXPORT_SYMBOL(t10_pi_type1_crc);
25554d4e6abSMax Gurtovoy
25654d4e6abSMax Gurtovoy const struct blk_integrity_profile t10_pi_type1_ip = {
25754d4e6abSMax Gurtovoy .name = "T10-DIF-TYPE1-IP",
25854d4e6abSMax Gurtovoy .generate_fn = t10_pi_type1_generate_ip,
25954d4e6abSMax Gurtovoy .verify_fn = t10_pi_type1_verify_ip,
26054d4e6abSMax Gurtovoy .prepare_fn = t10_pi_type1_prepare,
26154d4e6abSMax Gurtovoy .complete_fn = t10_pi_type1_complete,
26254d4e6abSMax Gurtovoy };
26354d4e6abSMax Gurtovoy EXPORT_SYMBOL(t10_pi_type1_ip);
26454d4e6abSMax Gurtovoy
26554d4e6abSMax Gurtovoy const struct blk_integrity_profile t10_pi_type3_crc = {
26654d4e6abSMax Gurtovoy .name = "T10-DIF-TYPE3-CRC",
26754d4e6abSMax Gurtovoy .generate_fn = t10_pi_type3_generate_crc,
26854d4e6abSMax Gurtovoy .verify_fn = t10_pi_type3_verify_crc,
26954d4e6abSMax Gurtovoy .prepare_fn = t10_pi_type3_prepare,
27054d4e6abSMax Gurtovoy .complete_fn = t10_pi_type3_complete,
27154d4e6abSMax Gurtovoy };
27254d4e6abSMax Gurtovoy EXPORT_SYMBOL(t10_pi_type3_crc);
27354d4e6abSMax Gurtovoy
27454d4e6abSMax Gurtovoy const struct blk_integrity_profile t10_pi_type3_ip = {
27554d4e6abSMax Gurtovoy .name = "T10-DIF-TYPE3-IP",
27654d4e6abSMax Gurtovoy .generate_fn = t10_pi_type3_generate_ip,
27754d4e6abSMax Gurtovoy .verify_fn = t10_pi_type3_verify_ip,
27854d4e6abSMax Gurtovoy .prepare_fn = t10_pi_type3_prepare,
27954d4e6abSMax Gurtovoy .complete_fn = t10_pi_type3_complete,
28054d4e6abSMax Gurtovoy };
28154d4e6abSMax Gurtovoy EXPORT_SYMBOL(t10_pi_type3_ip);
282a754bd5fSHerbert Xu
ext_pi_crc64(void * data,unsigned int len)283*a7d4383fSKeith Busch static __be64 ext_pi_crc64(void *data, unsigned int len)
284*a7d4383fSKeith Busch {
285*a7d4383fSKeith Busch return cpu_to_be64(crc64_rocksoft(data, len));
286*a7d4383fSKeith Busch }
287*a7d4383fSKeith Busch
ext_pi_crc64_generate(struct blk_integrity_iter * iter,enum t10_dif_type type)288*a7d4383fSKeith Busch static blk_status_t ext_pi_crc64_generate(struct blk_integrity_iter *iter,
289*a7d4383fSKeith Busch enum t10_dif_type type)
290*a7d4383fSKeith Busch {
291*a7d4383fSKeith Busch unsigned int i;
292*a7d4383fSKeith Busch
293*a7d4383fSKeith Busch for (i = 0 ; i < iter->data_size ; i += iter->interval) {
294*a7d4383fSKeith Busch struct crc64_pi_tuple *pi = iter->prot_buf;
295*a7d4383fSKeith Busch
296*a7d4383fSKeith Busch pi->guard_tag = ext_pi_crc64(iter->data_buf, iter->interval);
297*a7d4383fSKeith Busch pi->app_tag = 0;
298*a7d4383fSKeith Busch
299*a7d4383fSKeith Busch if (type == T10_PI_TYPE1_PROTECTION)
300*a7d4383fSKeith Busch put_unaligned_be48(iter->seed, pi->ref_tag);
301*a7d4383fSKeith Busch else
302*a7d4383fSKeith Busch put_unaligned_be48(0ULL, pi->ref_tag);
303*a7d4383fSKeith Busch
304*a7d4383fSKeith Busch iter->data_buf += iter->interval;
305*a7d4383fSKeith Busch iter->prot_buf += iter->tuple_size;
306*a7d4383fSKeith Busch iter->seed++;
307*a7d4383fSKeith Busch }
308*a7d4383fSKeith Busch
309*a7d4383fSKeith Busch return BLK_STS_OK;
310*a7d4383fSKeith Busch }
311*a7d4383fSKeith Busch
ext_pi_ref_escape(u8 * ref_tag)312*a7d4383fSKeith Busch static bool ext_pi_ref_escape(u8 *ref_tag)
313*a7d4383fSKeith Busch {
314*a7d4383fSKeith Busch static u8 ref_escape[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
315*a7d4383fSKeith Busch
316*a7d4383fSKeith Busch return memcmp(ref_tag, ref_escape, sizeof(ref_escape)) == 0;
317*a7d4383fSKeith Busch }
318*a7d4383fSKeith Busch
ext_pi_crc64_verify(struct blk_integrity_iter * iter,enum t10_dif_type type)319*a7d4383fSKeith Busch static blk_status_t ext_pi_crc64_verify(struct blk_integrity_iter *iter,
320*a7d4383fSKeith Busch enum t10_dif_type type)
321*a7d4383fSKeith Busch {
322*a7d4383fSKeith Busch unsigned int i;
323*a7d4383fSKeith Busch
324*a7d4383fSKeith Busch for (i = 0; i < iter->data_size; i += iter->interval) {
325*a7d4383fSKeith Busch struct crc64_pi_tuple *pi = iter->prot_buf;
326*a7d4383fSKeith Busch u64 ref, seed;
327*a7d4383fSKeith Busch __be64 csum;
328*a7d4383fSKeith Busch
329*a7d4383fSKeith Busch if (type == T10_PI_TYPE1_PROTECTION) {
330*a7d4383fSKeith Busch if (pi->app_tag == T10_PI_APP_ESCAPE)
331*a7d4383fSKeith Busch goto next;
332*a7d4383fSKeith Busch
333*a7d4383fSKeith Busch ref = get_unaligned_be48(pi->ref_tag);
334*a7d4383fSKeith Busch seed = lower_48_bits(iter->seed);
335*a7d4383fSKeith Busch if (ref != seed) {
336*a7d4383fSKeith Busch pr_err("%s: ref tag error at location %llu (rcvd %llu)\n",
337*a7d4383fSKeith Busch iter->disk_name, seed, ref);
338*a7d4383fSKeith Busch return BLK_STS_PROTECTION;
339*a7d4383fSKeith Busch }
340*a7d4383fSKeith Busch } else if (type == T10_PI_TYPE3_PROTECTION) {
341*a7d4383fSKeith Busch if (pi->app_tag == T10_PI_APP_ESCAPE &&
342*a7d4383fSKeith Busch ext_pi_ref_escape(pi->ref_tag))
343*a7d4383fSKeith Busch goto next;
344*a7d4383fSKeith Busch }
345*a7d4383fSKeith Busch
346*a7d4383fSKeith Busch csum = ext_pi_crc64(iter->data_buf, iter->interval);
347*a7d4383fSKeith Busch if (pi->guard_tag != csum) {
348*a7d4383fSKeith Busch pr_err("%s: guard tag error at sector %llu " \
349*a7d4383fSKeith Busch "(rcvd %016llx, want %016llx)\n",
350*a7d4383fSKeith Busch iter->disk_name, (unsigned long long)iter->seed,
351*a7d4383fSKeith Busch be64_to_cpu(pi->guard_tag), be64_to_cpu(csum));
352*a7d4383fSKeith Busch return BLK_STS_PROTECTION;
353*a7d4383fSKeith Busch }
354*a7d4383fSKeith Busch
355*a7d4383fSKeith Busch next:
356*a7d4383fSKeith Busch iter->data_buf += iter->interval;
357*a7d4383fSKeith Busch iter->prot_buf += iter->tuple_size;
358*a7d4383fSKeith Busch iter->seed++;
359*a7d4383fSKeith Busch }
360*a7d4383fSKeith Busch
361*a7d4383fSKeith Busch return BLK_STS_OK;
362*a7d4383fSKeith Busch }
363*a7d4383fSKeith Busch
ext_pi_type1_verify_crc64(struct blk_integrity_iter * iter)364*a7d4383fSKeith Busch static blk_status_t ext_pi_type1_verify_crc64(struct blk_integrity_iter *iter)
365*a7d4383fSKeith Busch {
366*a7d4383fSKeith Busch return ext_pi_crc64_verify(iter, T10_PI_TYPE1_PROTECTION);
367*a7d4383fSKeith Busch }
368*a7d4383fSKeith Busch
ext_pi_type1_generate_crc64(struct blk_integrity_iter * iter)369*a7d4383fSKeith Busch static blk_status_t ext_pi_type1_generate_crc64(struct blk_integrity_iter *iter)
370*a7d4383fSKeith Busch {
371*a7d4383fSKeith Busch return ext_pi_crc64_generate(iter, T10_PI_TYPE1_PROTECTION);
372*a7d4383fSKeith Busch }
373*a7d4383fSKeith Busch
ext_pi_type1_prepare(struct request * rq)374*a7d4383fSKeith Busch static void ext_pi_type1_prepare(struct request *rq)
375*a7d4383fSKeith Busch {
376*a7d4383fSKeith Busch const int tuple_sz = rq->q->integrity.tuple_size;
377*a7d4383fSKeith Busch u64 ref_tag = ext_pi_ref_tag(rq);
378*a7d4383fSKeith Busch struct bio *bio;
379*a7d4383fSKeith Busch
380*a7d4383fSKeith Busch __rq_for_each_bio(bio, rq) {
381*a7d4383fSKeith Busch struct bio_integrity_payload *bip = bio_integrity(bio);
382*a7d4383fSKeith Busch u64 virt = lower_48_bits(bip_get_seed(bip));
383*a7d4383fSKeith Busch struct bio_vec iv;
384*a7d4383fSKeith Busch struct bvec_iter iter;
385*a7d4383fSKeith Busch
386*a7d4383fSKeith Busch /* Already remapped? */
387*a7d4383fSKeith Busch if (bip->bip_flags & BIP_MAPPED_INTEGRITY)
388*a7d4383fSKeith Busch break;
389*a7d4383fSKeith Busch
390*a7d4383fSKeith Busch bip_for_each_vec(iv, bip, iter) {
391*a7d4383fSKeith Busch unsigned int j;
392*a7d4383fSKeith Busch void *p;
393*a7d4383fSKeith Busch
394*a7d4383fSKeith Busch p = bvec_kmap_local(&iv);
395*a7d4383fSKeith Busch for (j = 0; j < iv.bv_len; j += tuple_sz) {
396*a7d4383fSKeith Busch struct crc64_pi_tuple *pi = p;
397*a7d4383fSKeith Busch u64 ref = get_unaligned_be48(pi->ref_tag);
398*a7d4383fSKeith Busch
399*a7d4383fSKeith Busch if (ref == virt)
400*a7d4383fSKeith Busch put_unaligned_be48(ref_tag, pi->ref_tag);
401*a7d4383fSKeith Busch virt++;
402*a7d4383fSKeith Busch ref_tag++;
403*a7d4383fSKeith Busch p += tuple_sz;
404*a7d4383fSKeith Busch }
405*a7d4383fSKeith Busch kunmap_local(p);
406*a7d4383fSKeith Busch }
407*a7d4383fSKeith Busch
408*a7d4383fSKeith Busch bip->bip_flags |= BIP_MAPPED_INTEGRITY;
409*a7d4383fSKeith Busch }
410*a7d4383fSKeith Busch }
411*a7d4383fSKeith Busch
ext_pi_type1_complete(struct request * rq,unsigned int nr_bytes)412*a7d4383fSKeith Busch static void ext_pi_type1_complete(struct request *rq, unsigned int nr_bytes)
413*a7d4383fSKeith Busch {
414*a7d4383fSKeith Busch unsigned intervals = nr_bytes >> rq->q->integrity.interval_exp;
415*a7d4383fSKeith Busch const int tuple_sz = rq->q->integrity.tuple_size;
416*a7d4383fSKeith Busch u64 ref_tag = ext_pi_ref_tag(rq);
417*a7d4383fSKeith Busch struct bio *bio;
418*a7d4383fSKeith Busch
419*a7d4383fSKeith Busch __rq_for_each_bio(bio, rq) {
420*a7d4383fSKeith Busch struct bio_integrity_payload *bip = bio_integrity(bio);
421*a7d4383fSKeith Busch u64 virt = lower_48_bits(bip_get_seed(bip));
422*a7d4383fSKeith Busch struct bio_vec iv;
423*a7d4383fSKeith Busch struct bvec_iter iter;
424*a7d4383fSKeith Busch
425*a7d4383fSKeith Busch bip_for_each_vec(iv, bip, iter) {
426*a7d4383fSKeith Busch unsigned int j;
427*a7d4383fSKeith Busch void *p;
428*a7d4383fSKeith Busch
429*a7d4383fSKeith Busch p = bvec_kmap_local(&iv);
430*a7d4383fSKeith Busch for (j = 0; j < iv.bv_len && intervals; j += tuple_sz) {
431*a7d4383fSKeith Busch struct crc64_pi_tuple *pi = p;
432*a7d4383fSKeith Busch u64 ref = get_unaligned_be48(pi->ref_tag);
433*a7d4383fSKeith Busch
434*a7d4383fSKeith Busch if (ref == ref_tag)
435*a7d4383fSKeith Busch put_unaligned_be48(virt, pi->ref_tag);
436*a7d4383fSKeith Busch virt++;
437*a7d4383fSKeith Busch ref_tag++;
438*a7d4383fSKeith Busch intervals--;
439*a7d4383fSKeith Busch p += tuple_sz;
440*a7d4383fSKeith Busch }
441*a7d4383fSKeith Busch kunmap_local(p);
442*a7d4383fSKeith Busch }
443*a7d4383fSKeith Busch }
444*a7d4383fSKeith Busch }
445*a7d4383fSKeith Busch
ext_pi_type3_verify_crc64(struct blk_integrity_iter * iter)446*a7d4383fSKeith Busch static blk_status_t ext_pi_type3_verify_crc64(struct blk_integrity_iter *iter)
447*a7d4383fSKeith Busch {
448*a7d4383fSKeith Busch return ext_pi_crc64_verify(iter, T10_PI_TYPE3_PROTECTION);
449*a7d4383fSKeith Busch }
450*a7d4383fSKeith Busch
ext_pi_type3_generate_crc64(struct blk_integrity_iter * iter)451*a7d4383fSKeith Busch static blk_status_t ext_pi_type3_generate_crc64(struct blk_integrity_iter *iter)
452*a7d4383fSKeith Busch {
453*a7d4383fSKeith Busch return ext_pi_crc64_generate(iter, T10_PI_TYPE3_PROTECTION);
454*a7d4383fSKeith Busch }
455*a7d4383fSKeith Busch
456*a7d4383fSKeith Busch const struct blk_integrity_profile ext_pi_type1_crc64 = {
457*a7d4383fSKeith Busch .name = "EXT-DIF-TYPE1-CRC64",
458*a7d4383fSKeith Busch .generate_fn = ext_pi_type1_generate_crc64,
459*a7d4383fSKeith Busch .verify_fn = ext_pi_type1_verify_crc64,
460*a7d4383fSKeith Busch .prepare_fn = ext_pi_type1_prepare,
461*a7d4383fSKeith Busch .complete_fn = ext_pi_type1_complete,
462*a7d4383fSKeith Busch };
463*a7d4383fSKeith Busch EXPORT_SYMBOL_GPL(ext_pi_type1_crc64);
464*a7d4383fSKeith Busch
465*a7d4383fSKeith Busch const struct blk_integrity_profile ext_pi_type3_crc64 = {
466*a7d4383fSKeith Busch .name = "EXT-DIF-TYPE3-CRC64",
467*a7d4383fSKeith Busch .generate_fn = ext_pi_type3_generate_crc64,
468*a7d4383fSKeith Busch .verify_fn = ext_pi_type3_verify_crc64,
469*a7d4383fSKeith Busch .prepare_fn = t10_pi_type3_prepare,
470*a7d4383fSKeith Busch .complete_fn = t10_pi_type3_complete,
471*a7d4383fSKeith Busch };
472*a7d4383fSKeith Busch EXPORT_SYMBOL_GPL(ext_pi_type3_crc64);
473*a7d4383fSKeith Busch
474*a7d4383fSKeith Busch MODULE_LICENSE("GPL");
475a754bd5fSHerbert Xu MODULE_LICENSE("GPL");
476