4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (c) 2018, DataDirect Networks Storage.
26 * Data integrity functions for OSD
27 * Codes copied from kernel 3.10.0-862.el7
28 * drivers/scsi/sd_dif.c and block/t10-pi.c
30 #include <linux/blkdev.h>
31 #include <linux/blk_types.h>
33 #include <obd_cksum.h>
34 #include <lustre_compat.h>
36 #include "osd_internal.h"
38 #if IS_ENABLED(CONFIG_CRC_T10DIF)
40 * Data Integrity Field tuple.
43 __be16 guard_tag; /* Checksum */
44 __be16 app_tag; /* Opaque storage */
45 __be32 ref_tag; /* Target LBA or indirect LBA */
48 static struct niobuf_local *find_lnb(struct blk_integrity_exchg *bix)
50 struct bio *bio = bix->bio;
51 struct bio_vec *bv = bio_iovec_idx(bio, bix->bi_idx);
52 struct osd_bio_private *bio_private = bio->bi_private;
53 struct osd_iobuf *iobuf = bio_private->obp_iobuf;
54 int index = bio_private->obp_start_page_idx + bix->bi_idx;
58 * blocks are contiguous in bio but pages added to bio
59 * could have a gap comparing to iobuf->dr_pages.
60 * e.g. a page mapped to a hole in the middle.
62 for (i = index; i < iobuf->dr_npages; i++) {
63 if (iobuf->dr_pages[i] == bv->bv_page)
64 return iobuf->dr_lnbs[i];
71 * Type 1 and Type 2 protection use the same format: 16 bit guard tag,
72 * 16 bit app tag, 32 bit reference tag (sector number).
74 * Type 3 protection has a 16-bit guard tag and 16 + 32 bits of opaque
77 static void osd_dif_generate(struct blk_integrity_exchg *bix,
78 obd_dif_csum_fn *fn, enum osd_t10_type type)
80 void *buf = bix->data_buf;
81 struct sd_dif_tuple *sdt = bix->prot_buf;
82 struct niobuf_local *lnb = find_lnb(bix);
83 __u16 *guard_buf = lnb ? lnb->lnb_guards : NULL;
84 sector_t sector = bix->sector;
88 for (i = 0 ; i < bix->data_size ; i += bix->sector_size, sdt++) {
89 if (lnb && lnb->lnb_guard_rpc) {
90 sdt->guard_tag = *guard_buf;
93 sdt->guard_tag = fn(buf, bix->sector_size);
96 if (type == OSD_T10_TYPE1)
97 sdt->ref_tag = cpu_to_be32(sector & 0xffffffff);
98 else /* if (type == OSD_T10_TYPE3) */
101 buf += bix->sector_size;
107 static int osd_dif_verify(struct blk_integrity_exchg *bix,
108 obd_dif_csum_fn *fn, enum osd_t10_type type)
110 void *buf = bix->data_buf;
111 struct sd_dif_tuple *sdt = bix->prot_buf;
112 struct niobuf_local *lnb = find_lnb(bix);
113 __u16 *guard_buf = lnb ? lnb->lnb_guards : NULL;
114 sector_t sector = bix->sector;
119 for (i = 0 ; i < bix->data_size ; i += bix->sector_size, sdt++) {
120 if (type == OSD_T10_TYPE1) {
121 /* Unwritten sectors */
122 if (sdt->app_tag == 0xffff)
125 if (be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
126 CERROR("%s: ref tag error on sector %lu (rcvd %u): rc = %d\n",
127 bix->disk_name, (unsigned long)sector,
128 be32_to_cpu(sdt->ref_tag), -EIO);
131 } else /* if (type == OSD_T10_TYPE3) */ {
132 /* Unwritten sectors */
133 if (sdt->app_tag == 0xffff &&
134 sdt->ref_tag == 0xffffffff)
138 csum = fn(buf, bix->sector_size);
140 if (sdt->guard_tag != csum) {
141 CERROR("%s: guard tag error on sector %lu (rcvd %04x, data %04x): rc = %d\n",
142 bix->disk_name, (unsigned long)sector,
143 be16_to_cpu(sdt->guard_tag), be16_to_cpu(csum),
153 buf += bix->sector_size;
158 lnb->lnb_guard_disk = 1;
163 static void osd_dif_type1_generate_crc(struct blk_integrity_exchg *bix)
165 osd_dif_generate(bix, obd_dif_crc_fn, OSD_T10_TYPE1);
168 static void osd_dif_type1_generate_ip(struct blk_integrity_exchg *bix)
170 osd_dif_generate(bix, obd_dif_ip_fn, OSD_T10_TYPE1);
173 static void osd_dif_type3_generate_crc(struct blk_integrity_exchg *bix)
175 osd_dif_generate(bix, obd_dif_crc_fn, OSD_T10_TYPE3);
178 static void osd_dif_type3_generate_ip(struct blk_integrity_exchg *bix)
180 osd_dif_generate(bix, obd_dif_ip_fn, OSD_T10_TYPE3);
183 static int osd_dif_type1_verify_crc(struct blk_integrity_exchg *bix)
185 return osd_dif_verify(bix, obd_dif_crc_fn, OSD_T10_TYPE1);
188 static int osd_dif_type1_verify_ip(struct blk_integrity_exchg *bix)
190 return osd_dif_verify(bix, obd_dif_ip_fn, OSD_T10_TYPE1);
193 static int osd_dif_type3_verify_crc(struct blk_integrity_exchg *bix)
195 return osd_dif_verify(bix, obd_dif_crc_fn, OSD_T10_TYPE3);
198 static int osd_dif_type3_verify_ip(struct blk_integrity_exchg *bix)
200 return osd_dif_verify(bix, obd_dif_ip_fn, OSD_T10_TYPE3);
203 int osd_get_integrity_profile(struct osd_device *osd,
204 integrity_gen_fn **generate_fn,
205 integrity_vrfy_fn **verify_fn)
207 switch (osd->od_t10_type) {
208 case OSD_T10_TYPE1_CRC:
209 *verify_fn = osd_dif_type1_verify_crc;
210 *generate_fn = osd_dif_type1_generate_crc;
212 case OSD_T10_TYPE3_CRC:
213 *verify_fn = osd_dif_type3_verify_crc;
214 *generate_fn = osd_dif_type3_generate_crc;
216 case OSD_T10_TYPE1_IP:
217 *verify_fn = osd_dif_type1_verify_ip;
218 *generate_fn = osd_dif_type1_generate_ip;
220 case OSD_T10_TYPE3_IP:
221 *verify_fn = osd_dif_type3_verify_ip;
222 *generate_fn = osd_dif_type3_generate_ip;
230 #endif /* CONFIG_CRC_T10DIF */