aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/sd_dif.c
diff options
context:
space:
mode:
authorMax Gurtovoy <maxg@mellanox.com>2018-07-29 17:15:32 -0400
committerJens Axboe <axboe@kernel.dk>2018-07-30 10:27:02 -0400
commit10c41ddd61323b27b447bc8e18296ac6c06107ad (patch)
tree116e298295cfafda21080e0c83b501862753fcf1 /drivers/scsi/sd_dif.c
parentddd0bc756983dc4d19000a4fe021b4c7f9d59aab (diff)
block: move dif_prepare/dif_complete functions to block layer
Currently these functions are implemented in the scsi layer, but their actual place should be the block layer since T10-PI is a general data integrity feature that is used in the nvme protocol as well. Also, use the tuple size from the integrity profile since it may vary between integrity types. Suggested-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: Max Gurtovoy <maxg@mellanox.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'drivers/scsi/sd_dif.c')
-rw-r--r--drivers/scsi/sd_dif.c113
1 files changed, 0 insertions, 113 deletions
diff --git a/drivers/scsi/sd_dif.c b/drivers/scsi/sd_dif.c
index d8de43d359ac..db72c82486e3 100644
--- a/drivers/scsi/sd_dif.c
+++ b/drivers/scsi/sd_dif.c
@@ -95,116 +95,3 @@ out:
95 blk_integrity_register(disk, &bi); 95 blk_integrity_register(disk, &bi);
96} 96}
97 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 = t10_pi_ref_tag(scmd->request);
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 = t10_pi_ref_tag(scmd->request);
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