linux/drivers/scsi/sd_dif.c
<<
>>
Prefs
   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 == T10_PI_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 == T10_PI_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 == T10_PI_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 == T10_PI_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 == T10_PI_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