12341c2f8SMartin K. Petersen /* 22341c2f8SMartin K. Petersen * t10_pi.c - Functions for generating and verifying T10 Protection 32341c2f8SMartin K. Petersen * Information. 42341c2f8SMartin K. Petersen * 52341c2f8SMartin K. Petersen * Copyright (C) 2007, 2008, 2014 Oracle Corporation 62341c2f8SMartin K. Petersen * Written by: Martin K. Petersen <martin.petersen@oracle.com> 72341c2f8SMartin K. Petersen * 82341c2f8SMartin K. Petersen * This program is free software; you can redistribute it and/or 92341c2f8SMartin K. Petersen * modify it under the terms of the GNU General Public License version 102341c2f8SMartin K. Petersen * 2 as published by the Free Software Foundation. 112341c2f8SMartin K. Petersen * 122341c2f8SMartin K. Petersen * This program is distributed in the hope that it will be useful, but 132341c2f8SMartin K. Petersen * WITHOUT ANY WARRANTY; without even the implied warranty of 142341c2f8SMartin K. Petersen * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 152341c2f8SMartin K. Petersen * General Public License for more details. 162341c2f8SMartin K. Petersen * 172341c2f8SMartin K. Petersen * You should have received a copy of the GNU General Public License 182341c2f8SMartin K. Petersen * along with this program; see the file COPYING. If not, write to 192341c2f8SMartin K. Petersen * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, 202341c2f8SMartin K. Petersen * USA. 212341c2f8SMartin K. Petersen * 222341c2f8SMartin K. Petersen */ 232341c2f8SMartin K. Petersen 242341c2f8SMartin K. Petersen #include <linux/t10-pi.h> 252341c2f8SMartin K. Petersen #include <linux/blkdev.h> 262341c2f8SMartin K. Petersen #include <linux/crc-t10dif.h> 272341c2f8SMartin K. Petersen #include <net/checksum.h> 282341c2f8SMartin K. Petersen 292341c2f8SMartin K. Petersen typedef __be16 (csum_fn) (void *, unsigned int); 302341c2f8SMartin K. Petersen 312341c2f8SMartin K. Petersen static const __be16 APP_ESCAPE = (__force __be16) 0xffff; 322341c2f8SMartin K. Petersen static const __be32 REF_ESCAPE = (__force __be32) 0xffffffff; 332341c2f8SMartin K. Petersen 342341c2f8SMartin K. Petersen static __be16 t10_pi_crc_fn(void *data, unsigned int len) 352341c2f8SMartin K. Petersen { 362341c2f8SMartin K. Petersen return cpu_to_be16(crc_t10dif(data, len)); 372341c2f8SMartin K. Petersen } 382341c2f8SMartin K. Petersen 392341c2f8SMartin K. Petersen static __be16 t10_pi_ip_fn(void *data, unsigned int len) 402341c2f8SMartin K. Petersen { 412341c2f8SMartin K. Petersen return (__force __be16)ip_compute_csum(data, len); 422341c2f8SMartin K. Petersen } 432341c2f8SMartin K. Petersen 442341c2f8SMartin K. Petersen /* 452341c2f8SMartin K. Petersen * Type 1 and Type 2 protection use the same format: 16 bit guard tag, 462341c2f8SMartin K. Petersen * 16 bit app tag, 32 bit reference tag. Type 3 does not define the ref 472341c2f8SMartin K. Petersen * tag. 482341c2f8SMartin K. Petersen */ 492341c2f8SMartin K. Petersen static int t10_pi_generate(struct blk_integrity_iter *iter, csum_fn *fn, 502341c2f8SMartin K. Petersen unsigned int type) 512341c2f8SMartin K. Petersen { 522341c2f8SMartin K. Petersen unsigned int i; 532341c2f8SMartin K. Petersen 542341c2f8SMartin K. Petersen for (i = 0 ; i < iter->data_size ; i += iter->interval) { 552341c2f8SMartin K. Petersen struct t10_pi_tuple *pi = iter->prot_buf; 562341c2f8SMartin K. Petersen 572341c2f8SMartin K. Petersen pi->guard_tag = fn(iter->data_buf, iter->interval); 582341c2f8SMartin K. Petersen pi->app_tag = 0; 592341c2f8SMartin K. Petersen 602341c2f8SMartin K. Petersen if (type == 1) 612341c2f8SMartin K. Petersen pi->ref_tag = cpu_to_be32(lower_32_bits(iter->seed)); 622341c2f8SMartin K. Petersen else 632341c2f8SMartin K. Petersen pi->ref_tag = 0; 642341c2f8SMartin K. Petersen 652341c2f8SMartin K. Petersen iter->data_buf += iter->interval; 662341c2f8SMartin K. Petersen iter->prot_buf += sizeof(struct t10_pi_tuple); 672341c2f8SMartin K. Petersen iter->seed++; 682341c2f8SMartin K. Petersen } 692341c2f8SMartin K. Petersen 702341c2f8SMartin K. Petersen return 0; 712341c2f8SMartin K. Petersen } 722341c2f8SMartin K. Petersen 732341c2f8SMartin K. Petersen static int t10_pi_verify(struct blk_integrity_iter *iter, csum_fn *fn, 742341c2f8SMartin K. Petersen unsigned int type) 752341c2f8SMartin K. Petersen { 762341c2f8SMartin K. Petersen unsigned int i; 772341c2f8SMartin K. Petersen 782341c2f8SMartin K. Petersen for (i = 0 ; i < iter->data_size ; i += iter->interval) { 792341c2f8SMartin K. Petersen struct t10_pi_tuple *pi = iter->prot_buf; 802341c2f8SMartin K. Petersen __be16 csum; 812341c2f8SMartin K. Petersen 822341c2f8SMartin K. Petersen switch (type) { 832341c2f8SMartin K. Petersen case 1: 842341c2f8SMartin K. Petersen case 2: 852341c2f8SMartin K. Petersen if (pi->app_tag == APP_ESCAPE) 862341c2f8SMartin K. Petersen goto next; 872341c2f8SMartin K. Petersen 882341c2f8SMartin K. Petersen if (be32_to_cpu(pi->ref_tag) != 892341c2f8SMartin K. Petersen lower_32_bits(iter->seed)) { 902341c2f8SMartin K. Petersen pr_err("%s: ref tag error at location %llu " \ 912341c2f8SMartin K. Petersen "(rcvd %u)\n", iter->disk_name, 922341c2f8SMartin K. Petersen (unsigned long long) 932341c2f8SMartin K. Petersen iter->seed, be32_to_cpu(pi->ref_tag)); 942341c2f8SMartin K. Petersen return -EILSEQ; 952341c2f8SMartin K. Petersen } 962341c2f8SMartin K. Petersen break; 972341c2f8SMartin K. Petersen case 3: 982341c2f8SMartin K. Petersen if (pi->app_tag == APP_ESCAPE && 992341c2f8SMartin K. Petersen pi->ref_tag == REF_ESCAPE) 1002341c2f8SMartin K. Petersen goto next; 1012341c2f8SMartin K. Petersen break; 1022341c2f8SMartin K. Petersen } 1032341c2f8SMartin K. Petersen 1042341c2f8SMartin K. Petersen csum = fn(iter->data_buf, iter->interval); 1052341c2f8SMartin K. Petersen 1062341c2f8SMartin K. Petersen if (pi->guard_tag != csum) { 1072341c2f8SMartin K. Petersen pr_err("%s: guard tag error at sector %llu " \ 1082341c2f8SMartin K. Petersen "(rcvd %04x, want %04x)\n", iter->disk_name, 1092341c2f8SMartin K. Petersen (unsigned long long)iter->seed, 1102341c2f8SMartin K. Petersen be16_to_cpu(pi->guard_tag), be16_to_cpu(csum)); 1112341c2f8SMartin K. Petersen return -EILSEQ; 1122341c2f8SMartin K. Petersen } 1132341c2f8SMartin K. Petersen 1142341c2f8SMartin K. Petersen next: 1152341c2f8SMartin K. Petersen iter->data_buf += iter->interval; 1162341c2f8SMartin K. Petersen iter->prot_buf += sizeof(struct t10_pi_tuple); 1172341c2f8SMartin K. Petersen iter->seed++; 1182341c2f8SMartin K. Petersen } 1192341c2f8SMartin K. Petersen 1202341c2f8SMartin K. Petersen return 0; 1212341c2f8SMartin K. Petersen } 1222341c2f8SMartin K. Petersen 1232341c2f8SMartin K. Petersen static int t10_pi_type1_generate_crc(struct blk_integrity_iter *iter) 1242341c2f8SMartin K. Petersen { 1252341c2f8SMartin K. Petersen return t10_pi_generate(iter, t10_pi_crc_fn, 1); 1262341c2f8SMartin K. Petersen } 1272341c2f8SMartin K. Petersen 1282341c2f8SMartin K. Petersen static int t10_pi_type1_generate_ip(struct blk_integrity_iter *iter) 1292341c2f8SMartin K. Petersen { 1302341c2f8SMartin K. Petersen return t10_pi_generate(iter, t10_pi_ip_fn, 1); 1312341c2f8SMartin K. Petersen } 1322341c2f8SMartin K. Petersen 1332341c2f8SMartin K. Petersen static int t10_pi_type1_verify_crc(struct blk_integrity_iter *iter) 1342341c2f8SMartin K. Petersen { 1352341c2f8SMartin K. Petersen return t10_pi_verify(iter, t10_pi_crc_fn, 1); 1362341c2f8SMartin K. Petersen } 1372341c2f8SMartin K. Petersen 1382341c2f8SMartin K. Petersen static int t10_pi_type1_verify_ip(struct blk_integrity_iter *iter) 1392341c2f8SMartin K. Petersen { 1402341c2f8SMartin K. Petersen return t10_pi_verify(iter, t10_pi_ip_fn, 1); 1412341c2f8SMartin K. Petersen } 1422341c2f8SMartin K. Petersen 1432341c2f8SMartin K. Petersen static int t10_pi_type3_generate_crc(struct blk_integrity_iter *iter) 1442341c2f8SMartin K. Petersen { 1452341c2f8SMartin K. Petersen return t10_pi_generate(iter, t10_pi_crc_fn, 3); 1462341c2f8SMartin K. Petersen } 1472341c2f8SMartin K. Petersen 1482341c2f8SMartin K. Petersen static int t10_pi_type3_generate_ip(struct blk_integrity_iter *iter) 1492341c2f8SMartin K. Petersen { 1502341c2f8SMartin K. Petersen return t10_pi_generate(iter, t10_pi_ip_fn, 3); 1512341c2f8SMartin K. Petersen } 1522341c2f8SMartin K. Petersen 1532341c2f8SMartin K. Petersen static int t10_pi_type3_verify_crc(struct blk_integrity_iter *iter) 1542341c2f8SMartin K. Petersen { 1552341c2f8SMartin K. Petersen return t10_pi_verify(iter, t10_pi_crc_fn, 3); 1562341c2f8SMartin K. Petersen } 1572341c2f8SMartin K. Petersen 1582341c2f8SMartin K. Petersen static int t10_pi_type3_verify_ip(struct blk_integrity_iter *iter) 1592341c2f8SMartin K. Petersen { 1602341c2f8SMartin K. Petersen return t10_pi_verify(iter, t10_pi_ip_fn, 3); 1612341c2f8SMartin K. Petersen } 1622341c2f8SMartin K. Petersen 1630f8087ecSMartin K. Petersen struct blk_integrity_profile t10_pi_type1_crc = { 1642341c2f8SMartin K. Petersen .name = "T10-DIF-TYPE1-CRC", 1652341c2f8SMartin K. Petersen .generate_fn = t10_pi_type1_generate_crc, 1662341c2f8SMartin K. Petersen .verify_fn = t10_pi_type1_verify_crc, 1672341c2f8SMartin K. Petersen }; 1682341c2f8SMartin K. Petersen EXPORT_SYMBOL(t10_pi_type1_crc); 1692341c2f8SMartin K. Petersen 1700f8087ecSMartin K. Petersen struct blk_integrity_profile t10_pi_type1_ip = { 1712341c2f8SMartin K. Petersen .name = "T10-DIF-TYPE1-IP", 1722341c2f8SMartin K. Petersen .generate_fn = t10_pi_type1_generate_ip, 1732341c2f8SMartin K. Petersen .verify_fn = t10_pi_type1_verify_ip, 1742341c2f8SMartin K. Petersen }; 1752341c2f8SMartin K. Petersen EXPORT_SYMBOL(t10_pi_type1_ip); 1762341c2f8SMartin K. Petersen 1770f8087ecSMartin K. Petersen struct blk_integrity_profile t10_pi_type3_crc = { 1782341c2f8SMartin K. Petersen .name = "T10-DIF-TYPE3-CRC", 1792341c2f8SMartin K. Petersen .generate_fn = t10_pi_type3_generate_crc, 1802341c2f8SMartin K. Petersen .verify_fn = t10_pi_type3_verify_crc, 1812341c2f8SMartin K. Petersen }; 1822341c2f8SMartin K. Petersen EXPORT_SYMBOL(t10_pi_type3_crc); 1832341c2f8SMartin K. Petersen 1840f8087ecSMartin K. Petersen struct blk_integrity_profile t10_pi_type3_ip = { 1852341c2f8SMartin K. Petersen .name = "T10-DIF-TYPE3-IP", 1862341c2f8SMartin K. Petersen .generate_fn = t10_pi_type3_generate_ip, 1872341c2f8SMartin K. Petersen .verify_fn = t10_pi_type3_verify_ip, 1882341c2f8SMartin K. Petersen }; 1892341c2f8SMartin K. Petersen EXPORT_SYMBOL(t10_pi_type3_ip); 190