.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Asynchronous RAID-6 recovery calculations ASYNC_TX API. |
---|
3 | 4 | * Copyright(c) 2009 Intel Corporation |
---|
4 | 5 | * |
---|
5 | 6 | * based on raid6recov.c: |
---|
6 | 7 | * Copyright 2002 H. Peter Anvin |
---|
7 | | - * |
---|
8 | | - * This program is free software; you can redistribute it and/or modify it |
---|
9 | | - * under the terms of the GNU General Public License as published by the Free |
---|
10 | | - * Software Foundation; either version 2 of the License, or (at your option) |
---|
11 | | - * any later version. |
---|
12 | | - * |
---|
13 | | - * This program is distributed in the hope that it will be useful, but WITHOUT |
---|
14 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
---|
15 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
---|
16 | | - * more details. |
---|
17 | | - * |
---|
18 | | - * You should have received a copy of the GNU General Public License along with |
---|
19 | | - * this program; if not, write to the Free Software Foundation, Inc., 51 |
---|
20 | | - * Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. |
---|
21 | | - * |
---|
22 | 8 | */ |
---|
23 | 9 | #include <linux/kernel.h> |
---|
24 | 10 | #include <linux/interrupt.h> |
---|
.. | .. |
---|
29 | 15 | #include <linux/dmaengine.h> |
---|
30 | 16 | |
---|
31 | 17 | static struct dma_async_tx_descriptor * |
---|
32 | | -async_sum_product(struct page *dest, struct page **srcs, unsigned char *coef, |
---|
33 | | - size_t len, struct async_submit_ctl *submit) |
---|
| 18 | +async_sum_product(struct page *dest, unsigned int d_off, |
---|
| 19 | + struct page **srcs, unsigned int *src_offs, unsigned char *coef, |
---|
| 20 | + size_t len, struct async_submit_ctl *submit) |
---|
34 | 21 | { |
---|
35 | 22 | struct dma_chan *chan = async_tx_find_channel(submit, DMA_PQ, |
---|
36 | 23 | &dest, 1, srcs, 2, len); |
---|
.. | .. |
---|
51 | 38 | |
---|
52 | 39 | if (submit->flags & ASYNC_TX_FENCE) |
---|
53 | 40 | dma_flags |= DMA_PREP_FENCE; |
---|
54 | | - unmap->addr[0] = dma_map_page(dev, srcs[0], 0, len, DMA_TO_DEVICE); |
---|
55 | | - unmap->addr[1] = dma_map_page(dev, srcs[1], 0, len, DMA_TO_DEVICE); |
---|
| 41 | + unmap->addr[0] = dma_map_page(dev, srcs[0], src_offs[0], |
---|
| 42 | + len, DMA_TO_DEVICE); |
---|
| 43 | + unmap->addr[1] = dma_map_page(dev, srcs[1], src_offs[1], |
---|
| 44 | + len, DMA_TO_DEVICE); |
---|
56 | 45 | unmap->to_cnt = 2; |
---|
57 | 46 | |
---|
58 | | - unmap->addr[2] = dma_map_page(dev, dest, 0, len, DMA_BIDIRECTIONAL); |
---|
| 47 | + unmap->addr[2] = dma_map_page(dev, dest, d_off, |
---|
| 48 | + len, DMA_BIDIRECTIONAL); |
---|
59 | 49 | unmap->bidi_cnt = 1; |
---|
60 | 50 | /* engine only looks at Q, but expects it to follow P */ |
---|
61 | 51 | pq[1] = unmap->addr[2]; |
---|
.. | .. |
---|
80 | 70 | async_tx_quiesce(&submit->depend_tx); |
---|
81 | 71 | amul = raid6_gfmul[coef[0]]; |
---|
82 | 72 | bmul = raid6_gfmul[coef[1]]; |
---|
83 | | - a = page_address(srcs[0]); |
---|
84 | | - b = page_address(srcs[1]); |
---|
85 | | - c = page_address(dest); |
---|
| 73 | + a = page_address(srcs[0]) + src_offs[0]; |
---|
| 74 | + b = page_address(srcs[1]) + src_offs[1]; |
---|
| 75 | + c = page_address(dest) + d_off; |
---|
86 | 76 | |
---|
87 | 77 | while (len--) { |
---|
88 | 78 | ax = amul[*a++]; |
---|
.. | .. |
---|
94 | 84 | } |
---|
95 | 85 | |
---|
96 | 86 | static struct dma_async_tx_descriptor * |
---|
97 | | -async_mult(struct page *dest, struct page *src, u8 coef, size_t len, |
---|
98 | | - struct async_submit_ctl *submit) |
---|
| 87 | +async_mult(struct page *dest, unsigned int d_off, struct page *src, |
---|
| 88 | + unsigned int s_off, u8 coef, size_t len, |
---|
| 89 | + struct async_submit_ctl *submit) |
---|
99 | 90 | { |
---|
100 | 91 | struct dma_chan *chan = async_tx_find_channel(submit, DMA_PQ, |
---|
101 | 92 | &dest, 1, &src, 1, len); |
---|
.. | .. |
---|
115 | 106 | |
---|
116 | 107 | if (submit->flags & ASYNC_TX_FENCE) |
---|
117 | 108 | dma_flags |= DMA_PREP_FENCE; |
---|
118 | | - unmap->addr[0] = dma_map_page(dev, src, 0, len, DMA_TO_DEVICE); |
---|
| 109 | + unmap->addr[0] = dma_map_page(dev, src, s_off, |
---|
| 110 | + len, DMA_TO_DEVICE); |
---|
119 | 111 | unmap->to_cnt++; |
---|
120 | | - unmap->addr[1] = dma_map_page(dev, dest, 0, len, DMA_BIDIRECTIONAL); |
---|
| 112 | + unmap->addr[1] = dma_map_page(dev, dest, d_off, |
---|
| 113 | + len, DMA_BIDIRECTIONAL); |
---|
121 | 114 | dma_dest[1] = unmap->addr[1]; |
---|
122 | 115 | unmap->bidi_cnt++; |
---|
123 | 116 | unmap->len = len; |
---|
.. | .. |
---|
147 | 140 | */ |
---|
148 | 141 | async_tx_quiesce(&submit->depend_tx); |
---|
149 | 142 | qmul = raid6_gfmul[coef]; |
---|
150 | | - d = page_address(dest); |
---|
151 | | - s = page_address(src); |
---|
| 143 | + d = page_address(dest) + d_off; |
---|
| 144 | + s = page_address(src) + s_off; |
---|
152 | 145 | |
---|
153 | 146 | while (len--) |
---|
154 | 147 | *d++ = qmul[*s++]; |
---|
.. | .. |
---|
158 | 151 | |
---|
159 | 152 | static struct dma_async_tx_descriptor * |
---|
160 | 153 | __2data_recov_4(int disks, size_t bytes, int faila, int failb, |
---|
161 | | - struct page **blocks, struct async_submit_ctl *submit) |
---|
| 154 | + struct page **blocks, unsigned int *offs, |
---|
| 155 | + struct async_submit_ctl *submit) |
---|
162 | 156 | { |
---|
163 | 157 | struct dma_async_tx_descriptor *tx = NULL; |
---|
164 | 158 | struct page *p, *q, *a, *b; |
---|
| 159 | + unsigned int p_off, q_off, a_off, b_off; |
---|
165 | 160 | struct page *srcs[2]; |
---|
| 161 | + unsigned int src_offs[2]; |
---|
166 | 162 | unsigned char coef[2]; |
---|
167 | 163 | enum async_tx_flags flags = submit->flags; |
---|
168 | 164 | dma_async_tx_callback cb_fn = submit->cb_fn; |
---|
.. | .. |
---|
170 | 166 | void *scribble = submit->scribble; |
---|
171 | 167 | |
---|
172 | 168 | p = blocks[disks-2]; |
---|
| 169 | + p_off = offs[disks-2]; |
---|
173 | 170 | q = blocks[disks-1]; |
---|
| 171 | + q_off = offs[disks-1]; |
---|
174 | 172 | |
---|
175 | 173 | a = blocks[faila]; |
---|
| 174 | + a_off = offs[faila]; |
---|
176 | 175 | b = blocks[failb]; |
---|
| 176 | + b_off = offs[failb]; |
---|
177 | 177 | |
---|
178 | 178 | /* in the 4 disk case P + Pxy == P and Q + Qxy == Q */ |
---|
179 | 179 | /* Dx = A*(P+Pxy) + B*(Q+Qxy) */ |
---|
180 | 180 | srcs[0] = p; |
---|
| 181 | + src_offs[0] = p_off; |
---|
181 | 182 | srcs[1] = q; |
---|
| 183 | + src_offs[1] = q_off; |
---|
182 | 184 | coef[0] = raid6_gfexi[failb-faila]; |
---|
183 | 185 | coef[1] = raid6_gfinv[raid6_gfexp[faila]^raid6_gfexp[failb]]; |
---|
184 | 186 | init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL, scribble); |
---|
185 | | - tx = async_sum_product(b, srcs, coef, bytes, submit); |
---|
| 187 | + tx = async_sum_product(b, b_off, srcs, src_offs, coef, bytes, submit); |
---|
186 | 188 | |
---|
187 | 189 | /* Dy = P+Pxy+Dx */ |
---|
188 | 190 | srcs[0] = p; |
---|
| 191 | + src_offs[0] = p_off; |
---|
189 | 192 | srcs[1] = b; |
---|
| 193 | + src_offs[1] = b_off; |
---|
190 | 194 | init_async_submit(submit, flags | ASYNC_TX_XOR_ZERO_DST, tx, cb_fn, |
---|
191 | 195 | cb_param, scribble); |
---|
192 | | - tx = async_xor(a, srcs, 0, 2, bytes, submit); |
---|
| 196 | + tx = async_xor_offs(a, a_off, srcs, src_offs, 2, bytes, submit); |
---|
193 | 197 | |
---|
194 | 198 | return tx; |
---|
195 | 199 | |
---|
.. | .. |
---|
197 | 201 | |
---|
198 | 202 | static struct dma_async_tx_descriptor * |
---|
199 | 203 | __2data_recov_5(int disks, size_t bytes, int faila, int failb, |
---|
200 | | - struct page **blocks, struct async_submit_ctl *submit) |
---|
| 204 | + struct page **blocks, unsigned int *offs, |
---|
| 205 | + struct async_submit_ctl *submit) |
---|
201 | 206 | { |
---|
202 | 207 | struct dma_async_tx_descriptor *tx = NULL; |
---|
203 | 208 | struct page *p, *q, *g, *dp, *dq; |
---|
| 209 | + unsigned int p_off, q_off, g_off, dp_off, dq_off; |
---|
204 | 210 | struct page *srcs[2]; |
---|
| 211 | + unsigned int src_offs[2]; |
---|
205 | 212 | unsigned char coef[2]; |
---|
206 | 213 | enum async_tx_flags flags = submit->flags; |
---|
207 | 214 | dma_async_tx_callback cb_fn = submit->cb_fn; |
---|
.. | .. |
---|
222 | 229 | BUG_ON(good_srcs > 1); |
---|
223 | 230 | |
---|
224 | 231 | p = blocks[disks-2]; |
---|
| 232 | + p_off = offs[disks-2]; |
---|
225 | 233 | q = blocks[disks-1]; |
---|
| 234 | + q_off = offs[disks-1]; |
---|
226 | 235 | g = blocks[good]; |
---|
| 236 | + g_off = offs[good]; |
---|
227 | 237 | |
---|
228 | 238 | /* Compute syndrome with zero for the missing data pages |
---|
229 | 239 | * Use the dead data pages as temporary storage for delta p and |
---|
230 | 240 | * delta q |
---|
231 | 241 | */ |
---|
232 | 242 | dp = blocks[faila]; |
---|
| 243 | + dp_off = offs[faila]; |
---|
233 | 244 | dq = blocks[failb]; |
---|
| 245 | + dq_off = offs[failb]; |
---|
234 | 246 | |
---|
235 | 247 | init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL, scribble); |
---|
236 | | - tx = async_memcpy(dp, g, 0, 0, bytes, submit); |
---|
| 248 | + tx = async_memcpy(dp, g, dp_off, g_off, bytes, submit); |
---|
237 | 249 | init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL, scribble); |
---|
238 | | - tx = async_mult(dq, g, raid6_gfexp[good], bytes, submit); |
---|
| 250 | + tx = async_mult(dq, dq_off, g, g_off, |
---|
| 251 | + raid6_gfexp[good], bytes, submit); |
---|
239 | 252 | |
---|
240 | 253 | /* compute P + Pxy */ |
---|
241 | 254 | srcs[0] = dp; |
---|
| 255 | + src_offs[0] = dp_off; |
---|
242 | 256 | srcs[1] = p; |
---|
| 257 | + src_offs[1] = p_off; |
---|
243 | 258 | init_async_submit(submit, ASYNC_TX_FENCE|ASYNC_TX_XOR_DROP_DST, tx, |
---|
244 | 259 | NULL, NULL, scribble); |
---|
245 | | - tx = async_xor(dp, srcs, 0, 2, bytes, submit); |
---|
| 260 | + tx = async_xor_offs(dp, dp_off, srcs, src_offs, 2, bytes, submit); |
---|
246 | 261 | |
---|
247 | 262 | /* compute Q + Qxy */ |
---|
248 | 263 | srcs[0] = dq; |
---|
| 264 | + src_offs[0] = dq_off; |
---|
249 | 265 | srcs[1] = q; |
---|
| 266 | + src_offs[1] = q_off; |
---|
250 | 267 | init_async_submit(submit, ASYNC_TX_FENCE|ASYNC_TX_XOR_DROP_DST, tx, |
---|
251 | 268 | NULL, NULL, scribble); |
---|
252 | | - tx = async_xor(dq, srcs, 0, 2, bytes, submit); |
---|
| 269 | + tx = async_xor_offs(dq, dq_off, srcs, src_offs, 2, bytes, submit); |
---|
253 | 270 | |
---|
254 | 271 | /* Dx = A*(P+Pxy) + B*(Q+Qxy) */ |
---|
255 | 272 | srcs[0] = dp; |
---|
| 273 | + src_offs[0] = dp_off; |
---|
256 | 274 | srcs[1] = dq; |
---|
| 275 | + src_offs[1] = dq_off; |
---|
257 | 276 | coef[0] = raid6_gfexi[failb-faila]; |
---|
258 | 277 | coef[1] = raid6_gfinv[raid6_gfexp[faila]^raid6_gfexp[failb]]; |
---|
259 | 278 | init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL, scribble); |
---|
260 | | - tx = async_sum_product(dq, srcs, coef, bytes, submit); |
---|
| 279 | + tx = async_sum_product(dq, dq_off, srcs, src_offs, coef, bytes, submit); |
---|
261 | 280 | |
---|
262 | 281 | /* Dy = P+Pxy+Dx */ |
---|
263 | 282 | srcs[0] = dp; |
---|
| 283 | + src_offs[0] = dp_off; |
---|
264 | 284 | srcs[1] = dq; |
---|
| 285 | + src_offs[1] = dq_off; |
---|
265 | 286 | init_async_submit(submit, flags | ASYNC_TX_XOR_DROP_DST, tx, cb_fn, |
---|
266 | 287 | cb_param, scribble); |
---|
267 | | - tx = async_xor(dp, srcs, 0, 2, bytes, submit); |
---|
| 288 | + tx = async_xor_offs(dp, dp_off, srcs, src_offs, 2, bytes, submit); |
---|
268 | 289 | |
---|
269 | 290 | return tx; |
---|
270 | 291 | } |
---|
271 | 292 | |
---|
272 | 293 | static struct dma_async_tx_descriptor * |
---|
273 | 294 | __2data_recov_n(int disks, size_t bytes, int faila, int failb, |
---|
274 | | - struct page **blocks, struct async_submit_ctl *submit) |
---|
| 295 | + struct page **blocks, unsigned int *offs, |
---|
| 296 | + struct async_submit_ctl *submit) |
---|
275 | 297 | { |
---|
276 | 298 | struct dma_async_tx_descriptor *tx = NULL; |
---|
277 | 299 | struct page *p, *q, *dp, *dq; |
---|
| 300 | + unsigned int p_off, q_off, dp_off, dq_off; |
---|
278 | 301 | struct page *srcs[2]; |
---|
| 302 | + unsigned int src_offs[2]; |
---|
279 | 303 | unsigned char coef[2]; |
---|
280 | 304 | enum async_tx_flags flags = submit->flags; |
---|
281 | 305 | dma_async_tx_callback cb_fn = submit->cb_fn; |
---|
.. | .. |
---|
283 | 307 | void *scribble = submit->scribble; |
---|
284 | 308 | |
---|
285 | 309 | p = blocks[disks-2]; |
---|
| 310 | + p_off = offs[disks-2]; |
---|
286 | 311 | q = blocks[disks-1]; |
---|
| 312 | + q_off = offs[disks-1]; |
---|
287 | 313 | |
---|
288 | 314 | /* Compute syndrome with zero for the missing data pages |
---|
289 | 315 | * Use the dead data pages as temporary storage for |
---|
290 | 316 | * delta p and delta q |
---|
291 | 317 | */ |
---|
292 | 318 | dp = blocks[faila]; |
---|
| 319 | + dp_off = offs[faila]; |
---|
293 | 320 | blocks[faila] = NULL; |
---|
294 | 321 | blocks[disks-2] = dp; |
---|
| 322 | + offs[disks-2] = dp_off; |
---|
295 | 323 | dq = blocks[failb]; |
---|
| 324 | + dq_off = offs[failb]; |
---|
296 | 325 | blocks[failb] = NULL; |
---|
297 | 326 | blocks[disks-1] = dq; |
---|
| 327 | + offs[disks-1] = dq_off; |
---|
298 | 328 | |
---|
299 | 329 | init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL, scribble); |
---|
300 | | - tx = async_gen_syndrome(blocks, 0, disks, bytes, submit); |
---|
| 330 | + tx = async_gen_syndrome(blocks, offs, disks, bytes, submit); |
---|
301 | 331 | |
---|
302 | 332 | /* Restore pointer table */ |
---|
303 | 333 | blocks[faila] = dp; |
---|
| 334 | + offs[faila] = dp_off; |
---|
304 | 335 | blocks[failb] = dq; |
---|
| 336 | + offs[failb] = dq_off; |
---|
305 | 337 | blocks[disks-2] = p; |
---|
| 338 | + offs[disks-2] = p_off; |
---|
306 | 339 | blocks[disks-1] = q; |
---|
| 340 | + offs[disks-1] = q_off; |
---|
307 | 341 | |
---|
308 | 342 | /* compute P + Pxy */ |
---|
309 | 343 | srcs[0] = dp; |
---|
| 344 | + src_offs[0] = dp_off; |
---|
310 | 345 | srcs[1] = p; |
---|
| 346 | + src_offs[1] = p_off; |
---|
311 | 347 | init_async_submit(submit, ASYNC_TX_FENCE|ASYNC_TX_XOR_DROP_DST, tx, |
---|
312 | 348 | NULL, NULL, scribble); |
---|
313 | | - tx = async_xor(dp, srcs, 0, 2, bytes, submit); |
---|
| 349 | + tx = async_xor_offs(dp, dp_off, srcs, src_offs, 2, bytes, submit); |
---|
314 | 350 | |
---|
315 | 351 | /* compute Q + Qxy */ |
---|
316 | 352 | srcs[0] = dq; |
---|
| 353 | + src_offs[0] = dq_off; |
---|
317 | 354 | srcs[1] = q; |
---|
| 355 | + src_offs[1] = q_off; |
---|
318 | 356 | init_async_submit(submit, ASYNC_TX_FENCE|ASYNC_TX_XOR_DROP_DST, tx, |
---|
319 | 357 | NULL, NULL, scribble); |
---|
320 | | - tx = async_xor(dq, srcs, 0, 2, bytes, submit); |
---|
| 358 | + tx = async_xor_offs(dq, dq_off, srcs, src_offs, 2, bytes, submit); |
---|
321 | 359 | |
---|
322 | 360 | /* Dx = A*(P+Pxy) + B*(Q+Qxy) */ |
---|
323 | 361 | srcs[0] = dp; |
---|
| 362 | + src_offs[0] = dp_off; |
---|
324 | 363 | srcs[1] = dq; |
---|
| 364 | + src_offs[1] = dq_off; |
---|
325 | 365 | coef[0] = raid6_gfexi[failb-faila]; |
---|
326 | 366 | coef[1] = raid6_gfinv[raid6_gfexp[faila]^raid6_gfexp[failb]]; |
---|
327 | 367 | init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL, scribble); |
---|
328 | | - tx = async_sum_product(dq, srcs, coef, bytes, submit); |
---|
| 368 | + tx = async_sum_product(dq, dq_off, srcs, src_offs, coef, bytes, submit); |
---|
329 | 369 | |
---|
330 | 370 | /* Dy = P+Pxy+Dx */ |
---|
331 | 371 | srcs[0] = dp; |
---|
| 372 | + src_offs[0] = dp_off; |
---|
332 | 373 | srcs[1] = dq; |
---|
| 374 | + src_offs[1] = dq_off; |
---|
333 | 375 | init_async_submit(submit, flags | ASYNC_TX_XOR_DROP_DST, tx, cb_fn, |
---|
334 | 376 | cb_param, scribble); |
---|
335 | | - tx = async_xor(dp, srcs, 0, 2, bytes, submit); |
---|
| 377 | + tx = async_xor_offs(dp, dp_off, srcs, src_offs, 2, bytes, submit); |
---|
336 | 378 | |
---|
337 | 379 | return tx; |
---|
338 | 380 | } |
---|
.. | .. |
---|
344 | 386 | * @faila: first failed drive index |
---|
345 | 387 | * @failb: second failed drive index |
---|
346 | 388 | * @blocks: array of source pointers where the last two entries are p and q |
---|
| 389 | + * @offs: array of offset for pages in blocks |
---|
347 | 390 | * @submit: submission/completion modifiers |
---|
348 | 391 | */ |
---|
349 | 392 | struct dma_async_tx_descriptor * |
---|
350 | 393 | async_raid6_2data_recov(int disks, size_t bytes, int faila, int failb, |
---|
351 | | - struct page **blocks, struct async_submit_ctl *submit) |
---|
| 394 | + struct page **blocks, unsigned int *offs, |
---|
| 395 | + struct async_submit_ctl *submit) |
---|
352 | 396 | { |
---|
353 | 397 | void *scribble = submit->scribble; |
---|
354 | 398 | int non_zero_srcs, i; |
---|
.. | .. |
---|
372 | 416 | if (blocks[i] == NULL) |
---|
373 | 417 | ptrs[i] = (void *) raid6_empty_zero_page; |
---|
374 | 418 | else |
---|
375 | | - ptrs[i] = page_address(blocks[i]); |
---|
| 419 | + ptrs[i] = page_address(blocks[i]) + offs[i]; |
---|
376 | 420 | |
---|
377 | 421 | raid6_2data_recov(disks, bytes, faila, failb, ptrs); |
---|
378 | 422 | |
---|
.. | .. |
---|
397 | 441 | * explicitly handle the special case of a 4 disk array with |
---|
398 | 442 | * both data disks missing. |
---|
399 | 443 | */ |
---|
400 | | - return __2data_recov_4(disks, bytes, faila, failb, blocks, submit); |
---|
| 444 | + return __2data_recov_4(disks, bytes, faila, failb, |
---|
| 445 | + blocks, offs, submit); |
---|
401 | 446 | case 3: |
---|
402 | 447 | /* dma devices do not uniformly understand a single |
---|
403 | 448 | * source pq operation (in contrast to the synchronous |
---|
404 | 449 | * case), so explicitly handle the special case of a 5 disk |
---|
405 | 450 | * array with 2 of 3 data disks missing. |
---|
406 | 451 | */ |
---|
407 | | - return __2data_recov_5(disks, bytes, faila, failb, blocks, submit); |
---|
| 452 | + return __2data_recov_5(disks, bytes, faila, failb, |
---|
| 453 | + blocks, offs, submit); |
---|
408 | 454 | default: |
---|
409 | | - return __2data_recov_n(disks, bytes, faila, failb, blocks, submit); |
---|
| 455 | + return __2data_recov_n(disks, bytes, faila, failb, |
---|
| 456 | + blocks, offs, submit); |
---|
410 | 457 | } |
---|
411 | 458 | } |
---|
412 | 459 | EXPORT_SYMBOL_GPL(async_raid6_2data_recov); |
---|
.. | .. |
---|
417 | 464 | * @bytes: block size |
---|
418 | 465 | * @faila: failed drive index |
---|
419 | 466 | * @blocks: array of source pointers where the last two entries are p and q |
---|
| 467 | + * @offs: array of offset for pages in blocks |
---|
420 | 468 | * @submit: submission/completion modifiers |
---|
421 | 469 | */ |
---|
422 | 470 | struct dma_async_tx_descriptor * |
---|
423 | 471 | async_raid6_datap_recov(int disks, size_t bytes, int faila, |
---|
424 | | - struct page **blocks, struct async_submit_ctl *submit) |
---|
| 472 | + struct page **blocks, unsigned int *offs, |
---|
| 473 | + struct async_submit_ctl *submit) |
---|
425 | 474 | { |
---|
426 | 475 | struct dma_async_tx_descriptor *tx = NULL; |
---|
427 | 476 | struct page *p, *q, *dq; |
---|
| 477 | + unsigned int p_off, q_off, dq_off; |
---|
428 | 478 | u8 coef; |
---|
429 | 479 | enum async_tx_flags flags = submit->flags; |
---|
430 | 480 | dma_async_tx_callback cb_fn = submit->cb_fn; |
---|
.. | .. |
---|
432 | 482 | void *scribble = submit->scribble; |
---|
433 | 483 | int good_srcs, good, i; |
---|
434 | 484 | struct page *srcs[2]; |
---|
| 485 | + unsigned int src_offs[2]; |
---|
435 | 486 | |
---|
436 | 487 | pr_debug("%s: disks: %d len: %zu\n", __func__, disks, bytes); |
---|
437 | 488 | |
---|
.. | .. |
---|
448 | 499 | if (blocks[i] == NULL) |
---|
449 | 500 | ptrs[i] = (void*)raid6_empty_zero_page; |
---|
450 | 501 | else |
---|
451 | | - ptrs[i] = page_address(blocks[i]); |
---|
| 502 | + ptrs[i] = page_address(blocks[i]) + offs[i]; |
---|
452 | 503 | |
---|
453 | 504 | raid6_datap_recov(disks, bytes, faila, ptrs); |
---|
454 | 505 | |
---|
.. | .. |
---|
472 | 523 | BUG_ON(good_srcs == 0); |
---|
473 | 524 | |
---|
474 | 525 | p = blocks[disks-2]; |
---|
| 526 | + p_off = offs[disks-2]; |
---|
475 | 527 | q = blocks[disks-1]; |
---|
| 528 | + q_off = offs[disks-1]; |
---|
476 | 529 | |
---|
477 | 530 | /* Compute syndrome with zero for the missing data page |
---|
478 | 531 | * Use the dead data page as temporary storage for delta q |
---|
479 | 532 | */ |
---|
480 | 533 | dq = blocks[faila]; |
---|
| 534 | + dq_off = offs[faila]; |
---|
481 | 535 | blocks[faila] = NULL; |
---|
482 | 536 | blocks[disks-1] = dq; |
---|
| 537 | + offs[disks-1] = dq_off; |
---|
483 | 538 | |
---|
484 | 539 | /* in the 4-disk case we only need to perform a single source |
---|
485 | 540 | * multiplication with the one good data block. |
---|
486 | 541 | */ |
---|
487 | 542 | if (good_srcs == 1) { |
---|
488 | 543 | struct page *g = blocks[good]; |
---|
| 544 | + unsigned int g_off = offs[good]; |
---|
489 | 545 | |
---|
490 | 546 | init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL, |
---|
491 | 547 | scribble); |
---|
492 | | - tx = async_memcpy(p, g, 0, 0, bytes, submit); |
---|
| 548 | + tx = async_memcpy(p, g, p_off, g_off, bytes, submit); |
---|
493 | 549 | |
---|
494 | 550 | init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL, |
---|
495 | 551 | scribble); |
---|
496 | | - tx = async_mult(dq, g, raid6_gfexp[good], bytes, submit); |
---|
| 552 | + tx = async_mult(dq, dq_off, g, g_off, |
---|
| 553 | + raid6_gfexp[good], bytes, submit); |
---|
497 | 554 | } else { |
---|
498 | 555 | init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL, |
---|
499 | 556 | scribble); |
---|
500 | | - tx = async_gen_syndrome(blocks, 0, disks, bytes, submit); |
---|
| 557 | + tx = async_gen_syndrome(blocks, offs, disks, bytes, submit); |
---|
501 | 558 | } |
---|
502 | 559 | |
---|
503 | 560 | /* Restore pointer table */ |
---|
504 | 561 | blocks[faila] = dq; |
---|
| 562 | + offs[faila] = dq_off; |
---|
505 | 563 | blocks[disks-1] = q; |
---|
| 564 | + offs[disks-1] = q_off; |
---|
506 | 565 | |
---|
507 | 566 | /* calculate g^{-faila} */ |
---|
508 | 567 | coef = raid6_gfinv[raid6_gfexp[faila]]; |
---|
509 | 568 | |
---|
510 | 569 | srcs[0] = dq; |
---|
| 570 | + src_offs[0] = dq_off; |
---|
511 | 571 | srcs[1] = q; |
---|
| 572 | + src_offs[1] = q_off; |
---|
512 | 573 | init_async_submit(submit, ASYNC_TX_FENCE|ASYNC_TX_XOR_DROP_DST, tx, |
---|
513 | 574 | NULL, NULL, scribble); |
---|
514 | | - tx = async_xor(dq, srcs, 0, 2, bytes, submit); |
---|
| 575 | + tx = async_xor_offs(dq, dq_off, srcs, src_offs, 2, bytes, submit); |
---|
515 | 576 | |
---|
516 | 577 | init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL, scribble); |
---|
517 | | - tx = async_mult(dq, dq, coef, bytes, submit); |
---|
| 578 | + tx = async_mult(dq, dq_off, dq, dq_off, coef, bytes, submit); |
---|
518 | 579 | |
---|
519 | 580 | srcs[0] = p; |
---|
| 581 | + src_offs[0] = p_off; |
---|
520 | 582 | srcs[1] = dq; |
---|
| 583 | + src_offs[1] = dq_off; |
---|
521 | 584 | init_async_submit(submit, flags | ASYNC_TX_XOR_DROP_DST, tx, cb_fn, |
---|
522 | 585 | cb_param, scribble); |
---|
523 | | - tx = async_xor(p, srcs, 0, 2, bytes, submit); |
---|
| 586 | + tx = async_xor_offs(p, p_off, srcs, src_offs, 2, bytes, submit); |
---|
524 | 587 | |
---|
525 | 588 | return tx; |
---|
526 | 589 | } |
---|