sd_dif.c (aae7df50190a640e51bfe11c93f94741ac82ff0b) | sd_dif.c (2341c2f8c33196d02cf5a721746eea4e3c06674a) |
---|---|
1/* 2 * sd_dif.c - SCSI Data Integrity Field 3 * 4 * Copyright (C) 2007, 2008 Oracle Corporation 5 * Written by: Martin K. Petersen <martin.petersen@oracle.com> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License version --- 7 unchanged lines hidden (view full) --- 16 * You should have received a copy of the GNU General Public License 17 * along with this program; see the file COPYING. If not, write to 18 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, 19 * USA. 20 * 21 */ 22 23#include <linux/blkdev.h> | 1/* 2 * sd_dif.c - SCSI Data Integrity Field 3 * 4 * Copyright (C) 2007, 2008 Oracle Corporation 5 * Written by: Martin K. Petersen <martin.petersen@oracle.com> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License version --- 7 unchanged lines hidden (view full) --- 16 * You should have received a copy of the GNU General Public License 17 * along with this program; see the file COPYING. If not, write to 18 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, 19 * USA. 20 * 21 */ 22 23#include <linux/blkdev.h> |
24#include <linux/crc-t10dif.h> | 24#include <linux/t10-pi.h> |
25 26#include <scsi/scsi.h> 27#include <scsi/scsi_cmnd.h> 28#include <scsi/scsi_dbg.h> 29#include <scsi/scsi_device.h> 30#include <scsi/scsi_driver.h> 31#include <scsi/scsi_eh.h> 32#include <scsi/scsi_host.h> 33#include <scsi/scsi_ioctl.h> 34#include <scsi/scsicam.h> 35 | 25 26#include <scsi/scsi.h> 27#include <scsi/scsi_cmnd.h> 28#include <scsi/scsi_dbg.h> 29#include <scsi/scsi_device.h> 30#include <scsi/scsi_driver.h> 31#include <scsi/scsi_eh.h> 32#include <scsi/scsi_host.h> 33#include <scsi/scsi_ioctl.h> 34#include <scsi/scsicam.h> 35 |
36#include <net/checksum.h> 37 | |
38#include "sd.h" 39 | 36#include "sd.h" 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/* | 38/* |
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/* | |
238 * Configure exchange of protection information between OS and HBA. 239 */ 240void sd_dif_config_host(struct scsi_disk *sdkp) 241{ 242 struct scsi_device *sdp = sdkp->device; 243 struct gendisk *disk = sdkp->disk; 244 u8 type = sdkp->protection_type; 245 int dif, dix; --- 6 unchanged lines hidden (view full) --- 252 } 253 254 if (!dix) 255 return; 256 257 /* Enable DMA of protection information */ 258 if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP) { 259 if (type == SD_DIF_TYPE3_PROTECTION) | 39 * Configure exchange of protection information between OS and HBA. 40 */ 41void sd_dif_config_host(struct scsi_disk *sdkp) 42{ 43 struct scsi_device *sdp = sdkp->device; 44 struct gendisk *disk = sdkp->disk; 45 u8 type = sdkp->protection_type; 46 int dif, dix; --- 6 unchanged lines hidden (view full) --- 53 } 54 55 if (!dix) 56 return; 57 58 /* Enable DMA of protection information */ 59 if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP) { 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 264 disk->integrity->flags |= BLK_INTEGRITY_IP_CHECKSUM; 265 } else 266 if (type == SD_DIF_TYPE3_PROTECTION) | 64 65 disk->integrity->flags |= BLK_INTEGRITY_IP_CHECKSUM; 66 } else 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 271 sd_printk(KERN_NOTICE, sdkp, 272 "Enabling DIX %s protection\n", disk->integrity->name); 273 274 /* Signal to block layer that we support sector tagging */ 275 if (dif && type) { 276 277 disk->integrity->flags |= BLK_INTEGRITY_DEVICE_CAPABLE; --- 25 unchanged lines hidden (view full) --- 303 * (we could be reading from real disk as opposed to MD/DM device. So 304 * we always remap Type 2 making it identical to Type 1. 305 * 306 * Type 3 does not have a reference tag so no remapping is required. 307 */ 308void sd_dif_prepare(struct request *rq, sector_t hw_sector, 309 unsigned int sector_sz) 310{ | 71 72 sd_printk(KERN_NOTICE, sdkp, 73 "Enabling DIX %s protection\n", disk->integrity->name); 74 75 /* Signal to block layer that we support sector tagging */ 76 if (dif && type) { 77 78 disk->integrity->flags |= BLK_INTEGRITY_DEVICE_CAPABLE; --- 25 unchanged lines hidden (view full) --- 104 * (we could be reading from real disk as opposed to MD/DM device. So 105 * we always remap Type 2 making it identical to Type 1. 106 * 107 * Type 3 does not have a reference tag so no remapping is required. 108 */ 109void sd_dif_prepare(struct request *rq, sector_t hw_sector, 110 unsigned int sector_sz) 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; 313 struct scsi_disk *sdkp; | 113 struct bio *bio; 114 struct scsi_disk *sdkp; |
314 struct sd_dif_tuple *sdt; | 115 struct t10_pi_tuple *pi; |
315 u32 phys, virt; 316 317 sdkp = rq->bio->bi_bdev->bd_disk->private_data; 318 319 if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION) 320 return; 321 322 phys = hw_sector & 0xffffffff; --- 6 unchanged lines hidden (view full) --- 329 330 /* Already remapped? */ 331 if (bip->bip_flags & BIP_MAPPED_INTEGRITY) 332 break; 333 334 virt = bip_get_seed(bip) & 0xffffffff; 335 336 bip_for_each_vec(iv, bip, iter) { | 116 u32 phys, virt; 117 118 sdkp = rq->bio->bi_bdev->bd_disk->private_data; 119 120 if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION) 121 return; 122 123 phys = hw_sector & 0xffffffff; --- 6 unchanged lines hidden (view full) --- 130 131 /* Already remapped? */ 132 if (bip->bip_flags & BIP_MAPPED_INTEGRITY) 133 break; 134 135 virt = bip_get_seed(bip) & 0xffffffff; 136 137 bip_for_each_vec(iv, bip, iter) { |
337 sdt = kmap_atomic(iv.bv_page) 338 + iv.bv_offset; | 138 pi = kmap_atomic(iv.bv_page) + 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) 343 sdt->ref_tag = cpu_to_be32(phys); | 142 if (be32_to_cpu(pi->ref_tag) == virt) 143 pi->ref_tag = cpu_to_be32(phys); |
344 345 virt++; 346 phys++; 347 } 348 | 144 145 virt++; 146 phys++; 147 } 148 |
349 kunmap_atomic(sdt); | 149 kunmap_atomic(pi); |
350 } 351 352 bip->bip_flags |= BIP_MAPPED_INTEGRITY; 353 } 354} 355 356/* 357 * Remap physical sector values in the reference tag to the virtual 358 * values expected by the block layer. 359 */ 360void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes) 361{ | 150 } 151 152 bip->bip_flags |= BIP_MAPPED_INTEGRITY; 153 } 154} 155 156/* 157 * Remap physical sector values in the reference tag to the virtual 158 * values expected by the block layer. 159 */ 160void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes) 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; 364 struct bio *bio; | 163 struct scsi_disk *sdkp; 164 struct bio *bio; |
365 struct sd_dif_tuple *sdt; | 165 struct t10_pi_tuple *pi; |
366 unsigned int j, sectors, sector_sz; 367 u32 phys, virt; 368 369 sdkp = scsi_disk(scmd->request->rq_disk); 370 371 if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION || good_bytes == 0) 372 return; 373 --- 7 unchanged lines hidden (view full) --- 381 __rq_for_each_bio(bio, scmd->request) { 382 struct bio_integrity_payload *bip = bio_integrity(bio); 383 struct bio_vec iv; 384 struct bvec_iter iter; 385 386 virt = bip_get_seed(bip) & 0xffffffff; 387 388 bip_for_each_vec(iv, bip, iter) { | 166 unsigned int j, sectors, sector_sz; 167 u32 phys, virt; 168 169 sdkp = scsi_disk(scmd->request->rq_disk); 170 171 if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION || good_bytes == 0) 172 return; 173 --- 7 unchanged lines hidden (view full) --- 181 __rq_for_each_bio(bio, scmd->request) { 182 struct bio_integrity_payload *bip = bio_integrity(bio); 183 struct bio_vec iv; 184 struct bvec_iter iter; 185 186 virt = bip_get_seed(bip) & 0xffffffff; 187 188 bip_for_each_vec(iv, bip, iter) { |
389 sdt = kmap_atomic(iv.bv_page) 390 + iv.bv_offset; | 189 pi = kmap_atomic(iv.bv_page) + 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 394 if (sectors == 0) { | 192 193 if (sectors == 0) { |
395 kunmap_atomic(sdt); | 194 kunmap_atomic(pi); |
396 return; 397 } 398 | 195 return; 196 } 197 |
399 if (be32_to_cpu(sdt->ref_tag) == phys) 400 sdt->ref_tag = cpu_to_be32(virt); | 198 if (be32_to_cpu(pi->ref_tag) == phys) 199 pi->ref_tag = cpu_to_be32(virt); |
401 402 virt++; 403 phys++; 404 sectors--; 405 } 406 | 200 201 virt++; 202 phys++; 203 sectors--; 204 } 205 |
407 kunmap_atomic(sdt); | 206 kunmap_atomic(pi); |
408 } 409 } 410} 411 | 207 } 208 } 209} 210 |