Merge tag 'drivers-5.10-2020-10-12' of git://git.kernel.dk/linux-block
[sfrench/cifs-2.6.git] / crypto / async_tx / async_raid6_recov.c
index f249142ceac4f1eb672b9b9048ac285b70f47cb3..354b8cd5537f8702b513c9106fbeec91d9ca9ac5 100644 (file)
@@ -15,8 +15,9 @@
 #include <linux/dmaengine.h>
 
 static struct dma_async_tx_descriptor *
-async_sum_product(struct page *dest, struct page **srcs, unsigned char *coef,
-                 size_t len, struct async_submit_ctl *submit)
+async_sum_product(struct page *dest, unsigned int d_off,
+               struct page **srcs, unsigned int *src_offs, unsigned char *coef,
+               size_t len, struct async_submit_ctl *submit)
 {
        struct dma_chan *chan = async_tx_find_channel(submit, DMA_PQ,
                                                      &dest, 1, srcs, 2, len);
@@ -37,11 +38,14 @@ async_sum_product(struct page *dest, struct page **srcs, unsigned char *coef,
 
                if (submit->flags & ASYNC_TX_FENCE)
                        dma_flags |= DMA_PREP_FENCE;
-               unmap->addr[0] = dma_map_page(dev, srcs[0], 0, len, DMA_TO_DEVICE);
-               unmap->addr[1] = dma_map_page(dev, srcs[1], 0, len, DMA_TO_DEVICE);
+               unmap->addr[0] = dma_map_page(dev, srcs[0], src_offs[0],
+                                               len, DMA_TO_DEVICE);
+               unmap->addr[1] = dma_map_page(dev, srcs[1], src_offs[1],
+                                               len, DMA_TO_DEVICE);
                unmap->to_cnt = 2;
 
-               unmap->addr[2] = dma_map_page(dev, dest, 0, len, DMA_BIDIRECTIONAL);
+               unmap->addr[2] = dma_map_page(dev, dest, d_off,
+                                               len, DMA_BIDIRECTIONAL);
                unmap->bidi_cnt = 1;
                /* engine only looks at Q, but expects it to follow P */
                pq[1] = unmap->addr[2];
@@ -66,9 +70,9 @@ async_sum_product(struct page *dest, struct page **srcs, unsigned char *coef,
        async_tx_quiesce(&submit->depend_tx);
        amul = raid6_gfmul[coef[0]];
        bmul = raid6_gfmul[coef[1]];
-       a = page_address(srcs[0]);
-       b = page_address(srcs[1]);
-       c = page_address(dest);
+       a = page_address(srcs[0]) + src_offs[0];
+       b = page_address(srcs[1]) + src_offs[1];
+       c = page_address(dest) + d_off;
 
        while (len--) {
                ax    = amul[*a++];
@@ -80,8 +84,9 @@ async_sum_product(struct page *dest, struct page **srcs, unsigned char *coef,
 }
 
 static struct dma_async_tx_descriptor *
-async_mult(struct page *dest, struct page *src, u8 coef, size_t len,
-          struct async_submit_ctl *submit)
+async_mult(struct page *dest, unsigned int d_off, struct page *src,
+               unsigned int s_off, u8 coef, size_t len,
+               struct async_submit_ctl *submit)
 {
        struct dma_chan *chan = async_tx_find_channel(submit, DMA_PQ,
                                                      &dest, 1, &src, 1, len);
@@ -101,9 +106,11 @@ async_mult(struct page *dest, struct page *src, u8 coef, size_t len,
 
                if (submit->flags & ASYNC_TX_FENCE)
                        dma_flags |= DMA_PREP_FENCE;
-               unmap->addr[0] = dma_map_page(dev, src, 0, len, DMA_TO_DEVICE);
+               unmap->addr[0] = dma_map_page(dev, src, s_off,
+                                               len, DMA_TO_DEVICE);
                unmap->to_cnt++;
-               unmap->addr[1] = dma_map_page(dev, dest, 0, len, DMA_BIDIRECTIONAL);
+               unmap->addr[1] = dma_map_page(dev, dest, d_off,
+                                               len, DMA_BIDIRECTIONAL);
                dma_dest[1] = unmap->addr[1];
                unmap->bidi_cnt++;
                unmap->len = len;
@@ -133,8 +140,8 @@ async_mult(struct page *dest, struct page *src, u8 coef, size_t len,
         */
        async_tx_quiesce(&submit->depend_tx);
        qmul  = raid6_gfmul[coef];
-       d = page_address(dest);
-       s = page_address(src);
+       d = page_address(dest) + d_off;
+       s = page_address(src) + s_off;
 
        while (len--)
                *d++ = qmul[*s++];
@@ -144,11 +151,14 @@ async_mult(struct page *dest, struct page *src, u8 coef, size_t len,
 
 static struct dma_async_tx_descriptor *
 __2data_recov_4(int disks, size_t bytes, int faila, int failb,
-               struct page **blocks, struct async_submit_ctl *submit)
+               struct page **blocks, unsigned int *offs,
+               struct async_submit_ctl *submit)
 {
        struct dma_async_tx_descriptor *tx = NULL;
        struct page *p, *q, *a, *b;
+       unsigned int p_off, q_off, a_off, b_off;
        struct page *srcs[2];
+       unsigned int src_offs[2];
        unsigned char coef[2];
        enum async_tx_flags flags = submit->flags;
        dma_async_tx_callback cb_fn = submit->cb_fn;
@@ -156,26 +166,34 @@ __2data_recov_4(int disks, size_t bytes, int faila, int failb,
        void *scribble = submit->scribble;
 
        p = blocks[disks-2];
+       p_off = offs[disks-2];
        q = blocks[disks-1];
+       q_off = offs[disks-1];
 
        a = blocks[faila];
+       a_off = offs[faila];
        b = blocks[failb];
+       b_off = offs[failb];
 
        /* in the 4 disk case P + Pxy == P and Q + Qxy == Q */
        /* Dx = A*(P+Pxy) + B*(Q+Qxy) */
        srcs[0] = p;
+       src_offs[0] = p_off;
        srcs[1] = q;
+       src_offs[1] = q_off;
        coef[0] = raid6_gfexi[failb-faila];
        coef[1] = raid6_gfinv[raid6_gfexp[faila]^raid6_gfexp[failb]];
        init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL, scribble);
-       tx = async_sum_product(b, srcs, coef, bytes, submit);
+       tx = async_sum_product(b, b_off, srcs, src_offs, coef, bytes, submit);
 
        /* Dy = P+Pxy+Dx */
        srcs[0] = p;
+       src_offs[0] = p_off;
        srcs[1] = b;
+       src_offs[1] = b_off;
        init_async_submit(submit, flags | ASYNC_TX_XOR_ZERO_DST, tx, cb_fn,
                          cb_param, scribble);
-       tx = async_xor(a, srcs, 0, 2, bytes, submit);
+       tx = async_xor_offs(a, a_off, srcs, src_offs, 2, bytes, submit);
 
        return tx;
 
@@ -183,11 +201,14 @@ __2data_recov_4(int disks, size_t bytes, int faila, int failb,
 
 static struct dma_async_tx_descriptor *
 __2data_recov_5(int disks, size_t bytes, int faila, int failb,
-               struct page **blocks, struct async_submit_ctl *submit)
+               struct page **blocks, unsigned int *offs,
+               struct async_submit_ctl *submit)
 {
        struct dma_async_tx_descriptor *tx = NULL;
        struct page *p, *q, *g, *dp, *dq;
+       unsigned int p_off, q_off, g_off, dp_off, dq_off;
        struct page *srcs[2];
+       unsigned int src_offs[2];
        unsigned char coef[2];
        enum async_tx_flags flags = submit->flags;
        dma_async_tx_callback cb_fn = submit->cb_fn;
@@ -208,60 +229,77 @@ __2data_recov_5(int disks, size_t bytes, int faila, int failb,
        BUG_ON(good_srcs > 1);
 
        p = blocks[disks-2];
+       p_off = offs[disks-2];
        q = blocks[disks-1];
+       q_off = offs[disks-1];
        g = blocks[good];
+       g_off = offs[good];
 
        /* Compute syndrome with zero for the missing data pages
         * Use the dead data pages as temporary storage for delta p and
         * delta q
         */
        dp = blocks[faila];
+       dp_off = offs[faila];
        dq = blocks[failb];
+       dq_off = offs[failb];
 
        init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL, scribble);
-       tx = async_memcpy(dp, g, 0, 0, bytes, submit);
+       tx = async_memcpy(dp, g, dp_off, g_off, bytes, submit);
        init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL, scribble);
-       tx = async_mult(dq, g, raid6_gfexp[good], bytes, submit);
+       tx = async_mult(dq, dq_off, g, g_off,
+                       raid6_gfexp[good], bytes, submit);
 
        /* compute P + Pxy */
        srcs[0] = dp;
+       src_offs[0] = dp_off;
        srcs[1] = p;
+       src_offs[1] = p_off;
        init_async_submit(submit, ASYNC_TX_FENCE|ASYNC_TX_XOR_DROP_DST, tx,
                          NULL, NULL, scribble);
-       tx = async_xor(dp, srcs, 0, 2, bytes, submit);
+       tx = async_xor_offs(dp, dp_off, srcs, src_offs, 2, bytes, submit);
 
        /* compute Q + Qxy */
        srcs[0] = dq;
+       src_offs[0] = dq_off;
        srcs[1] = q;
+       src_offs[1] = q_off;
        init_async_submit(submit, ASYNC_TX_FENCE|ASYNC_TX_XOR_DROP_DST, tx,
                          NULL, NULL, scribble);
-       tx = async_xor(dq, srcs, 0, 2, bytes, submit);
+       tx = async_xor_offs(dq, dq_off, srcs, src_offs, 2, bytes, submit);
 
        /* Dx = A*(P+Pxy) + B*(Q+Qxy) */
        srcs[0] = dp;
+       src_offs[0] = dp_off;
        srcs[1] = dq;
+       src_offs[1] = dq_off;
        coef[0] = raid6_gfexi[failb-faila];
        coef[1] = raid6_gfinv[raid6_gfexp[faila]^raid6_gfexp[failb]];
        init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL, scribble);
-       tx = async_sum_product(dq, srcs, coef, bytes, submit);
+       tx = async_sum_product(dq, dq_off, srcs, src_offs, coef, bytes, submit);
 
        /* Dy = P+Pxy+Dx */
        srcs[0] = dp;
+       src_offs[0] = dp_off;
        srcs[1] = dq;
+       src_offs[1] = dq_off;
        init_async_submit(submit, flags | ASYNC_TX_XOR_DROP_DST, tx, cb_fn,
                          cb_param, scribble);
-       tx = async_xor(dp, srcs, 0, 2, bytes, submit);
+       tx = async_xor_offs(dp, dp_off, srcs, src_offs, 2, bytes, submit);
 
        return tx;
 }
 
 static struct dma_async_tx_descriptor *
 __2data_recov_n(int disks, size_t bytes, int faila, int failb,
-             struct page **blocks, struct async_submit_ctl *submit)
+             struct page **blocks, unsigned int *offs,
+                 struct async_submit_ctl *submit)
 {
        struct dma_async_tx_descriptor *tx = NULL;
        struct page *p, *q, *dp, *dq;
+       unsigned int p_off, q_off, dp_off, dq_off;
        struct page *srcs[2];
+       unsigned int src_offs[2];
        unsigned char coef[2];
        enum async_tx_flags flags = submit->flags;
        dma_async_tx_callback cb_fn = submit->cb_fn;
@@ -269,56 +307,74 @@ __2data_recov_n(int disks, size_t bytes, int faila, int failb,
        void *scribble = submit->scribble;
 
        p = blocks[disks-2];
+       p_off = offs[disks-2];
        q = blocks[disks-1];
+       q_off = offs[disks-1];
 
        /* Compute syndrome with zero for the missing data pages
         * Use the dead data pages as temporary storage for
         * delta p and delta q
         */
        dp = blocks[faila];
+       dp_off = offs[faila];
        blocks[faila] = NULL;
        blocks[disks-2] = dp;
+       offs[disks-2] = dp_off;
        dq = blocks[failb];
+       dq_off = offs[failb];
        blocks[failb] = NULL;
        blocks[disks-1] = dq;
+       offs[disks-1] = dq_off;
 
        init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL, scribble);
-       tx = async_gen_syndrome(blocks, 0, disks, bytes, submit);
+       tx = async_gen_syndrome(blocks, offs, disks, bytes, submit);
 
        /* Restore pointer table */
        blocks[faila]   = dp;
+       offs[faila] = dp_off;
        blocks[failb]   = dq;
+       offs[failb] = dq_off;
        blocks[disks-2] = p;
+       offs[disks-2] = p_off;
        blocks[disks-1] = q;
+       offs[disks-1] = q_off;
 
        /* compute P + Pxy */
        srcs[0] = dp;
+       src_offs[0] = dp_off;
        srcs[1] = p;
+       src_offs[1] = p_off;
        init_async_submit(submit, ASYNC_TX_FENCE|ASYNC_TX_XOR_DROP_DST, tx,
                          NULL, NULL, scribble);
-       tx = async_xor(dp, srcs, 0, 2, bytes, submit);
+       tx = async_xor_offs(dp, dp_off, srcs, src_offs, 2, bytes, submit);
 
        /* compute Q + Qxy */
        srcs[0] = dq;
+       src_offs[0] = dq_off;
        srcs[1] = q;
+       src_offs[1] = q_off;
        init_async_submit(submit, ASYNC_TX_FENCE|ASYNC_TX_XOR_DROP_DST, tx,
                          NULL, NULL, scribble);
-       tx = async_xor(dq, srcs, 0, 2, bytes, submit);
+       tx = async_xor_offs(dq, dq_off, srcs, src_offs, 2, bytes, submit);
 
        /* Dx = A*(P+Pxy) + B*(Q+Qxy) */
        srcs[0] = dp;
+       src_offs[0] = dp_off;
        srcs[1] = dq;
+       src_offs[1] = dq_off;
        coef[0] = raid6_gfexi[failb-faila];
        coef[1] = raid6_gfinv[raid6_gfexp[faila]^raid6_gfexp[failb]];
        init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL, scribble);
-       tx = async_sum_product(dq, srcs, coef, bytes, submit);
+       tx = async_sum_product(dq, dq_off, srcs, src_offs, coef, bytes, submit);
 
        /* Dy = P+Pxy+Dx */
        srcs[0] = dp;
+       src_offs[0] = dp_off;
        srcs[1] = dq;
+       src_offs[1] = dq_off;
        init_async_submit(submit, flags | ASYNC_TX_XOR_DROP_DST, tx, cb_fn,
                          cb_param, scribble);
-       tx = async_xor(dp, srcs, 0, 2, bytes, submit);
+       tx = async_xor_offs(dp, dp_off, srcs, src_offs, 2, bytes, submit);
 
        return tx;
 }
@@ -330,11 +386,13 @@ __2data_recov_n(int disks, size_t bytes, int faila, int failb,
  * @faila: first failed drive index
  * @failb: second failed drive index
  * @blocks: array of source pointers where the last two entries are p and q
+ * @offs: array of offset for pages in blocks
  * @submit: submission/completion modifiers
  */
 struct dma_async_tx_descriptor *
 async_raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
-                       struct page **blocks, struct async_submit_ctl *submit)
+                       struct page **blocks, unsigned int *offs,
+                       struct async_submit_ctl *submit)
 {
        void *scribble = submit->scribble;
        int non_zero_srcs, i;
@@ -358,7 +416,7 @@ async_raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
                        if (blocks[i] == NULL)
                                ptrs[i] = (void *) raid6_empty_zero_page;
                        else
-                               ptrs[i] = page_address(blocks[i]);
+                               ptrs[i] = page_address(blocks[i]) + offs[i];
 
                raid6_2data_recov(disks, bytes, faila, failb, ptrs);
 
@@ -383,16 +441,19 @@ async_raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
                 * explicitly handle the special case of a 4 disk array with
                 * both data disks missing.
                 */
-               return __2data_recov_4(disks, bytes, faila, failb, blocks, submit);
+               return __2data_recov_4(disks, bytes, faila, failb,
+                               blocks, offs, submit);
        case 3:
                /* dma devices do not uniformly understand a single
                 * source pq operation (in contrast to the synchronous
                 * case), so explicitly handle the special case of a 5 disk
                 * array with 2 of 3 data disks missing.
                 */
-               return __2data_recov_5(disks, bytes, faila, failb, blocks, submit);
+               return __2data_recov_5(disks, bytes, faila, failb,
+                               blocks, offs, submit);
        default:
-               return __2data_recov_n(disks, bytes, faila, failb, blocks, submit);
+               return __2data_recov_n(disks, bytes, faila, failb,
+                               blocks, offs, submit);
        }
 }
 EXPORT_SYMBOL_GPL(async_raid6_2data_recov);
@@ -403,14 +464,17 @@ EXPORT_SYMBOL_GPL(async_raid6_2data_recov);
  * @bytes: block size
  * @faila: failed drive index
  * @blocks: array of source pointers where the last two entries are p and q
+ * @offs: array of offset for pages in blocks
  * @submit: submission/completion modifiers
  */
 struct dma_async_tx_descriptor *
 async_raid6_datap_recov(int disks, size_t bytes, int faila,
-                       struct page **blocks, struct async_submit_ctl *submit)
+                       struct page **blocks, unsigned int *offs,
+                       struct async_submit_ctl *submit)
 {
        struct dma_async_tx_descriptor *tx = NULL;
        struct page *p, *q, *dq;
+       unsigned int p_off, q_off, dq_off;
        u8 coef;
        enum async_tx_flags flags = submit->flags;
        dma_async_tx_callback cb_fn = submit->cb_fn;
@@ -418,6 +482,7 @@ async_raid6_datap_recov(int disks, size_t bytes, int faila,
        void *scribble = submit->scribble;
        int good_srcs, good, i;
        struct page *srcs[2];
+       unsigned int src_offs[2];
 
        pr_debug("%s: disks: %d len: %zu\n", __func__, disks, bytes);
 
@@ -434,7 +499,7 @@ async_raid6_datap_recov(int disks, size_t bytes, int faila,
                        if (blocks[i] == NULL)
                                ptrs[i] = (void*)raid6_empty_zero_page;
                        else
-                               ptrs[i] = page_address(blocks[i]);
+                               ptrs[i] = page_address(blocks[i]) + offs[i];
 
                raid6_datap_recov(disks, bytes, faila, ptrs);
 
@@ -458,55 +523,67 @@ async_raid6_datap_recov(int disks, size_t bytes, int faila,
        BUG_ON(good_srcs == 0);
 
        p = blocks[disks-2];
+       p_off = offs[disks-2];
        q = blocks[disks-1];
+       q_off = offs[disks-1];
 
        /* Compute syndrome with zero for the missing data page
         * Use the dead data page as temporary storage for delta q
         */
        dq = blocks[faila];
+       dq_off = offs[faila];
        blocks[faila] = NULL;
        blocks[disks-1] = dq;
+       offs[disks-1] = dq_off;
 
        /* in the 4-disk case we only need to perform a single source
         * multiplication with the one good data block.
         */
        if (good_srcs == 1) {
                struct page *g = blocks[good];
+               unsigned int g_off = offs[good];
 
                init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL,
                                  scribble);
-               tx = async_memcpy(p, g, 0, 0, bytes, submit);
+               tx = async_memcpy(p, g, p_off, g_off, bytes, submit);
 
                init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL,
                                  scribble);
-               tx = async_mult(dq, g, raid6_gfexp[good], bytes, submit);
+               tx = async_mult(dq, dq_off, g, g_off,
+                               raid6_gfexp[good], bytes, submit);
        } else {
                init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL,
                                  scribble);
-               tx = async_gen_syndrome(blocks, 0, disks, bytes, submit);
+               tx = async_gen_syndrome(blocks, offs, disks, bytes, submit);
        }
 
        /* Restore pointer table */
        blocks[faila]   = dq;
+       offs[faila] = dq_off;
        blocks[disks-1] = q;
+       offs[disks-1] = q_off;
 
        /* calculate g^{-faila} */
        coef = raid6_gfinv[raid6_gfexp[faila]];
 
        srcs[0] = dq;
+       src_offs[0] = dq_off;
        srcs[1] = q;
+       src_offs[1] = q_off;
        init_async_submit(submit, ASYNC_TX_FENCE|ASYNC_TX_XOR_DROP_DST, tx,
                          NULL, NULL, scribble);
-       tx = async_xor(dq, srcs, 0, 2, bytes, submit);
+       tx = async_xor_offs(dq, dq_off, srcs, src_offs, 2, bytes, submit);
 
        init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL, scribble);
-       tx = async_mult(dq, dq, coef, bytes, submit);
+       tx = async_mult(dq, dq_off, dq, dq_off, coef, bytes, submit);
 
        srcs[0] = p;
+       src_offs[0] = p_off;
        srcs[1] = dq;
+       src_offs[1] = dq_off;
        init_async_submit(submit, flags | ASYNC_TX_XOR_DROP_DST, tx, cb_fn,
                          cb_param, scribble);
-       tx = async_xor(p, srcs, 0, 2, bytes, submit);
+       tx = async_xor_offs(p, p_off, srcs, src_offs, 2, bytes, submit);
 
        return tx;
 }