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; | |
0f8087ec | 46 | struct blk_integrity bi; |
9e06688e | 47 | int dif, dix; |
af55ff67 | 48 | |
9e06688e MP |
49 | dif = scsi_host_dif_capable(sdp->host, type); |
50 | dix = scsi_host_dix_capable(sdp->host, type); | |
af55ff67 | 51 | |
9e06688e MP |
52 | if (!dix && scsi_host_dix_capable(sdp->host, 0)) { |
53 | dif = 0; dix = 1; | |
54 | } | |
af55ff67 | 55 | |
9e06688e | 56 | if (!dix) |
af55ff67 | 57 | return; |
af55ff67 | 58 | |
0f8087ec MP |
59 | memset(&bi, 0, sizeof(bi)); |
60 | ||
af55ff67 | 61 | /* Enable DMA of protection information */ |
aae7df50 | 62 | if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP) { |
8475c811 | 63 | if (type == T10_PI_TYPE3_PROTECTION) |
0f8087ec | 64 | bi.profile = &t10_pi_type3_ip; |
af55ff67 | 65 | else |
0f8087ec | 66 | bi.profile = &t10_pi_type1_ip; |
aae7df50 | 67 | |
0f8087ec | 68 | bi.flags |= BLK_INTEGRITY_IP_CHECKSUM; |
aae7df50 | 69 | } else |
8475c811 | 70 | if (type == T10_PI_TYPE3_PROTECTION) |
0f8087ec | 71 | bi.profile = &t10_pi_type3_crc; |
af55ff67 | 72 | else |
0f8087ec | 73 | bi.profile = &t10_pi_type1_crc; |
af55ff67 | 74 | |
0f8087ec | 75 | bi.tuple_size = sizeof(struct t10_pi_tuple); |
cbdc1445 | 76 | sd_printk(KERN_NOTICE, sdkp, |
0f8087ec | 77 | "Enabling DIX %s protection\n", bi.profile->name); |
af55ff67 | 78 | |
3aec2f41 | 79 | if (dif && type) { |
0f8087ec | 80 | bi.flags |= BLK_INTEGRITY_DEVICE_CAPABLE; |
3aec2f41 | 81 | |
e557990e | 82 | if (!sdkp->ATO) |
0f8087ec | 83 | goto out; |
3aec2f41 | 84 | |
8475c811 | 85 | if (type == T10_PI_TYPE3_PROTECTION) |
0f8087ec | 86 | bi.tag_size = sizeof(u16) + sizeof(u32); |
af55ff67 | 87 | else |
0f8087ec | 88 | bi.tag_size = sizeof(u16); |
af55ff67 | 89 | |
cbdc1445 | 90 | sd_printk(KERN_NOTICE, sdkp, "DIF application tag size %u\n", |
0f8087ec | 91 | bi.tag_size); |
af55ff67 | 92 | } |
0f8087ec MP |
93 | |
94 | out: | |
95 | blk_integrity_register(disk, &bi); | |
af55ff67 MP |
96 | } |
97 | ||
af55ff67 MP |
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 | */ | |
c611529e | 114 | void sd_dif_prepare(struct scsi_cmnd *scmd) |
af55ff67 | 115 | { |
2341c2f8 | 116 | const int tuple_sz = sizeof(struct t10_pi_tuple); |
af55ff67 MP |
117 | struct bio *bio; |
118 | struct scsi_disk *sdkp; | |
2341c2f8 | 119 | struct t10_pi_tuple *pi; |
af55ff67 MP |
120 | u32 phys, virt; |
121 | ||
c611529e | 122 | sdkp = scsi_disk(scmd->request->rq_disk); |
af55ff67 | 123 | |
8475c811 | 124 | if (sdkp->protection_type == T10_PI_TYPE3_PROTECTION) |
8c579ab6 | 125 | return; |
af55ff67 | 126 | |
c611529e | 127 | phys = scsi_prot_ref_tag(scmd); |
af55ff67 | 128 | |
c611529e | 129 | __rq_for_each_bio(bio, scmd->request) { |
18593088 | 130 | struct bio_integrity_payload *bip = bio_integrity(bio); |
d57a5f7c KO |
131 | struct bio_vec iv; |
132 | struct bvec_iter iter; | |
133 | unsigned int j; | |
af55ff67 | 134 | |
495d2b38 | 135 | /* Already remapped? */ |
b1f01388 | 136 | if (bip->bip_flags & BIP_MAPPED_INTEGRITY) |
495d2b38 MP |
137 | break; |
138 | ||
18593088 | 139 | virt = bip_get_seed(bip) & 0xffffffff; |
af55ff67 | 140 | |
18593088 | 141 | bip_for_each_vec(iv, bip, iter) { |
2341c2f8 | 142 | pi = kmap_atomic(iv.bv_page) + iv.bv_offset; |
af55ff67 | 143 | |
2341c2f8 | 144 | for (j = 0; j < iv.bv_len; j += tuple_sz, pi++) { |
af55ff67 | 145 | |
2341c2f8 MP |
146 | if (be32_to_cpu(pi->ref_tag) == virt) |
147 | pi->ref_tag = cpu_to_be32(phys); | |
af55ff67 | 148 | |
af55ff67 MP |
149 | virt++; |
150 | phys++; | |
151 | } | |
152 | ||
2341c2f8 | 153 | kunmap_atomic(pi); |
af55ff67 | 154 | } |
495d2b38 | 155 | |
b1f01388 | 156 | bip->bip_flags |= BIP_MAPPED_INTEGRITY; |
af55ff67 | 157 | } |
af55ff67 MP |
158 | } |
159 | ||
160 | /* | |
161 | * Remap physical sector values in the reference tag to the virtual | |
162 | * values expected by the block layer. | |
163 | */ | |
164 | void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes) | |
165 | { | |
2341c2f8 | 166 | const int tuple_sz = sizeof(struct t10_pi_tuple); |
af55ff67 MP |
167 | struct scsi_disk *sdkp; |
168 | struct bio *bio; | |
2341c2f8 | 169 | struct t10_pi_tuple *pi; |
c611529e | 170 | unsigned int j, intervals; |
af55ff67 MP |
171 | u32 phys, virt; |
172 | ||
173 | sdkp = scsi_disk(scmd->request->rq_disk); | |
174 | ||
8475c811 | 175 | if (sdkp->protection_type == T10_PI_TYPE3_PROTECTION || good_bytes == 0) |
af55ff67 MP |
176 | return; |
177 | ||
c611529e MP |
178 | intervals = good_bytes / scsi_prot_interval(scmd); |
179 | phys = scsi_prot_ref_tag(scmd); | |
af55ff67 MP |
180 | |
181 | __rq_for_each_bio(bio, scmd->request) { | |
18593088 | 182 | struct bio_integrity_payload *bip = bio_integrity(bio); |
d57a5f7c KO |
183 | struct bio_vec iv; |
184 | struct bvec_iter iter; | |
af55ff67 | 185 | |
18593088 | 186 | virt = bip_get_seed(bip) & 0xffffffff; |
af55ff67 | 187 | |
18593088 | 188 | bip_for_each_vec(iv, bip, iter) { |
2341c2f8 | 189 | pi = kmap_atomic(iv.bv_page) + iv.bv_offset; |
af55ff67 | 190 | |
2341c2f8 | 191 | for (j = 0; j < iv.bv_len; j += tuple_sz, pi++) { |
af55ff67 | 192 | |
c611529e | 193 | if (intervals == 0) { |
2341c2f8 | 194 | kunmap_atomic(pi); |
af55ff67 MP |
195 | return; |
196 | } | |
197 | ||
2341c2f8 MP |
198 | if (be32_to_cpu(pi->ref_tag) == phys) |
199 | pi->ref_tag = cpu_to_be32(virt); | |
af55ff67 MP |
200 | |
201 | virt++; | |
202 | phys++; | |
c611529e | 203 | intervals--; |
af55ff67 MP |
204 | } |
205 | ||
2341c2f8 | 206 | kunmap_atomic(pi); |
af55ff67 MP |
207 | } |
208 | } | |
209 | } | |
210 |