aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/sd_dif.c
diff options
context:
space:
mode:
authorMartin K. Petersen <martin.petersen@oracle.com>2014-09-26 19:20:07 -0400
committerJens Axboe <axboe@fb.com>2014-09-27 11:14:59 -0400
commit2341c2f8c33196d02cf5a721746eea4e3c06674a (patch)
treecd51e37c084f016ea05a253b7b9041866d2e12fb /drivers/scsi/sd_dif.c
parent4eaf99beadcefbf126fa05e66fb40fca999e09fd (diff)
block: Add T10 Protection Information functions
The T10 Protection Information format is also used by some devices that do not go through the SCSI layer (virtual block devices, NVMe). Relocate the relevant functions to a block layer library that can be used without involving SCSI. Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'drivers/scsi/sd_dif.c')
-rw-r--r--drivers/scsi/sd_dif.c241
1 files changed, 20 insertions, 221 deletions
diff --git a/drivers/scsi/sd_dif.c b/drivers/scsi/sd_dif.c
index 2198abee619e..b7eaeadc18f9 100644
--- a/drivers/scsi/sd_dif.c
+++ b/drivers/scsi/sd_dif.c
@@ -21,7 +21,7 @@
21 */ 21 */
22 22
23#include <linux/blkdev.h> 23#include <linux/blkdev.h>
24#include <linux/crc-t10dif.h> 24#include <linux/t10-pi.h>
25 25
26#include <scsi/scsi.h> 26#include <scsi/scsi.h>
27#include <scsi/scsi_cmnd.h> 27#include <scsi/scsi_cmnd.h>
@@ -33,207 +33,8 @@
33#include <scsi/scsi_ioctl.h> 33#include <scsi/scsi_ioctl.h>
34#include <scsi/scsicam.h> 34#include <scsi/scsicam.h>
35 35
36#include <net/checksum.h>
37
38#include "sd.h" 36#include "sd.h"
39 37
40typedef __u16 (csum_fn) (void *, unsigned int);
41
42static __u16 sd_dif_crc_fn(void *data, unsigned int len)
43{
44 return cpu_to_be16(crc_t10dif(data, len));
45}
46
47static __u16 sd_dif_ip_fn(void *data, unsigned int len)
48{
49 return ip_compute_csum(data, len);
50}
51
52/*
53 * Type 1 and Type 2 protection use the same format: 16 bit guard tag,
54 * 16 bit app tag, 32 bit reference tag.
55 */
56static void sd_dif_type1_generate(struct blk_integrity_iter *iter, csum_fn *fn)
57{
58 void *buf = iter->data_buf;
59 struct sd_dif_tuple *sdt = iter->prot_buf;
60 sector_t seed = iter->seed;
61 unsigned int i;
62
63 for (i = 0 ; i < iter->data_size ; i += iter->interval, sdt++) {
64 sdt->guard_tag = fn(buf, iter->interval);
65 sdt->ref_tag = cpu_to_be32(seed & 0xffffffff);
66 sdt->app_tag = 0;
67
68 buf += iter->interval;
69 seed++;
70 }
71}
72
73static int sd_dif_type1_generate_crc(struct blk_integrity_iter *iter)
74{
75 sd_dif_type1_generate(iter, sd_dif_crc_fn);
76 return 0;
77}
78
79static int sd_dif_type1_generate_ip(struct blk_integrity_iter *iter)
80{
81 sd_dif_type1_generate(iter, sd_dif_ip_fn);
82 return 0;
83}
84
85static int sd_dif_type1_verify(struct blk_integrity_iter *iter, csum_fn *fn)
86{
87 void *buf = iter->data_buf;
88 struct sd_dif_tuple *sdt = iter->prot_buf;
89 sector_t seed = iter->seed;
90 unsigned int i;
91 __u16 csum;
92
93 for (i = 0 ; i < iter->data_size ; i += iter->interval, sdt++) {
94 /* Unwritten sectors */
95 if (sdt->app_tag == 0xffff)
96 return 0;
97
98 if (be32_to_cpu(sdt->ref_tag) != (seed & 0xffffffff)) {
99 printk(KERN_ERR
100 "%s: ref tag error on sector %lu (rcvd %u)\n",
101 iter->disk_name, (unsigned long)seed,
102 be32_to_cpu(sdt->ref_tag));
103 return -EIO;
104 }
105
106 csum = fn(buf, iter->interval);
107
108 if (sdt->guard_tag != csum) {
109 printk(KERN_ERR "%s: guard tag error on sector %lu " \
110 "(rcvd %04x, data %04x)\n", iter->disk_name,
111 (unsigned long)seed,
112 be16_to_cpu(sdt->guard_tag), be16_to_cpu(csum));
113 return -EIO;
114 }
115
116 buf += iter->interval;
117 seed++;
118 }
119
120 return 0;
121}
122
123static int sd_dif_type1_verify_crc(struct blk_integrity_iter *iter)
124{
125 return sd_dif_type1_verify(iter, sd_dif_crc_fn);
126}
127
128static int sd_dif_type1_verify_ip(struct blk_integrity_iter *iter)
129{
130 return sd_dif_type1_verify(iter, sd_dif_ip_fn);
131}
132
133static struct blk_integrity dif_type1_integrity_crc = {
134 .name = "T10-DIF-TYPE1-CRC",
135 .generate_fn = sd_dif_type1_generate_crc,
136 .verify_fn = sd_dif_type1_verify_crc,
137 .tuple_size = sizeof(struct sd_dif_tuple),
138 .tag_size = 0,
139};
140
141static struct blk_integrity dif_type1_integrity_ip = {
142 .name = "T10-DIF-TYPE1-IP",
143 .generate_fn = sd_dif_type1_generate_ip,
144 .verify_fn = sd_dif_type1_verify_ip,
145 .tuple_size = sizeof(struct sd_dif_tuple),
146 .tag_size = 0,
147};
148
149
150/*
151 * Type 3 protection has a 16-bit guard tag and 16 + 32 bits of opaque
152 * tag space.
153 */
154static void sd_dif_type3_generate(struct blk_integrity_iter *iter, csum_fn *fn)
155{
156 void *buf = iter->data_buf;
157 struct sd_dif_tuple *sdt = iter->prot_buf;
158 unsigned int i;
159
160 for (i = 0 ; i < iter->data_size ; i += iter->interval, sdt++) {
161 sdt->guard_tag = fn(buf, iter->interval);
162 sdt->ref_tag = 0;
163 sdt->app_tag = 0;
164
165 buf += iter->interval;
166 }
167}
168
169static int sd_dif_type3_generate_crc(struct blk_integrity_iter *iter)
170{
171 sd_dif_type3_generate(iter, sd_dif_crc_fn);
172 return 0;
173}
174
175static int sd_dif_type3_generate_ip(struct blk_integrity_iter *iter)
176{
177 sd_dif_type3_generate(iter, sd_dif_ip_fn);
178 return 0;
179}
180
181static int sd_dif_type3_verify(struct blk_integrity_iter *iter, csum_fn *fn)
182{
183 void *buf = iter->data_buf;
184 struct sd_dif_tuple *sdt = iter->prot_buf;
185 sector_t seed = iter->seed;
186 unsigned int i;
187 __u16 csum;
188
189 for (i = 0 ; i < iter->data_size ; i += iter->interval, sdt++) {
190 /* Unwritten sectors */
191 if (sdt->app_tag == 0xffff && sdt->ref_tag == 0xffffffff)
192 return 0;
193
194 csum = fn(buf, iter->interval);
195
196 if (sdt->guard_tag != csum) {
197 printk(KERN_ERR "%s: guard tag error on sector %lu " \
198 "(rcvd %04x, data %04x)\n", iter->disk_name,
199 (unsigned long)seed,
200 be16_to_cpu(sdt->guard_tag), be16_to_cpu(csum));
201 return -EIO;
202 }
203
204 buf += iter->interval;
205 seed++;
206 }
207
208 return 0;
209}
210
211static int sd_dif_type3_verify_crc(struct blk_integrity_iter *iter)
212{
213 return sd_dif_type3_verify(iter, sd_dif_crc_fn);
214}
215
216static int sd_dif_type3_verify_ip(struct blk_integrity_iter *iter)
217{
218 return sd_dif_type3_verify(iter, sd_dif_ip_fn);
219}
220
221static struct blk_integrity dif_type3_integrity_crc = {
222 .name = "T10-DIF-TYPE3-CRC",
223 .generate_fn = sd_dif_type3_generate_crc,
224 .verify_fn = sd_dif_type3_verify_crc,
225 .tuple_size = sizeof(struct sd_dif_tuple),
226 .tag_size = 0,
227};
228
229static struct blk_integrity dif_type3_integrity_ip = {
230 .name = "T10-DIF-TYPE3-IP",
231 .generate_fn = sd_dif_type3_generate_ip,
232 .verify_fn = sd_dif_type3_verify_ip,
233 .tuple_size = sizeof(struct sd_dif_tuple),
234 .tag_size = 0,
235};
236
237/* 38/*
238 * Configure exchange of protection information between OS and HBA. 39 * Configure exchange of protection information between OS and HBA.
239 */ 40 */
@@ -257,16 +58,16 @@ void sd_dif_config_host(struct scsi_disk *sdkp)
257 /* Enable DMA of protection information */ 58 /* Enable DMA of protection information */
258 if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP) { 59 if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP) {
259 if (type == SD_DIF_TYPE3_PROTECTION) 60 if (type == SD_DIF_TYPE3_PROTECTION)
260 blk_integrity_register(disk, &dif_type3_integrity_ip); 61 blk_integrity_register(disk, &t10_pi_type3_ip);
261 else 62 else
262 blk_integrity_register(disk, &dif_type1_integrity_ip); 63 blk_integrity_register(disk, &t10_pi_type1_ip);
263 64
264 disk->integrity->flags |= BLK_INTEGRITY_IP_CHECKSUM; 65 disk->integrity->flags |= BLK_INTEGRITY_IP_CHECKSUM;
265 } else 66 } else
266 if (type == SD_DIF_TYPE3_PROTECTION) 67 if (type == SD_DIF_TYPE3_PROTECTION)
267 blk_integrity_register(disk, &dif_type3_integrity_crc); 68 blk_integrity_register(disk, &t10_pi_type3_crc);
268 else 69 else
269 blk_integrity_register(disk, &dif_type1_integrity_crc); 70 blk_integrity_register(disk, &t10_pi_type1_crc);
270 71
271 sd_printk(KERN_NOTICE, sdkp, 72 sd_printk(KERN_NOTICE, sdkp,
272 "Enabling DIX %s protection\n", disk->integrity->name); 73 "Enabling DIX %s protection\n", disk->integrity->name);
@@ -308,10 +109,10 @@ void sd_dif_config_host(struct scsi_disk *sdkp)
308void sd_dif_prepare(struct request *rq, sector_t hw_sector, 109void sd_dif_prepare(struct request *rq, sector_t hw_sector,
309 unsigned int sector_sz) 110 unsigned int sector_sz)
310{ 111{
311 const int tuple_sz = sizeof(struct sd_dif_tuple); 112 const int tuple_sz = sizeof(struct t10_pi_tuple);
312 struct bio *bio; 113 struct bio *bio;
313 struct scsi_disk *sdkp; 114 struct scsi_disk *sdkp;
314 struct sd_dif_tuple *sdt; 115 struct t10_pi_tuple *pi;
315 u32 phys, virt; 116 u32 phys, virt;
316 117
317 sdkp = rq->bio->bi_bdev->bd_disk->private_data; 118 sdkp = rq->bio->bi_bdev->bd_disk->private_data;
@@ -334,19 +135,18 @@ void sd_dif_prepare(struct request *rq, sector_t hw_sector,
334 virt = bip_get_seed(bip) & 0xffffffff; 135 virt = bip_get_seed(bip) & 0xffffffff;
335 136
336 bip_for_each_vec(iv, bip, iter) { 137 bip_for_each_vec(iv, bip, iter) {
337 sdt = kmap_atomic(iv.bv_page) 138 pi = kmap_atomic(iv.bv_page) + iv.bv_offset;
338 + iv.bv_offset;
339 139
340 for (j = 0; j < iv.bv_len; j += tuple_sz, sdt++) { 140 for (j = 0; j < iv.bv_len; j += tuple_sz, pi++) {
341 141
342 if (be32_to_cpu(sdt->ref_tag) == virt) 142 if (be32_to_cpu(pi->ref_tag) == virt)
343 sdt->ref_tag = cpu_to_be32(phys); 143 pi->ref_tag = cpu_to_be32(phys);
344 144
345 virt++; 145 virt++;
346 phys++; 146 phys++;
347 } 147 }
348 148
349 kunmap_atomic(sdt); 149 kunmap_atomic(pi);
350 } 150 }
351 151
352 bip->bip_flags |= BIP_MAPPED_INTEGRITY; 152 bip->bip_flags |= BIP_MAPPED_INTEGRITY;
@@ -359,10 +159,10 @@ void sd_dif_prepare(struct request *rq, sector_t hw_sector,
359 */ 159 */
360void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes) 160void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes)
361{ 161{
362 const int tuple_sz = sizeof(struct sd_dif_tuple); 162 const int tuple_sz = sizeof(struct t10_pi_tuple);
363 struct scsi_disk *sdkp; 163 struct scsi_disk *sdkp;
364 struct bio *bio; 164 struct bio *bio;
365 struct sd_dif_tuple *sdt; 165 struct t10_pi_tuple *pi;
366 unsigned int j, sectors, sector_sz; 166 unsigned int j, sectors, sector_sz;
367 u32 phys, virt; 167 u32 phys, virt;
368 168
@@ -386,25 +186,24 @@ void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes)
386 virt = bip_get_seed(bip) & 0xffffffff; 186 virt = bip_get_seed(bip) & 0xffffffff;
387 187
388 bip_for_each_vec(iv, bip, iter) { 188 bip_for_each_vec(iv, bip, iter) {
389 sdt = kmap_atomic(iv.bv_page) 189 pi = kmap_atomic(iv.bv_page) + iv.bv_offset;
390 + iv.bv_offset;
391 190
392 for (j = 0; j < iv.bv_len; j += tuple_sz, sdt++) { 191 for (j = 0; j < iv.bv_len; j += tuple_sz, pi++) {
393 192
394 if (sectors == 0) { 193 if (sectors == 0) {
395 kunmap_atomic(sdt); 194 kunmap_atomic(pi);
396 return; 195 return;
397 } 196 }
398 197
399 if (be32_to_cpu(sdt->ref_tag) == phys) 198 if (be32_to_cpu(pi->ref_tag) == phys)
400 sdt->ref_tag = cpu_to_be32(virt); 199 pi->ref_tag = cpu_to_be32(virt);
401 200
402 virt++; 201 virt++;
403 phys++; 202 phys++;
404 sectors--; 203 sectors--;
405 } 204 }
406 205
407 kunmap_atomic(sdt); 206 kunmap_atomic(pi);
408 } 207 }
409 } 208 }
410} 209}