aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/sd_dif.c
diff options
context:
space:
mode:
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}