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 #ifdef HAVE_LINUX_BLK_INTEGRITY_HEADER
31 #include <linux/blk-integrity.h>
33 #include <linux/blkdev.h>
35 #include <linux/blk_types.h>
37 #include <obd_cksum.h>
38 #include <lustre_compat.h>
40 #include "osd_internal.h"
42 #if IS_ENABLED(CONFIG_CRC_T10DIF)
43 #ifdef HAVE_BLK_INTEGRITY_ITER
44 # define blk_status_gen blk_status_t
45 # define RETURN_GEN(_gen_fn) return _gen_fn
47 # define blk_status_gen void
48 # define RETURN_GEN(_gen_fn) _gen_fn
49 # define blk_integrity_iter blk_integrity_exchg
50 # define interval sector_size
52 # define blk_status_t int
53 # define BLK_STS_PROTECTION -EIO
57 * Data Integrity Field tuple.
60 __be16 guard_tag; /* Checksum */
61 __be16 app_tag; /* Opaque storage */
62 __be32 ref_tag; /* Target LBA or indirect LBA */
65 #define T10_PI_APP_ESCAPE cpu_to_be16(0xffff)
66 #define T10_PI_REF_ESCAPE cpu_to_be32(0xffffffff)
68 static struct niobuf_local *find_lnb(struct blk_integrity_iter *iter)
70 struct bio *bio = iter->bio;
71 struct bio_vec *bv = &bio->bi_io_vec[iter->bi_idx];
72 struct osd_bio_private *bio_private = bio->bi_private;
73 struct osd_iobuf *iobuf = bio_private->obp_iobuf;
74 int index = bio_private->obp_start_page_idx + iter->bi_idx;
78 * blocks are contiguous in bio but pages added to bio
79 * could have a gap comparing to iobuf->dr_pages.
80 * e.g. a page mapped to a hole in the middle.
82 for (i = index; i < iobuf->dr_npages; i++) {
83 if (iobuf->dr_pages[i] == bv->bv_page)
84 return iobuf->dr_lnbs[i];
91 * Type 1 and Type 2 protection use the same format: 16 bit guard tag,
92 * 16 bit app tag, 32 bit reference tag (sector number).
94 * Type 3 protection has a 16-bit guard tag and 16 + 32 bits of opaque
97 static blk_status_gen osd_dif_generate(struct blk_integrity_iter *iter,
98 obd_dif_csum_fn *fn, enum osd_t10_type type)
100 struct niobuf_local *lnb = find_lnb(iter);
101 __be16 *guard_buf = lnb ? lnb->lnb_guards : NULL;
105 for (i = 0 ; i < iter->data_size ; i += iter->interval) {
106 struct t10_pi_tuple *pi = iter->prot_buf;
108 if (lnb && lnb->lnb_guard_rpc) {
109 pi->guard_tag = *guard_buf;
112 pi->guard_tag = fn(iter->data_buf, iter->interval);
116 if (type == OSD_T10_TYPE1)
117 pi->ref_tag = cpu_to_be32(lower_32_bits(iter->seed));
118 else /* if (type == OSD_T10_TYPE3) */
121 iter->data_buf += iter->interval;
122 iter->prot_buf += sizeof(struct t10_pi_tuple);
126 #ifdef HAVE_BLK_INTEGRITY_ITER
133 static blk_status_t osd_dif_verify(struct blk_integrity_iter *iter,
134 obd_dif_csum_fn *fn, enum osd_t10_type type)
136 struct niobuf_local *lnb = find_lnb(iter);
137 __be16 *guard_buf = lnb ? lnb->lnb_guards : NULL;
141 for (i = 0 ; i < iter->data_size ; i += iter->interval) {
142 struct t10_pi_tuple *pi = iter->prot_buf;
145 if (type == OSD_T10_TYPE1 ||
146 type == OSD_T10_TYPE2) {
147 if (pi->app_tag == T10_PI_APP_ESCAPE) {
152 if (be32_to_cpu(pi->ref_tag) !=
153 lower_32_bits(iter->seed)) {
154 CERROR("%s: ref tag error at location %llu (rcvd %u): rc = %d\n",
156 (unsigned long long)iter->seed,
157 be32_to_cpu(pi->ref_tag),
159 RETURN(BLK_STS_PROTECTION);
161 } else if (type == OSD_T10_TYPE3) {
162 if (pi->app_tag == T10_PI_APP_ESCAPE &&
163 pi->ref_tag == T10_PI_REF_ESCAPE) {
169 csum = fn(iter->data_buf, iter->interval);
171 if (pi->guard_tag != csum) {
172 CERROR("%s: guard tag error on sector %llu (rcvd %04x, want %04x): rc = %d\n",
173 iter->disk_name, (unsigned long long)iter->seed,
174 be16_to_cpu(pi->guard_tag), be16_to_cpu(csum),
176 RETURN(BLK_STS_PROTECTION);
185 iter->data_buf += iter->interval;
186 iter->prot_buf += sizeof(struct t10_pi_tuple);
191 lnb->lnb_guard_disk = 1;
196 static blk_status_gen osd_dif_type1_generate_crc(struct blk_integrity_iter *iter)
198 RETURN_GEN(osd_dif_generate(iter, obd_dif_crc_fn, OSD_T10_TYPE1));
201 static blk_status_gen osd_dif_type1_generate_ip(struct blk_integrity_iter *iter)
203 RETURN_GEN(osd_dif_generate(iter, obd_dif_ip_fn, OSD_T10_TYPE1));
206 static blk_status_gen osd_dif_type3_generate_crc(struct blk_integrity_iter *iter)
208 RETURN_GEN(osd_dif_generate(iter, obd_dif_crc_fn, OSD_T10_TYPE3));
211 static blk_status_gen osd_dif_type3_generate_ip(struct blk_integrity_iter *iter)
213 RETURN_GEN(osd_dif_generate(iter, obd_dif_ip_fn, OSD_T10_TYPE3));
215 static blk_status_t osd_dif_type1_verify_crc(struct blk_integrity_iter *iter)
217 return osd_dif_verify(iter, obd_dif_crc_fn, OSD_T10_TYPE1);
220 static blk_status_t osd_dif_type1_verify_ip(struct blk_integrity_iter *iter)
222 return osd_dif_verify(iter, obd_dif_ip_fn, OSD_T10_TYPE1);
225 static blk_status_t osd_dif_type3_verify_crc(struct blk_integrity_iter *iter)
227 return osd_dif_verify(iter, obd_dif_crc_fn, OSD_T10_TYPE3);
230 static blk_status_t osd_dif_type3_verify_ip(struct blk_integrity_iter *iter)
232 return osd_dif_verify(iter, obd_dif_ip_fn, OSD_T10_TYPE3);
235 int osd_get_integrity_profile(struct osd_device *osd,
236 integrity_gen_fn **generate_fn,
237 integrity_vrfy_fn **verify_fn)
239 switch (osd->od_t10_type) {
240 case OSD_T10_TYPE1_CRC:
241 *verify_fn = osd_dif_type1_verify_crc;
242 *generate_fn = osd_dif_type1_generate_crc;
244 case OSD_T10_TYPE3_CRC:
245 *verify_fn = osd_dif_type3_verify_crc;
246 *generate_fn = osd_dif_type3_generate_crc;
248 case OSD_T10_TYPE1_IP:
249 *verify_fn = osd_dif_type1_verify_ip;
250 *generate_fn = osd_dif_type1_generate_ip;
252 case OSD_T10_TYPE3_IP:
253 *verify_fn = osd_dif_type3_verify_ip;
254 *generate_fn = osd_dif_type3_generate_ip;
262 #endif /* CONFIG_CRC_T10DIF */