linux/block/t10-pi.c
<<
>>
Prefs
   1/*
   2 * t10_pi.c - Functions for generating and verifying T10 Protection
   3 *            Information.
   4 *
   5 * Copyright (C) 2007, 2008, 2014 Oracle Corporation
   6 * Written by: Martin K. Petersen <martin.petersen@oracle.com>
   7 *
   8 * This program is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU General Public License version
  10 * 2 as published by the Free Software Foundation.
  11 *
  12 * This program is distributed in the hope that it will be useful, but
  13 * WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15 * General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; see the file COPYING.  If not, write to
  19 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
  20 * USA.
  21 *
  22 */
  23
  24#include <linux/t10-pi.h>
  25#include <linux/blkdev.h>
  26#include <linux/crc-t10dif.h>
  27#include <net/checksum.h>
  28
  29typedef __be16 (csum_fn) (void *, unsigned int);
  30
  31static const __be16 APP_ESCAPE = (__force __be16) 0xffff;
  32static const __be32 REF_ESCAPE = (__force __be32) 0xffffffff;
  33
  34static __be16 t10_pi_crc_fn(void *data, unsigned int len)
  35{
  36        return cpu_to_be16(crc_t10dif(data, len));
  37}
  38
  39static __be16 t10_pi_ip_fn(void *data, unsigned int len)
  40{
  41        return (__force __be16)ip_compute_csum(data, len);
  42}
  43
  44/*
  45 * Type 1 and Type 2 protection use the same format: 16 bit guard tag,
  46 * 16 bit app tag, 32 bit reference tag. Type 3 does not define the ref
  47 * tag.
  48 */
  49static int t10_pi_generate(struct blk_integrity_iter *iter, csum_fn *fn,
  50                           unsigned int type)
  51{
  52        unsigned int i;
  53
  54        for (i = 0 ; i < iter->data_size ; i += iter->interval) {
  55                struct t10_pi_tuple *pi = iter->prot_buf;
  56
  57                pi->guard_tag = fn(iter->data_buf, iter->interval);
  58                pi->app_tag = 0;
  59
  60                if (type == 1)
  61                        pi->ref_tag = cpu_to_be32(lower_32_bits(iter->seed));
  62                else
  63                        pi->ref_tag = 0;
  64
  65                iter->data_buf += iter->interval;
  66                iter->prot_buf += sizeof(struct t10_pi_tuple);
  67                iter->seed++;
  68        }
  69
  70        return 0;
  71}
  72
  73static int t10_pi_verify(struct blk_integrity_iter *iter, csum_fn *fn,
  74                                unsigned int type)
  75{
  76        unsigned int i;
  77
  78        for (i = 0 ; i < iter->data_size ; i += iter->interval) {
  79                struct t10_pi_tuple *pi = iter->prot_buf;
  80                __be16 csum;
  81
  82                switch (type) {
  83                case 1:
  84                case 2:
  85                        if (pi->app_tag == APP_ESCAPE)
  86                                goto next;
  87
  88                        if (be32_to_cpu(pi->ref_tag) !=
  89                            lower_32_bits(iter->seed)) {
  90                                pr_err("%s: ref tag error at location %llu " \
  91                                       "(rcvd %u)\n", iter->disk_name,
  92                                       (unsigned long long)
  93                                       iter->seed, be32_to_cpu(pi->ref_tag));
  94                                return -EILSEQ;
  95                        }
  96                        break;
  97                case 3:
  98                        if (pi->app_tag == APP_ESCAPE &&
  99                            pi->ref_tag == REF_ESCAPE)
 100                                goto next;
 101                        break;
 102                }
 103
 104                csum = fn(iter->data_buf, iter->interval);
 105
 106                if (pi->guard_tag != csum) {
 107                        pr_err("%s: guard tag error at sector %llu " \
 108                               "(rcvd %04x, want %04x)\n", iter->disk_name,
 109                               (unsigned long long)iter->seed,
 110                               be16_to_cpu(pi->guard_tag), be16_to_cpu(csum));
 111                        return -EILSEQ;
 112                }
 113
 114next:
 115                iter->data_buf += iter->interval;
 116                iter->prot_buf += sizeof(struct t10_pi_tuple);
 117                iter->seed++;
 118        }
 119
 120        return 0;
 121}
 122
 123static int t10_pi_type1_generate_crc(struct blk_integrity_iter *iter)
 124{
 125        return t10_pi_generate(iter, t10_pi_crc_fn, 1);
 126}
 127
 128static int t10_pi_type1_generate_ip(struct blk_integrity_iter *iter)
 129{
 130        return t10_pi_generate(iter, t10_pi_ip_fn, 1);
 131}
 132
 133static int t10_pi_type1_verify_crc(struct blk_integrity_iter *iter)
 134{
 135        return t10_pi_verify(iter, t10_pi_crc_fn, 1);
 136}
 137
 138static int t10_pi_type1_verify_ip(struct blk_integrity_iter *iter)
 139{
 140        return t10_pi_verify(iter, t10_pi_ip_fn, 1);
 141}
 142
 143static int t10_pi_type3_generate_crc(struct blk_integrity_iter *iter)
 144{
 145        return t10_pi_generate(iter, t10_pi_crc_fn, 3);
 146}
 147
 148static int t10_pi_type3_generate_ip(struct blk_integrity_iter *iter)
 149{
 150        return t10_pi_generate(iter, t10_pi_ip_fn, 3);
 151}
 152
 153static int t10_pi_type3_verify_crc(struct blk_integrity_iter *iter)
 154{
 155        return t10_pi_verify(iter, t10_pi_crc_fn, 3);
 156}
 157
 158static int t10_pi_type3_verify_ip(struct blk_integrity_iter *iter)
 159{
 160        return t10_pi_verify(iter, t10_pi_ip_fn, 3);
 161}
 162
 163struct blk_integrity_profile t10_pi_type1_crc = {
 164        .name                   = "T10-DIF-TYPE1-CRC",
 165        .generate_fn            = t10_pi_type1_generate_crc,
 166        .verify_fn              = t10_pi_type1_verify_crc,
 167};
 168EXPORT_SYMBOL(t10_pi_type1_crc);
 169
 170struct blk_integrity_profile t10_pi_type1_ip = {
 171        .name                   = "T10-DIF-TYPE1-IP",
 172        .generate_fn            = t10_pi_type1_generate_ip,
 173        .verify_fn              = t10_pi_type1_verify_ip,
 174};
 175EXPORT_SYMBOL(t10_pi_type1_ip);
 176
 177struct blk_integrity_profile t10_pi_type3_crc = {
 178        .name                   = "T10-DIF-TYPE3-CRC",
 179        .generate_fn            = t10_pi_type3_generate_crc,
 180        .verify_fn              = t10_pi_type3_verify_crc,
 181};
 182EXPORT_SYMBOL(t10_pi_type3_crc);
 183
 184struct blk_integrity_profile t10_pi_type3_ip = {
 185        .name                   = "T10-DIF-TYPE3-IP",
 186        .generate_fn            = t10_pi_type3_generate_ip,
 187        .verify_fn              = t10_pi_type3_verify_ip,
 188};
 189EXPORT_SYMBOL(t10_pi_type3_ip);
 190