diff options
Diffstat (limited to 'drivers/scsi/sd_dif.c')
-rw-r--r-- | drivers/scsi/sd_dif.c | 241 |
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 | ||
40 | typedef __u16 (csum_fn) (void *, unsigned int); | ||
41 | |||
42 | static __u16 sd_dif_crc_fn(void *data, unsigned int len) | ||
43 | { | ||
44 | return cpu_to_be16(crc_t10dif(data, len)); | ||
45 | } | ||
46 | |||
47 | static __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 | */ | ||
56 | static 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 | |||
73 | static 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 | |||
79 | static 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 | |||
85 | static 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 | |||
123 | static 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 | |||
128 | static 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 | |||
133 | static 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 | |||
141 | static 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 | */ | ||
154 | static 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 | |||
169 | static 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 | |||
175 | static 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 | |||
181 | static 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 | |||
211 | static 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 | |||
216 | static 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 | |||
221 | static 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 | |||
229 | static 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) | |||
308 | void sd_dif_prepare(struct request *rq, sector_t hw_sector, | 109 | void 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 | */ |
360 | void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes) | 160 | void 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 | } |