Merge tag 'i2c-for-6.6-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa...
[platform/kernel/linux-rpi.git] / lib / raid6 / recov.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* -*- linux-c -*- ------------------------------------------------------- *
3  *
4  *   Copyright 2002 H. Peter Anvin - All Rights Reserved
5  *
6  * ----------------------------------------------------------------------- */
7
8 /*
9  * raid6/recov.c
10  *
11  * RAID-6 data recovery in dual failure mode.  In single failure mode,
12  * use the RAID-5 algorithm (or, in the case of Q failure, just reconstruct
13  * the syndrome.)
14  */
15
16 #include <linux/raid/pq.h>
17
18 /* Recover two failed data blocks. */
19 static void raid6_2data_recov_intx1(int disks, size_t bytes, int faila,
20                 int failb, void **ptrs)
21 {
22         u8 *p, *q, *dp, *dq;
23         u8 px, qx, db;
24         const u8 *pbmul;        /* P multiplier table for B data */
25         const u8 *qmul;         /* Q multiplier table (for both) */
26
27         p = (u8 *)ptrs[disks-2];
28         q = (u8 *)ptrs[disks-1];
29
30         /* Compute syndrome with zero for the missing data pages
31            Use the dead data pages as temporary storage for
32            delta p and delta q */
33         dp = (u8 *)ptrs[faila];
34         ptrs[faila] = (void *)raid6_empty_zero_page;
35         ptrs[disks-2] = dp;
36         dq = (u8 *)ptrs[failb];
37         ptrs[failb] = (void *)raid6_empty_zero_page;
38         ptrs[disks-1] = dq;
39
40         raid6_call.gen_syndrome(disks, bytes, ptrs);
41
42         /* Restore pointer table */
43         ptrs[faila]   = dp;
44         ptrs[failb]   = dq;
45         ptrs[disks-2] = p;
46         ptrs[disks-1] = q;
47
48         /* Now, pick the proper data tables */
49         pbmul = raid6_gfmul[raid6_gfexi[failb-faila]];
50         qmul  = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]^raid6_gfexp[failb]]];
51
52         /* Now do it... */
53         while ( bytes-- ) {
54                 px    = *p ^ *dp;
55                 qx    = qmul[*q ^ *dq];
56                 *dq++ = db = pbmul[px] ^ qx; /* Reconstructed B */
57                 *dp++ = db ^ px; /* Reconstructed A */
58                 p++; q++;
59         }
60 }
61
62 /* Recover failure of one data block plus the P block */
63 static void raid6_datap_recov_intx1(int disks, size_t bytes, int faila,
64                 void **ptrs)
65 {
66         u8 *p, *q, *dq;
67         const u8 *qmul;         /* Q multiplier table */
68
69         p = (u8 *)ptrs[disks-2];
70         q = (u8 *)ptrs[disks-1];
71
72         /* Compute syndrome with zero for the missing data page
73            Use the dead data page as temporary storage for delta q */
74         dq = (u8 *)ptrs[faila];
75         ptrs[faila] = (void *)raid6_empty_zero_page;
76         ptrs[disks-1] = dq;
77
78         raid6_call.gen_syndrome(disks, bytes, ptrs);
79
80         /* Restore pointer table */
81         ptrs[faila]   = dq;
82         ptrs[disks-1] = q;
83
84         /* Now, pick the proper data tables */
85         qmul  = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]]];
86
87         /* Now do it... */
88         while ( bytes-- ) {
89                 *p++ ^= *dq = qmul[*q ^ *dq];
90                 q++; dq++;
91         }
92 }
93
94
95 const struct raid6_recov_calls raid6_recov_intx1 = {
96         .data2 = raid6_2data_recov_intx1,
97         .datap = raid6_datap_recov_intx1,
98         .valid = NULL,
99         .name = "intx1",
100         .priority = 0,
101 };
102
103 #ifndef __KERNEL__
104 /* Testing only */
105
106 /* Recover two failed blocks. */
107 void raid6_dual_recov(int disks, size_t bytes, int faila, int failb, void **ptrs)
108 {
109         if ( faila > failb ) {
110                 int tmp = faila;
111                 faila = failb;
112                 failb = tmp;
113         }
114
115         if ( failb == disks-1 ) {
116                 if ( faila == disks-2 ) {
117                         /* P+Q failure.  Just rebuild the syndrome. */
118                         raid6_call.gen_syndrome(disks, bytes, ptrs);
119                 } else {
120                         /* data+Q failure.  Reconstruct data from P,
121                            then rebuild syndrome. */
122                         /* NOT IMPLEMENTED - equivalent to RAID-5 */
123                 }
124         } else {
125                 if ( failb == disks-2 ) {
126                         /* data+P failure. */
127                         raid6_datap_recov(disks, bytes, faila, ptrs);
128                 } else {
129                         /* data+data failure. */
130                         raid6_2data_recov(disks, bytes, faila, failb, ptrs);
131                 }
132         }
133 }
134
135 #endif