Commit | Line | Data |
---|---|---|
af55ff67 MP |
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> | |
2341c2f8 | 24 | #include <linux/t10-pi.h> |
af55ff67 MP |
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 | ||
af55ff67 MP |
36 | #include "sd.h" |
37 | ||
af55ff67 MP |
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; | |
9e06688e | 46 | int dif, dix; |
af55ff67 | 47 | |
9e06688e MP |
48 | dif = scsi_host_dif_capable(sdp->host, type); |
49 | dix = scsi_host_dix_capable(sdp->host, type); | |
af55ff67 | 50 | |
9e06688e MP |
51 | if (!dix && scsi_host_dix_capable(sdp->host, 0)) { |
52 | dif = 0; dix = 1; | |
53 | } | |
af55ff67 | 54 | |
9e06688e | 55 | if (!dix) |
af55ff67 | 56 | return; |
af55ff67 MP |
57 | |
58 | /* Enable DMA of protection information */ | |
aae7df50 | 59 | if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP) { |
af55ff67 | 60 | if (type == SD_DIF_TYPE3_PROTECTION) |
2341c2f8 | 61 | blk_integrity_register(disk, &t10_pi_type3_ip); |
af55ff67 | 62 | else |
2341c2f8 | 63 | blk_integrity_register(disk, &t10_pi_type1_ip); |
aae7df50 MP |
64 | |
65 | disk->integrity->flags |= BLK_INTEGRITY_IP_CHECKSUM; | |
66 | } else | |
af55ff67 | 67 | if (type == SD_DIF_TYPE3_PROTECTION) |
2341c2f8 | 68 | blk_integrity_register(disk, &t10_pi_type3_crc); |
af55ff67 | 69 | else |
2341c2f8 | 70 | blk_integrity_register(disk, &t10_pi_type1_crc); |
af55ff67 | 71 | |
cbdc1445 | 72 | sd_printk(KERN_NOTICE, sdkp, |
9e06688e | 73 | "Enabling DIX %s protection\n", disk->integrity->name); |
af55ff67 MP |
74 | |
75 | /* Signal to block layer that we support sector tagging */ | |
3aec2f41 MP |
76 | if (dif && type) { |
77 | ||
78 | disk->integrity->flags |= BLK_INTEGRITY_DEVICE_CAPABLE; | |
79 | ||
e557990e | 80 | if (!sdkp->ATO) |
3aec2f41 MP |
81 | return; |
82 | ||
af55ff67 MP |
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 | ||
cbdc1445 | 88 | sd_printk(KERN_NOTICE, sdkp, "DIF application tag size %u\n", |
af55ff67 MP |
89 | disk->integrity->tag_size); |
90 | } | |
91 | } | |
92 | ||
af55ff67 MP |
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 | */ | |
c611529e | 109 | void sd_dif_prepare(struct scsi_cmnd *scmd) |
af55ff67 | 110 | { |
2341c2f8 | 111 | const int tuple_sz = sizeof(struct t10_pi_tuple); |
af55ff67 MP |
112 | struct bio *bio; |
113 | struct scsi_disk *sdkp; | |
2341c2f8 | 114 | struct t10_pi_tuple *pi; |
af55ff67 MP |
115 | u32 phys, virt; |
116 | ||
c611529e | 117 | sdkp = scsi_disk(scmd->request->rq_disk); |
af55ff67 MP |
118 | |
119 | if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION) | |
8c579ab6 | 120 | return; |
af55ff67 | 121 | |
c611529e | 122 | phys = scsi_prot_ref_tag(scmd); |
af55ff67 | 123 | |
c611529e | 124 | __rq_for_each_bio(bio, scmd->request) { |
18593088 | 125 | struct bio_integrity_payload *bip = bio_integrity(bio); |
d57a5f7c KO |
126 | struct bio_vec iv; |
127 | struct bvec_iter iter; | |
128 | unsigned int j; | |
af55ff67 | 129 | |
495d2b38 | 130 | /* Already remapped? */ |
b1f01388 | 131 | if (bip->bip_flags & BIP_MAPPED_INTEGRITY) |
495d2b38 MP |
132 | break; |
133 | ||
18593088 | 134 | virt = bip_get_seed(bip) & 0xffffffff; |
af55ff67 | 135 | |
18593088 | 136 | bip_for_each_vec(iv, bip, iter) { |
2341c2f8 | 137 | pi = kmap_atomic(iv.bv_page) + iv.bv_offset; |
af55ff67 | 138 | |
2341c2f8 | 139 | for (j = 0; j < iv.bv_len; j += tuple_sz, pi++) { |
af55ff67 | 140 | |
2341c2f8 MP |
141 | if (be32_to_cpu(pi->ref_tag) == virt) |
142 | pi->ref_tag = cpu_to_be32(phys); | |
af55ff67 | 143 | |
af55ff67 MP |
144 | virt++; |
145 | phys++; | |
146 | } | |
147 | ||
2341c2f8 | 148 | kunmap_atomic(pi); |
af55ff67 | 149 | } |
495d2b38 | 150 | |
b1f01388 | 151 | bip->bip_flags |= BIP_MAPPED_INTEGRITY; |
af55ff67 | 152 | } |
af55ff67 MP |
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 | { | |
2341c2f8 | 161 | const int tuple_sz = sizeof(struct t10_pi_tuple); |
af55ff67 MP |
162 | struct scsi_disk *sdkp; |
163 | struct bio *bio; | |
2341c2f8 | 164 | struct t10_pi_tuple *pi; |
c611529e | 165 | unsigned int j, intervals; |
af55ff67 MP |
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 | ||
c611529e MP |
173 | intervals = good_bytes / scsi_prot_interval(scmd); |
174 | phys = scsi_prot_ref_tag(scmd); | |
af55ff67 MP |
175 | |
176 | __rq_for_each_bio(bio, scmd->request) { | |
18593088 | 177 | struct bio_integrity_payload *bip = bio_integrity(bio); |
d57a5f7c KO |
178 | struct bio_vec iv; |
179 | struct bvec_iter iter; | |
af55ff67 | 180 | |
18593088 | 181 | virt = bip_get_seed(bip) & 0xffffffff; |
af55ff67 | 182 | |
18593088 | 183 | bip_for_each_vec(iv, bip, iter) { |
2341c2f8 | 184 | pi = kmap_atomic(iv.bv_page) + iv.bv_offset; |
af55ff67 | 185 | |
2341c2f8 | 186 | for (j = 0; j < iv.bv_len; j += tuple_sz, pi++) { |
af55ff67 | 187 | |
c611529e | 188 | if (intervals == 0) { |
2341c2f8 | 189 | kunmap_atomic(pi); |
af55ff67 MP |
190 | return; |
191 | } | |
192 | ||
2341c2f8 MP |
193 | if (be32_to_cpu(pi->ref_tag) == phys) |
194 | pi->ref_tag = cpu_to_be32(virt); | |
af55ff67 MP |
195 | |
196 | virt++; | |
197 | phys++; | |
c611529e | 198 | intervals--; |
af55ff67 MP |
199 | } |
200 | ||
2341c2f8 | 201 | kunmap_atomic(pi); |
af55ff67 MP |
202 | } |
203 | } | |
204 | } | |
205 |