xref: /linux/block/t10-pi.c (revision a52079dad4718fa924ae81a939f8a665366f562b)
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