xref: /openbmc/linux/lib/raid6/recov.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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