diff options
author | Yunhong Jiang <yunhong.jiang@intel.com> | 2015-08-04 12:17:53 -0700 |
---|---|---|
committer | Yunhong Jiang <yunhong.jiang@intel.com> | 2015-08-04 15:44:42 -0700 |
commit | 9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (patch) | |
tree | 1c9cafbcd35f783a87880a10f85d1a060db1a563 /kernel/drivers/scsi/sd_dif.c | |
parent | 98260f3884f4a202f9ca5eabed40b1354c489b29 (diff) |
Add the rt linux 4.1.3-rt3 as base
Import the rt linux 4.1.3-rt3 as OPNFV kvm base.
It's from git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git linux-4.1.y-rt and
the base is:
commit 0917f823c59692d751951bf5ea699a2d1e2f26a2
Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Date: Sat Jul 25 12:13:34 2015 +0200
Prepare v4.1.3-rt3
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
We lose all the git history this way and it's not good. We
should apply another opnfv project repo in future.
Change-Id: I87543d81c9df70d99c5001fbdf646b202c19f423
Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com>
Diffstat (limited to 'kernel/drivers/scsi/sd_dif.c')
-rw-r--r-- | kernel/drivers/scsi/sd_dif.c | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/kernel/drivers/scsi/sd_dif.c b/kernel/drivers/scsi/sd_dif.c new file mode 100644 index 000000000..5c06d292b --- /dev/null +++ b/kernel/drivers/scsi/sd_dif.c @@ -0,0 +1,205 @@ +/* + * sd_dif.c - SCSI Data Integrity Field + * + * Copyright (C) 2007, 2008 Oracle Corporation + * Written by: Martin K. Petersen <martin.petersen@oracle.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + */ + +#include <linux/blkdev.h> +#include <linux/t10-pi.h> + +#include <scsi/scsi.h> +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_dbg.h> +#include <scsi/scsi_device.h> +#include <scsi/scsi_driver.h> +#include <scsi/scsi_eh.h> +#include <scsi/scsi_host.h> +#include <scsi/scsi_ioctl.h> +#include <scsi/scsicam.h> + +#include "sd.h" + +/* + * Configure exchange of protection information between OS and HBA. + */ +void sd_dif_config_host(struct scsi_disk *sdkp) +{ + struct scsi_device *sdp = sdkp->device; + struct gendisk *disk = sdkp->disk; + u8 type = sdkp->protection_type; + int dif, dix; + + dif = scsi_host_dif_capable(sdp->host, type); + dix = scsi_host_dix_capable(sdp->host, type); + + if (!dix && scsi_host_dix_capable(sdp->host, 0)) { + dif = 0; dix = 1; + } + + if (!dix) + return; + + /* Enable DMA of protection information */ + if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP) { + if (type == SD_DIF_TYPE3_PROTECTION) + blk_integrity_register(disk, &t10_pi_type3_ip); + else + blk_integrity_register(disk, &t10_pi_type1_ip); + + disk->integrity->flags |= BLK_INTEGRITY_IP_CHECKSUM; + } else + if (type == SD_DIF_TYPE3_PROTECTION) + blk_integrity_register(disk, &t10_pi_type3_crc); + else + blk_integrity_register(disk, &t10_pi_type1_crc); + + sd_printk(KERN_NOTICE, sdkp, + "Enabling DIX %s protection\n", disk->integrity->name); + + /* Signal to block layer that we support sector tagging */ + if (dif && type) { + + disk->integrity->flags |= BLK_INTEGRITY_DEVICE_CAPABLE; + + if (!sdkp->ATO) + return; + + if (type == SD_DIF_TYPE3_PROTECTION) + disk->integrity->tag_size = sizeof(u16) + sizeof(u32); + else + disk->integrity->tag_size = sizeof(u16); + + sd_printk(KERN_NOTICE, sdkp, "DIF application tag size %u\n", + disk->integrity->tag_size); + } +} + +/* + * The virtual start sector is the one that was originally submitted + * by the block layer. Due to partitioning, MD/DM cloning, etc. the + * actual physical start sector is likely to be different. Remap + * protection information to match the physical LBA. + * + * From a protocol perspective there's a slight difference between + * Type 1 and 2. The latter uses 32-byte CDBs exclusively, and the + * reference tag is seeded in the CDB. This gives us the potential to + * avoid virt->phys remapping during write. However, at read time we + * don't know whether the virt sector is the same as when we wrote it + * (we could be reading from real disk as opposed to MD/DM device. So + * we always remap Type 2 making it identical to Type 1. + * + * Type 3 does not have a reference tag so no remapping is required. + */ +void sd_dif_prepare(struct scsi_cmnd *scmd) +{ + const int tuple_sz = sizeof(struct t10_pi_tuple); + struct bio *bio; + struct scsi_disk *sdkp; + struct t10_pi_tuple *pi; + u32 phys, virt; + + sdkp = scsi_disk(scmd->request->rq_disk); + + if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION) + return; + + phys = scsi_prot_ref_tag(scmd); + + __rq_for_each_bio(bio, scmd->request) { + struct bio_integrity_payload *bip = bio_integrity(bio); + struct bio_vec iv; + struct bvec_iter iter; + unsigned int j; + + /* Already remapped? */ + if (bip->bip_flags & BIP_MAPPED_INTEGRITY) + break; + + virt = bip_get_seed(bip) & 0xffffffff; + + bip_for_each_vec(iv, bip, iter) { + pi = kmap_atomic(iv.bv_page) + iv.bv_offset; + + for (j = 0; j < iv.bv_len; j += tuple_sz, pi++) { + + if (be32_to_cpu(pi->ref_tag) == virt) + pi->ref_tag = cpu_to_be32(phys); + + virt++; + phys++; + } + + kunmap_atomic(pi); + } + + bip->bip_flags |= BIP_MAPPED_INTEGRITY; + } +} + +/* + * Remap physical sector values in the reference tag to the virtual + * values expected by the block layer. + */ +void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes) +{ + const int tuple_sz = sizeof(struct t10_pi_tuple); + struct scsi_disk *sdkp; + struct bio *bio; + struct t10_pi_tuple *pi; + unsigned int j, intervals; + u32 phys, virt; + + sdkp = scsi_disk(scmd->request->rq_disk); + + if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION || good_bytes == 0) + return; + + intervals = good_bytes / scsi_prot_interval(scmd); + phys = scsi_prot_ref_tag(scmd); + + __rq_for_each_bio(bio, scmd->request) { + struct bio_integrity_payload *bip = bio_integrity(bio); + struct bio_vec iv; + struct bvec_iter iter; + + virt = bip_get_seed(bip) & 0xffffffff; + + bip_for_each_vec(iv, bip, iter) { + pi = kmap_atomic(iv.bv_page) + iv.bv_offset; + + for (j = 0; j < iv.bv_len; j += tuple_sz, pi++) { + + if (intervals == 0) { + kunmap_atomic(pi); + return; + } + + if (be32_to_cpu(pi->ref_tag) == phys) + pi->ref_tag = cpu_to_be32(virt); + + virt++; + phys++; + intervals--; + } + + kunmap_atomic(pi); + } + } +} + |