]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - block/t10-pi.c
block: Add T10 Protection Information functions
[mirror_ubuntu-bionic-kernel.git] / block / t10-pi.c
diff --git a/block/t10-pi.c b/block/t10-pi.c
new file mode 100644 (file)
index 0000000..24d6e97
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * t10_pi.c - Functions for generating and verifying T10 Protection
+ *           Information.
+ *
+ * Copyright (C) 2007, 2008, 2014 Oracle Corporation
+ * Written by: Martin K. Petersen <martin.petersen@oracle.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
+ * USA.
+ *
+ */
+
+#include <linux/t10-pi.h>
+#include <linux/blkdev.h>
+#include <linux/crc-t10dif.h>
+#include <net/checksum.h>
+
+typedef __be16 (csum_fn) (void *, unsigned int);
+
+static const __be16 APP_ESCAPE = (__force __be16) 0xffff;
+static const __be32 REF_ESCAPE = (__force __be32) 0xffffffff;
+
+static __be16 t10_pi_crc_fn(void *data, unsigned int len)
+{
+       return cpu_to_be16(crc_t10dif(data, len));
+}
+
+static __be16 t10_pi_ip_fn(void *data, unsigned int len)
+{
+       return (__force __be16)ip_compute_csum(data, len);
+}
+
+/*
+ * Type 1 and Type 2 protection use the same format: 16 bit guard tag,
+ * 16 bit app tag, 32 bit reference tag. Type 3 does not define the ref
+ * tag.
+ */
+static int t10_pi_generate(struct blk_integrity_iter *iter, csum_fn *fn,
+                          unsigned int type)
+{
+       unsigned int i;
+
+       for (i = 0 ; i < iter->data_size ; i += iter->interval) {
+               struct t10_pi_tuple *pi = iter->prot_buf;
+
+               pi->guard_tag = fn(iter->data_buf, iter->interval);
+               pi->app_tag = 0;
+
+               if (type == 1)
+                       pi->ref_tag = cpu_to_be32(lower_32_bits(iter->seed));
+               else
+                       pi->ref_tag = 0;
+
+               iter->data_buf += iter->interval;
+               iter->prot_buf += sizeof(struct t10_pi_tuple);
+               iter->seed++;
+       }
+
+       return 0;
+}
+
+static int t10_pi_verify(struct blk_integrity_iter *iter, csum_fn *fn,
+                               unsigned int type)
+{
+       unsigned int i;
+
+       for (i = 0 ; i < iter->data_size ; i += iter->interval) {
+               struct t10_pi_tuple *pi = iter->prot_buf;
+               __be16 csum;
+
+               switch (type) {
+               case 1:
+               case 2:
+                       if (pi->app_tag == APP_ESCAPE)
+                               goto next;
+
+                       if (be32_to_cpu(pi->ref_tag) !=
+                           lower_32_bits(iter->seed)) {
+                               pr_err("%s: ref tag error at location %llu " \
+                                      "(rcvd %u)\n", iter->disk_name,
+                                      (unsigned long long)
+                                      iter->seed, be32_to_cpu(pi->ref_tag));
+                               return -EILSEQ;
+                       }
+                       break;
+               case 3:
+                       if (pi->app_tag == APP_ESCAPE &&
+                           pi->ref_tag == REF_ESCAPE)
+                               goto next;
+                       break;
+               }
+
+               csum = fn(iter->data_buf, iter->interval);
+
+               if (pi->guard_tag != csum) {
+                       pr_err("%s: guard tag error at sector %llu " \
+                              "(rcvd %04x, want %04x)\n", iter->disk_name,
+                              (unsigned long long)iter->seed,
+                              be16_to_cpu(pi->guard_tag), be16_to_cpu(csum));
+                       return -EILSEQ;
+               }
+
+next:
+               iter->data_buf += iter->interval;
+               iter->prot_buf += sizeof(struct t10_pi_tuple);
+               iter->seed++;
+       }
+
+       return 0;
+}
+
+static int t10_pi_type1_generate_crc(struct blk_integrity_iter *iter)
+{
+       return t10_pi_generate(iter, t10_pi_crc_fn, 1);
+}
+
+static int t10_pi_type1_generate_ip(struct blk_integrity_iter *iter)
+{
+       return t10_pi_generate(iter, t10_pi_ip_fn, 1);
+}
+
+static int t10_pi_type1_verify_crc(struct blk_integrity_iter *iter)
+{
+       return t10_pi_verify(iter, t10_pi_crc_fn, 1);
+}
+
+static int t10_pi_type1_verify_ip(struct blk_integrity_iter *iter)
+{
+       return t10_pi_verify(iter, t10_pi_ip_fn, 1);
+}
+
+static int t10_pi_type3_generate_crc(struct blk_integrity_iter *iter)
+{
+       return t10_pi_generate(iter, t10_pi_crc_fn, 3);
+}
+
+static int t10_pi_type3_generate_ip(struct blk_integrity_iter *iter)
+{
+       return t10_pi_generate(iter, t10_pi_ip_fn, 3);
+}
+
+static int t10_pi_type3_verify_crc(struct blk_integrity_iter *iter)
+{
+       return t10_pi_verify(iter, t10_pi_crc_fn, 3);
+}
+
+static int t10_pi_type3_verify_ip(struct blk_integrity_iter *iter)
+{
+       return t10_pi_verify(iter, t10_pi_ip_fn, 3);
+}
+
+struct blk_integrity t10_pi_type1_crc = {
+       .name                   = "T10-DIF-TYPE1-CRC",
+       .generate_fn            = t10_pi_type1_generate_crc,
+       .verify_fn              = t10_pi_type1_verify_crc,
+       .tuple_size             = sizeof(struct t10_pi_tuple),
+       .tag_size               = 0,
+};
+EXPORT_SYMBOL(t10_pi_type1_crc);
+
+struct blk_integrity t10_pi_type1_ip = {
+       .name                   = "T10-DIF-TYPE1-IP",
+       .generate_fn            = t10_pi_type1_generate_ip,
+       .verify_fn              = t10_pi_type1_verify_ip,
+       .tuple_size             = sizeof(struct t10_pi_tuple),
+       .tag_size               = 0,
+};
+EXPORT_SYMBOL(t10_pi_type1_ip);
+
+struct blk_integrity t10_pi_type3_crc = {
+       .name                   = "T10-DIF-TYPE3-CRC",
+       .generate_fn            = t10_pi_type3_generate_crc,
+       .verify_fn              = t10_pi_type3_verify_crc,
+       .tuple_size             = sizeof(struct t10_pi_tuple),
+       .tag_size               = 0,
+};
+EXPORT_SYMBOL(t10_pi_type3_crc);
+
+struct blk_integrity t10_pi_type3_ip = {
+       .name                   = "T10-DIF-TYPE3-IP",
+       .generate_fn            = t10_pi_type3_generate_ip,
+       .verify_fn              = t10_pi_type3_verify_ip,
+       .tuple_size             = sizeof(struct t10_pi_tuple),
+       .tag_size               = 0,
+};
+EXPORT_SYMBOL(t10_pi_type3_ip);