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 */ 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 struct blk_integrity bi; 47 int dif, dix; 48 49 dif = scsi_host_dif_capable(sdp->host, type); 50 dix = scsi_host_dix_capable(sdp->host, type); 51 52 if (!dix && scsi_host_dix_capable(sdp->host, 0)) { 53 dif = 0; dix = 1; 54 } 55 56 if (!dix) 57 return; 58 59 memset(&bi, 0, sizeof(bi)); 60 61 /* Enable DMA of protection information */ 62 if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP) { 63 if (type == SD_DIF_TYPE3_PROTECTION) 64 bi.profile = &t10_pi_type3_ip; 65 else 66 bi.profile = &t10_pi_type1_ip; 67 68 bi.flags |= BLK_INTEGRITY_IP_CHECKSUM; 69 } else 70 if (type == SD_DIF_TYPE3_PROTECTION) 71 bi.profile = &t10_pi_type3_crc; 72 else 73 bi.profile = &t10_pi_type1_crc; 74 75 bi.tuple_size = sizeof(struct t10_pi_tuple); 76 sd_printk(KERN_NOTICE, sdkp, 77 "Enabling DIX %s protection\n", bi.profile->name); 78 79 if (dif && type) { 80 bi.flags |= BLK_INTEGRITY_DEVICE_CAPABLE; 81 82 if (!sdkp->ATO) 83 goto out; 84 85 if (type == SD_DIF_TYPE3_PROTECTION) 86 bi.tag_size = sizeof(u16) + sizeof(u32); 87 else 88 bi.tag_size = sizeof(u16); 89 90 sd_printk(KERN_NOTICE, sdkp, "DIF application tag size %u\n", 91 bi.tag_size); 92 } 93 94out: 95 blk_integrity_register(disk, &bi); 96} 97 98/* 99 * The virtual start sector is the one that was originally submitted 100 * by the block layer. Due to partitioning, MD/DM cloning, etc. the 101 * actual physical start sector is likely to be different. Remap 102 * protection information to match the physical LBA. 103 * 104 * From a protocol perspective there's a slight difference between 105 * Type 1 and 2. The latter uses 32-byte CDBs exclusively, and the 106 * reference tag is seeded in the CDB. This gives us the potential to 107 * avoid virt->phys remapping during write. However, at read time we 108 * don't know whether the virt sector is the same as when we wrote it 109 * (we could be reading from real disk as opposed to MD/DM device. So 110 * we always remap Type 2 making it identical to Type 1. 111 * 112 * Type 3 does not have a reference tag so no remapping is required. 113 */ 114void sd_dif_prepare(struct scsi_cmnd *scmd) 115{ 116 const int tuple_sz = sizeof(struct t10_pi_tuple); 117 struct bio *bio; 118 struct scsi_disk *sdkp; 119 struct t10_pi_tuple *pi; 120 u32 phys, virt; 121 122 sdkp = scsi_disk(scmd->request->rq_disk); 123 124 if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION) 125 return; 126 127 phys = scsi_prot_ref_tag(scmd); 128 129 __rq_for_each_bio(bio, scmd->request) { 130 struct bio_integrity_payload *bip = bio_integrity(bio); 131 struct bio_vec iv; 132 struct bvec_iter iter; 133 unsigned int j; 134 135 /* Already remapped? */ 136 if (bip->bip_flags & BIP_MAPPED_INTEGRITY) 137 break; 138 139 virt = bip_get_seed(bip) & 0xffffffff; 140 141 bip_for_each_vec(iv, bip, iter) { 142 pi = kmap_atomic(iv.bv_page) + iv.bv_offset; 143 144 for (j = 0; j < iv.bv_len; j += tuple_sz, pi++) { 145 146 if (be32_to_cpu(pi->ref_tag) == virt) 147 pi->ref_tag = cpu_to_be32(phys); 148 149 virt++; 150 phys++; 151 } 152 153 kunmap_atomic(pi); 154 } 155 156 bip->bip_flags |= BIP_MAPPED_INTEGRITY; 157 } 158} 159 160/* 161 * Remap physical sector values in the reference tag to the virtual 162 * values expected by the block layer. 163 */ 164void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes) 165{ 166 const int tuple_sz = sizeof(struct t10_pi_tuple); 167 struct scsi_disk *sdkp; 168 struct bio *bio; 169 struct t10_pi_tuple *pi; 170 unsigned int j, intervals; 171 u32 phys, virt; 172 173 sdkp = scsi_disk(scmd->request->rq_disk); 174 175 if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION || good_bytes == 0) 176 return; 177 178 intervals = good_bytes / scsi_prot_interval(scmd); 179 phys = scsi_prot_ref_tag(scmd); 180 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) { 189 pi = kmap_atomic(iv.bv_page) + iv.bv_offset; 190 191 for (j = 0; j < iv.bv_len; j += tuple_sz, pi++) { 192 193 if (intervals == 0) { 194 kunmap_atomic(pi); 195 return; 196 } 197 198 if (be32_to_cpu(pi->ref_tag) == phys) 199 pi->ref_tag = cpu_to_be32(virt); 200 201 virt++; 202 phys++; 203 intervals--; 204 } 205 206 kunmap_atomic(pi); 207 } 208 } 209} 210 211