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