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 9 * 2 as published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope that it will be useful, but 12 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * General Public License for more details. 15 * 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/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 36 #include "sd.h" 37 38 /* 39 * Configure exchange of protection information between OS and HBA. 40 */ 41 void 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; 47 48 dif = scsi_host_dif_capable(sdp->host, type); 49 dix = scsi_host_dix_capable(sdp->host, type); 50 51 if (!dix && scsi_host_dix_capable(sdp->host, 0)) { 52 dif = 0; dix = 1; 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) 61 blk_integrity_register(disk, &t10_pi_type3_ip); 62 else 63 blk_integrity_register(disk, &t10_pi_type1_ip); 64 65 disk->integrity->flags |= BLK_INTEGRITY_IP_CHECKSUM; 66 } else 67 if (type == SD_DIF_TYPE3_PROTECTION) 68 blk_integrity_register(disk, &t10_pi_type3_crc); 69 else 70 blk_integrity_register(disk, &t10_pi_type1_crc); 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; 79 80 if (!sdkp->ATO) 81 return; 82 83 if (type == SD_DIF_TYPE3_PROTECTION) 84 disk->integrity->tag_size = sizeof(u16) + sizeof(u32); 85 else 86 disk->integrity->tag_size = sizeof(u16); 87 88 sd_printk(KERN_NOTICE, sdkp, "DIF application tag size %u\n", 89 disk->integrity->tag_size); 90 } 91 } 92 93 /* 94 * The virtual start sector is the one that was originally submitted 95 * by the block layer. Due to partitioning, MD/DM cloning, etc. the 96 * actual physical start sector is likely to be different. Remap 97 * protection information to match the physical LBA. 98 * 99 * From a protocol perspective there's a slight difference between 100 * Type 1 and 2. The latter uses 32-byte CDBs exclusively, and the 101 * reference tag is seeded in the CDB. This gives us the potential to 102 * avoid virt->phys remapping during write. However, at read time we 103 * don't know whether the virt sector is the same as when we wrote it 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 */ 109 void sd_dif_prepare(struct scsi_cmnd *scmd) 110 { 111 const int tuple_sz = sizeof(struct t10_pi_tuple); 112 struct bio *bio; 113 struct scsi_disk *sdkp; 114 struct t10_pi_tuple *pi; 115 u32 phys, virt; 116 117 sdkp = scsi_disk(scmd->request->rq_disk); 118 119 if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION) 120 return; 121 122 phys = scsi_prot_ref_tag(scmd); 123 124 __rq_for_each_bio(bio, scmd->request) { 125 struct bio_integrity_payload *bip = bio_integrity(bio); 126 struct bio_vec iv; 127 struct bvec_iter iter; 128 unsigned int j; 129 130 /* Already remapped? */ 131 if (bip->bip_flags & BIP_MAPPED_INTEGRITY) 132 break; 133 134 virt = bip_get_seed(bip) & 0xffffffff; 135 136 bip_for_each_vec(iv, bip, iter) { 137 pi = kmap_atomic(iv.bv_page) + iv.bv_offset; 138 139 for (j = 0; j < iv.bv_len; j += tuple_sz, pi++) { 140 141 if (be32_to_cpu(pi->ref_tag) == virt) 142 pi->ref_tag = cpu_to_be32(phys); 143 144 virt++; 145 phys++; 146 } 147 148 kunmap_atomic(pi); 149 } 150 151 bip->bip_flags |= BIP_MAPPED_INTEGRITY; 152 } 153 } 154 155 /* 156 * Remap physical sector values in the reference tag to the virtual 157 * values expected by the block layer. 158 */ 159 void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes) 160 { 161 const int tuple_sz = sizeof(struct t10_pi_tuple); 162 struct scsi_disk *sdkp; 163 struct bio *bio; 164 struct t10_pi_tuple *pi; 165 unsigned int j, intervals; 166 u32 phys, virt; 167 168 sdkp = scsi_disk(scmd->request->rq_disk); 169 170 if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION || good_bytes == 0) 171 return; 172 173 intervals = good_bytes / scsi_prot_interval(scmd); 174 phys = scsi_prot_ref_tag(scmd); 175 176 __rq_for_each_bio(bio, scmd->request) { 177 struct bio_integrity_payload *bip = bio_integrity(bio); 178 struct bio_vec iv; 179 struct bvec_iter iter; 180 181 virt = bip_get_seed(bip) & 0xffffffff; 182 183 bip_for_each_vec(iv, bip, iter) { 184 pi = kmap_atomic(iv.bv_page) + iv.bv_offset; 185 186 for (j = 0; j < iv.bv_len; j += tuple_sz, pi++) { 187 188 if (intervals == 0) { 189 kunmap_atomic(pi); 190 return; 191 } 192 193 if (be32_to_cpu(pi->ref_tag) == phys) 194 pi->ref_tag = cpu_to_be32(virt); 195 196 virt++; 197 phys++; 198 intervals--; 199 } 200 201 kunmap_atomic(pi); 202 } 203 } 204 } 205 206