162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * t10_pi.c - Functions for generating and verifying T10 Protection 462306a36Sopenharmony_ci * Information. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/t10-pi.h> 862306a36Sopenharmony_ci#include <linux/blk-integrity.h> 962306a36Sopenharmony_ci#include <linux/crc-t10dif.h> 1062306a36Sopenharmony_ci#include <linux/crc64.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <net/checksum.h> 1362306a36Sopenharmony_ci#include <asm/unaligned.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_citypedef __be16 (csum_fn) (void *, unsigned int); 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistatic __be16 t10_pi_crc_fn(void *data, unsigned int len) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci return cpu_to_be16(crc_t10dif(data, len)); 2062306a36Sopenharmony_ci} 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic __be16 t10_pi_ip_fn(void *data, unsigned int len) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci return (__force __be16)ip_compute_csum(data, len); 2562306a36Sopenharmony_ci} 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* 2862306a36Sopenharmony_ci * Type 1 and Type 2 protection use the same format: 16 bit guard tag, 2962306a36Sopenharmony_ci * 16 bit app tag, 32 bit reference tag. Type 3 does not define the ref 3062306a36Sopenharmony_ci * tag. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_cistatic blk_status_t t10_pi_generate(struct blk_integrity_iter *iter, 3362306a36Sopenharmony_ci csum_fn *fn, enum t10_dif_type type) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci unsigned int i; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci for (i = 0 ; i < iter->data_size ; i += iter->interval) { 3862306a36Sopenharmony_ci struct t10_pi_tuple *pi = iter->prot_buf; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci pi->guard_tag = fn(iter->data_buf, iter->interval); 4162306a36Sopenharmony_ci pi->app_tag = 0; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci if (type == T10_PI_TYPE1_PROTECTION) 4462306a36Sopenharmony_ci pi->ref_tag = cpu_to_be32(lower_32_bits(iter->seed)); 4562306a36Sopenharmony_ci else 4662306a36Sopenharmony_ci pi->ref_tag = 0; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci iter->data_buf += iter->interval; 4962306a36Sopenharmony_ci iter->prot_buf += iter->tuple_size; 5062306a36Sopenharmony_ci iter->seed++; 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci return BLK_STS_OK; 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic blk_status_t t10_pi_verify(struct blk_integrity_iter *iter, 5762306a36Sopenharmony_ci csum_fn *fn, enum t10_dif_type type) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci unsigned int i; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci BUG_ON(type == T10_PI_TYPE0_PROTECTION); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci for (i = 0 ; i < iter->data_size ; i += iter->interval) { 6462306a36Sopenharmony_ci struct t10_pi_tuple *pi = iter->prot_buf; 6562306a36Sopenharmony_ci __be16 csum; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (type == T10_PI_TYPE1_PROTECTION || 6862306a36Sopenharmony_ci type == T10_PI_TYPE2_PROTECTION) { 6962306a36Sopenharmony_ci if (pi->app_tag == T10_PI_APP_ESCAPE) 7062306a36Sopenharmony_ci goto next; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (be32_to_cpu(pi->ref_tag) != 7362306a36Sopenharmony_ci lower_32_bits(iter->seed)) { 7462306a36Sopenharmony_ci pr_err("%s: ref tag error at location %llu " \ 7562306a36Sopenharmony_ci "(rcvd %u)\n", iter->disk_name, 7662306a36Sopenharmony_ci (unsigned long long) 7762306a36Sopenharmony_ci iter->seed, be32_to_cpu(pi->ref_tag)); 7862306a36Sopenharmony_ci return BLK_STS_PROTECTION; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci } else if (type == T10_PI_TYPE3_PROTECTION) { 8162306a36Sopenharmony_ci if (pi->app_tag == T10_PI_APP_ESCAPE && 8262306a36Sopenharmony_ci pi->ref_tag == T10_PI_REF_ESCAPE) 8362306a36Sopenharmony_ci goto next; 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci csum = fn(iter->data_buf, iter->interval); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if (pi->guard_tag != csum) { 8962306a36Sopenharmony_ci pr_err("%s: guard tag error at sector %llu " \ 9062306a36Sopenharmony_ci "(rcvd %04x, want %04x)\n", iter->disk_name, 9162306a36Sopenharmony_ci (unsigned long long)iter->seed, 9262306a36Sopenharmony_ci be16_to_cpu(pi->guard_tag), be16_to_cpu(csum)); 9362306a36Sopenharmony_ci return BLK_STS_PROTECTION; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cinext: 9762306a36Sopenharmony_ci iter->data_buf += iter->interval; 9862306a36Sopenharmony_ci iter->prot_buf += iter->tuple_size; 9962306a36Sopenharmony_ci iter->seed++; 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci return BLK_STS_OK; 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic blk_status_t t10_pi_type1_generate_crc(struct blk_integrity_iter *iter) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci return t10_pi_generate(iter, t10_pi_crc_fn, T10_PI_TYPE1_PROTECTION); 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic blk_status_t t10_pi_type1_generate_ip(struct blk_integrity_iter *iter) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci return t10_pi_generate(iter, t10_pi_ip_fn, T10_PI_TYPE1_PROTECTION); 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic blk_status_t t10_pi_type1_verify_crc(struct blk_integrity_iter *iter) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci return t10_pi_verify(iter, t10_pi_crc_fn, T10_PI_TYPE1_PROTECTION); 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic blk_status_t t10_pi_type1_verify_ip(struct blk_integrity_iter *iter) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci return t10_pi_verify(iter, t10_pi_ip_fn, T10_PI_TYPE1_PROTECTION); 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci/** 12662306a36Sopenharmony_ci * t10_pi_type1_prepare - prepare PI prior submitting request to device 12762306a36Sopenharmony_ci * @rq: request with PI that should be prepared 12862306a36Sopenharmony_ci * 12962306a36Sopenharmony_ci * For Type 1/Type 2, the virtual start sector is the one that was 13062306a36Sopenharmony_ci * originally submitted by the block layer for the ref_tag usage. Due to 13162306a36Sopenharmony_ci * partitioning, MD/DM cloning, etc. the actual physical start sector is 13262306a36Sopenharmony_ci * likely to be different. Remap protection information to match the 13362306a36Sopenharmony_ci * physical LBA. 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_cistatic void t10_pi_type1_prepare(struct request *rq) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci const int tuple_sz = rq->q->integrity.tuple_size; 13862306a36Sopenharmony_ci u32 ref_tag = t10_pi_ref_tag(rq); 13962306a36Sopenharmony_ci struct bio *bio; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci __rq_for_each_bio(bio, rq) { 14262306a36Sopenharmony_ci struct bio_integrity_payload *bip = bio_integrity(bio); 14362306a36Sopenharmony_ci u32 virt = bip_get_seed(bip) & 0xffffffff; 14462306a36Sopenharmony_ci struct bio_vec iv; 14562306a36Sopenharmony_ci struct bvec_iter iter; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* Already remapped? */ 14862306a36Sopenharmony_ci if (bip->bip_flags & BIP_MAPPED_INTEGRITY) 14962306a36Sopenharmony_ci break; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci bip_for_each_vec(iv, bip, iter) { 15262306a36Sopenharmony_ci unsigned int j; 15362306a36Sopenharmony_ci void *p; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci p = bvec_kmap_local(&iv); 15662306a36Sopenharmony_ci for (j = 0; j < iv.bv_len; j += tuple_sz) { 15762306a36Sopenharmony_ci struct t10_pi_tuple *pi = p; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (be32_to_cpu(pi->ref_tag) == virt) 16062306a36Sopenharmony_ci pi->ref_tag = cpu_to_be32(ref_tag); 16162306a36Sopenharmony_ci virt++; 16262306a36Sopenharmony_ci ref_tag++; 16362306a36Sopenharmony_ci p += tuple_sz; 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci kunmap_local(p); 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci bip->bip_flags |= BIP_MAPPED_INTEGRITY; 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci/** 17362306a36Sopenharmony_ci * t10_pi_type1_complete - prepare PI prior returning request to the blk layer 17462306a36Sopenharmony_ci * @rq: request with PI that should be prepared 17562306a36Sopenharmony_ci * @nr_bytes: total bytes to prepare 17662306a36Sopenharmony_ci * 17762306a36Sopenharmony_ci * For Type 1/Type 2, the virtual start sector is the one that was 17862306a36Sopenharmony_ci * originally submitted by the block layer for the ref_tag usage. Due to 17962306a36Sopenharmony_ci * partitioning, MD/DM cloning, etc. the actual physical start sector is 18062306a36Sopenharmony_ci * likely to be different. Since the physical start sector was submitted 18162306a36Sopenharmony_ci * to the device, we should remap it back to virtual values expected by the 18262306a36Sopenharmony_ci * block layer. 18362306a36Sopenharmony_ci */ 18462306a36Sopenharmony_cistatic void t10_pi_type1_complete(struct request *rq, unsigned int nr_bytes) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci unsigned intervals = nr_bytes >> rq->q->integrity.interval_exp; 18762306a36Sopenharmony_ci const int tuple_sz = rq->q->integrity.tuple_size; 18862306a36Sopenharmony_ci u32 ref_tag = t10_pi_ref_tag(rq); 18962306a36Sopenharmony_ci struct bio *bio; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci __rq_for_each_bio(bio, rq) { 19262306a36Sopenharmony_ci struct bio_integrity_payload *bip = bio_integrity(bio); 19362306a36Sopenharmony_ci u32 virt = bip_get_seed(bip) & 0xffffffff; 19462306a36Sopenharmony_ci struct bio_vec iv; 19562306a36Sopenharmony_ci struct bvec_iter iter; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci bip_for_each_vec(iv, bip, iter) { 19862306a36Sopenharmony_ci unsigned int j; 19962306a36Sopenharmony_ci void *p; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci p = bvec_kmap_local(&iv); 20262306a36Sopenharmony_ci for (j = 0; j < iv.bv_len && intervals; j += tuple_sz) { 20362306a36Sopenharmony_ci struct t10_pi_tuple *pi = p; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (be32_to_cpu(pi->ref_tag) == ref_tag) 20662306a36Sopenharmony_ci pi->ref_tag = cpu_to_be32(virt); 20762306a36Sopenharmony_ci virt++; 20862306a36Sopenharmony_ci ref_tag++; 20962306a36Sopenharmony_ci intervals--; 21062306a36Sopenharmony_ci p += tuple_sz; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci kunmap_local(p); 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic blk_status_t t10_pi_type3_generate_crc(struct blk_integrity_iter *iter) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci return t10_pi_generate(iter, t10_pi_crc_fn, T10_PI_TYPE3_PROTECTION); 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistatic blk_status_t t10_pi_type3_generate_ip(struct blk_integrity_iter *iter) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci return t10_pi_generate(iter, t10_pi_ip_fn, T10_PI_TYPE3_PROTECTION); 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic blk_status_t t10_pi_type3_verify_crc(struct blk_integrity_iter *iter) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci return t10_pi_verify(iter, t10_pi_crc_fn, T10_PI_TYPE3_PROTECTION); 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic blk_status_t t10_pi_type3_verify_ip(struct blk_integrity_iter *iter) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci return t10_pi_verify(iter, t10_pi_ip_fn, T10_PI_TYPE3_PROTECTION); 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci/* Type 3 does not have a reference tag so no remapping is required. */ 23862306a36Sopenharmony_cistatic void t10_pi_type3_prepare(struct request *rq) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci/* Type 3 does not have a reference tag so no remapping is required. */ 24362306a36Sopenharmony_cistatic void t10_pi_type3_complete(struct request *rq, unsigned int nr_bytes) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ciconst struct blk_integrity_profile t10_pi_type1_crc = { 24862306a36Sopenharmony_ci .name = "T10-DIF-TYPE1-CRC", 24962306a36Sopenharmony_ci .generate_fn = t10_pi_type1_generate_crc, 25062306a36Sopenharmony_ci .verify_fn = t10_pi_type1_verify_crc, 25162306a36Sopenharmony_ci .prepare_fn = t10_pi_type1_prepare, 25262306a36Sopenharmony_ci .complete_fn = t10_pi_type1_complete, 25362306a36Sopenharmony_ci}; 25462306a36Sopenharmony_ciEXPORT_SYMBOL(t10_pi_type1_crc); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ciconst struct blk_integrity_profile t10_pi_type1_ip = { 25762306a36Sopenharmony_ci .name = "T10-DIF-TYPE1-IP", 25862306a36Sopenharmony_ci .generate_fn = t10_pi_type1_generate_ip, 25962306a36Sopenharmony_ci .verify_fn = t10_pi_type1_verify_ip, 26062306a36Sopenharmony_ci .prepare_fn = t10_pi_type1_prepare, 26162306a36Sopenharmony_ci .complete_fn = t10_pi_type1_complete, 26262306a36Sopenharmony_ci}; 26362306a36Sopenharmony_ciEXPORT_SYMBOL(t10_pi_type1_ip); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ciconst struct blk_integrity_profile t10_pi_type3_crc = { 26662306a36Sopenharmony_ci .name = "T10-DIF-TYPE3-CRC", 26762306a36Sopenharmony_ci .generate_fn = t10_pi_type3_generate_crc, 26862306a36Sopenharmony_ci .verify_fn = t10_pi_type3_verify_crc, 26962306a36Sopenharmony_ci .prepare_fn = t10_pi_type3_prepare, 27062306a36Sopenharmony_ci .complete_fn = t10_pi_type3_complete, 27162306a36Sopenharmony_ci}; 27262306a36Sopenharmony_ciEXPORT_SYMBOL(t10_pi_type3_crc); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ciconst struct blk_integrity_profile t10_pi_type3_ip = { 27562306a36Sopenharmony_ci .name = "T10-DIF-TYPE3-IP", 27662306a36Sopenharmony_ci .generate_fn = t10_pi_type3_generate_ip, 27762306a36Sopenharmony_ci .verify_fn = t10_pi_type3_verify_ip, 27862306a36Sopenharmony_ci .prepare_fn = t10_pi_type3_prepare, 27962306a36Sopenharmony_ci .complete_fn = t10_pi_type3_complete, 28062306a36Sopenharmony_ci}; 28162306a36Sopenharmony_ciEXPORT_SYMBOL(t10_pi_type3_ip); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic __be64 ext_pi_crc64(void *data, unsigned int len) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci return cpu_to_be64(crc64_rocksoft(data, len)); 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic blk_status_t ext_pi_crc64_generate(struct blk_integrity_iter *iter, 28962306a36Sopenharmony_ci enum t10_dif_type type) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci unsigned int i; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci for (i = 0 ; i < iter->data_size ; i += iter->interval) { 29462306a36Sopenharmony_ci struct crc64_pi_tuple *pi = iter->prot_buf; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci pi->guard_tag = ext_pi_crc64(iter->data_buf, iter->interval); 29762306a36Sopenharmony_ci pi->app_tag = 0; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci if (type == T10_PI_TYPE1_PROTECTION) 30062306a36Sopenharmony_ci put_unaligned_be48(iter->seed, pi->ref_tag); 30162306a36Sopenharmony_ci else 30262306a36Sopenharmony_ci put_unaligned_be48(0ULL, pi->ref_tag); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci iter->data_buf += iter->interval; 30562306a36Sopenharmony_ci iter->prot_buf += iter->tuple_size; 30662306a36Sopenharmony_ci iter->seed++; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci return BLK_STS_OK; 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic bool ext_pi_ref_escape(u8 *ref_tag) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci static u8 ref_escape[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci return memcmp(ref_tag, ref_escape, sizeof(ref_escape)) == 0; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic blk_status_t ext_pi_crc64_verify(struct blk_integrity_iter *iter, 32062306a36Sopenharmony_ci enum t10_dif_type type) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci unsigned int i; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci for (i = 0; i < iter->data_size; i += iter->interval) { 32562306a36Sopenharmony_ci struct crc64_pi_tuple *pi = iter->prot_buf; 32662306a36Sopenharmony_ci u64 ref, seed; 32762306a36Sopenharmony_ci __be64 csum; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci if (type == T10_PI_TYPE1_PROTECTION) { 33062306a36Sopenharmony_ci if (pi->app_tag == T10_PI_APP_ESCAPE) 33162306a36Sopenharmony_ci goto next; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci ref = get_unaligned_be48(pi->ref_tag); 33462306a36Sopenharmony_ci seed = lower_48_bits(iter->seed); 33562306a36Sopenharmony_ci if (ref != seed) { 33662306a36Sopenharmony_ci pr_err("%s: ref tag error at location %llu (rcvd %llu)\n", 33762306a36Sopenharmony_ci iter->disk_name, seed, ref); 33862306a36Sopenharmony_ci return BLK_STS_PROTECTION; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci } else if (type == T10_PI_TYPE3_PROTECTION) { 34162306a36Sopenharmony_ci if (pi->app_tag == T10_PI_APP_ESCAPE && 34262306a36Sopenharmony_ci ext_pi_ref_escape(pi->ref_tag)) 34362306a36Sopenharmony_ci goto next; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci csum = ext_pi_crc64(iter->data_buf, iter->interval); 34762306a36Sopenharmony_ci if (pi->guard_tag != csum) { 34862306a36Sopenharmony_ci pr_err("%s: guard tag error at sector %llu " \ 34962306a36Sopenharmony_ci "(rcvd %016llx, want %016llx)\n", 35062306a36Sopenharmony_ci iter->disk_name, (unsigned long long)iter->seed, 35162306a36Sopenharmony_ci be64_to_cpu(pi->guard_tag), be64_to_cpu(csum)); 35262306a36Sopenharmony_ci return BLK_STS_PROTECTION; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cinext: 35662306a36Sopenharmony_ci iter->data_buf += iter->interval; 35762306a36Sopenharmony_ci iter->prot_buf += iter->tuple_size; 35862306a36Sopenharmony_ci iter->seed++; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci return BLK_STS_OK; 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic blk_status_t ext_pi_type1_verify_crc64(struct blk_integrity_iter *iter) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci return ext_pi_crc64_verify(iter, T10_PI_TYPE1_PROTECTION); 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic blk_status_t ext_pi_type1_generate_crc64(struct blk_integrity_iter *iter) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci return ext_pi_crc64_generate(iter, T10_PI_TYPE1_PROTECTION); 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic void ext_pi_type1_prepare(struct request *rq) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci const int tuple_sz = rq->q->integrity.tuple_size; 37762306a36Sopenharmony_ci u64 ref_tag = ext_pi_ref_tag(rq); 37862306a36Sopenharmony_ci struct bio *bio; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci __rq_for_each_bio(bio, rq) { 38162306a36Sopenharmony_ci struct bio_integrity_payload *bip = bio_integrity(bio); 38262306a36Sopenharmony_ci u64 virt = lower_48_bits(bip_get_seed(bip)); 38362306a36Sopenharmony_ci struct bio_vec iv; 38462306a36Sopenharmony_ci struct bvec_iter iter; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci /* Already remapped? */ 38762306a36Sopenharmony_ci if (bip->bip_flags & BIP_MAPPED_INTEGRITY) 38862306a36Sopenharmony_ci break; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci bip_for_each_vec(iv, bip, iter) { 39162306a36Sopenharmony_ci unsigned int j; 39262306a36Sopenharmony_ci void *p; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci p = bvec_kmap_local(&iv); 39562306a36Sopenharmony_ci for (j = 0; j < iv.bv_len; j += tuple_sz) { 39662306a36Sopenharmony_ci struct crc64_pi_tuple *pi = p; 39762306a36Sopenharmony_ci u64 ref = get_unaligned_be48(pi->ref_tag); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci if (ref == virt) 40062306a36Sopenharmony_ci put_unaligned_be48(ref_tag, pi->ref_tag); 40162306a36Sopenharmony_ci virt++; 40262306a36Sopenharmony_ci ref_tag++; 40362306a36Sopenharmony_ci p += tuple_sz; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci kunmap_local(p); 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci bip->bip_flags |= BIP_MAPPED_INTEGRITY; 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic void ext_pi_type1_complete(struct request *rq, unsigned int nr_bytes) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci unsigned intervals = nr_bytes >> rq->q->integrity.interval_exp; 41562306a36Sopenharmony_ci const int tuple_sz = rq->q->integrity.tuple_size; 41662306a36Sopenharmony_ci u64 ref_tag = ext_pi_ref_tag(rq); 41762306a36Sopenharmony_ci struct bio *bio; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci __rq_for_each_bio(bio, rq) { 42062306a36Sopenharmony_ci struct bio_integrity_payload *bip = bio_integrity(bio); 42162306a36Sopenharmony_ci u64 virt = lower_48_bits(bip_get_seed(bip)); 42262306a36Sopenharmony_ci struct bio_vec iv; 42362306a36Sopenharmony_ci struct bvec_iter iter; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci bip_for_each_vec(iv, bip, iter) { 42662306a36Sopenharmony_ci unsigned int j; 42762306a36Sopenharmony_ci void *p; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci p = bvec_kmap_local(&iv); 43062306a36Sopenharmony_ci for (j = 0; j < iv.bv_len && intervals; j += tuple_sz) { 43162306a36Sopenharmony_ci struct crc64_pi_tuple *pi = p; 43262306a36Sopenharmony_ci u64 ref = get_unaligned_be48(pi->ref_tag); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci if (ref == ref_tag) 43562306a36Sopenharmony_ci put_unaligned_be48(virt, pi->ref_tag); 43662306a36Sopenharmony_ci virt++; 43762306a36Sopenharmony_ci ref_tag++; 43862306a36Sopenharmony_ci intervals--; 43962306a36Sopenharmony_ci p += tuple_sz; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci kunmap_local(p); 44262306a36Sopenharmony_ci } 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic blk_status_t ext_pi_type3_verify_crc64(struct blk_integrity_iter *iter) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci return ext_pi_crc64_verify(iter, T10_PI_TYPE3_PROTECTION); 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic blk_status_t ext_pi_type3_generate_crc64(struct blk_integrity_iter *iter) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci return ext_pi_crc64_generate(iter, T10_PI_TYPE3_PROTECTION); 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ciconst struct blk_integrity_profile ext_pi_type1_crc64 = { 45762306a36Sopenharmony_ci .name = "EXT-DIF-TYPE1-CRC64", 45862306a36Sopenharmony_ci .generate_fn = ext_pi_type1_generate_crc64, 45962306a36Sopenharmony_ci .verify_fn = ext_pi_type1_verify_crc64, 46062306a36Sopenharmony_ci .prepare_fn = ext_pi_type1_prepare, 46162306a36Sopenharmony_ci .complete_fn = ext_pi_type1_complete, 46262306a36Sopenharmony_ci}; 46362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ext_pi_type1_crc64); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ciconst struct blk_integrity_profile ext_pi_type3_crc64 = { 46662306a36Sopenharmony_ci .name = "EXT-DIF-TYPE3-CRC64", 46762306a36Sopenharmony_ci .generate_fn = ext_pi_type3_generate_crc64, 46862306a36Sopenharmony_ci .verify_fn = ext_pi_type3_verify_crc64, 46962306a36Sopenharmony_ci .prepare_fn = t10_pi_type3_prepare, 47062306a36Sopenharmony_ci .complete_fn = t10_pi_type3_complete, 47162306a36Sopenharmony_ci}; 47262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ext_pi_type3_crc64); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 47562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 476