xref: /openbmc/linux/lib/raid6/recov_s390xc.c (revision 498495dba268b20e8eadd7fe93c140c68b6cc9d2)
1*b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2f5b55fa1SMartin Schwidefsky /*
3f5b55fa1SMartin Schwidefsky  * RAID-6 data recovery in dual failure mode based on the XC instruction.
4f5b55fa1SMartin Schwidefsky  *
5f5b55fa1SMartin Schwidefsky  * Copyright IBM Corp. 2016
6f5b55fa1SMartin Schwidefsky  * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
7f5b55fa1SMartin Schwidefsky  */
8f5b55fa1SMartin Schwidefsky 
9f5b55fa1SMartin Schwidefsky #include <linux/export.h>
10f5b55fa1SMartin Schwidefsky #include <linux/raid/pq.h>
11f5b55fa1SMartin Schwidefsky 
xor_block(u8 * p1,u8 * p2)12f5b55fa1SMartin Schwidefsky static inline void xor_block(u8 *p1, u8 *p2)
13f5b55fa1SMartin Schwidefsky {
14f5b55fa1SMartin Schwidefsky 	typedef struct { u8 _[256]; } addrtype;
15f5b55fa1SMartin Schwidefsky 
16f5b55fa1SMartin Schwidefsky 	asm volatile(
17f5b55fa1SMartin Schwidefsky 		"	xc	0(256,%[p1]),0(%[p2])\n"
18f5b55fa1SMartin Schwidefsky 		: "+m" (*(addrtype *) p1) : "m" (*(addrtype *) p2),
19f5b55fa1SMartin Schwidefsky 		  [p1] "a" (p1), [p2] "a" (p2) : "cc");
20f5b55fa1SMartin Schwidefsky }
21f5b55fa1SMartin Schwidefsky 
22f5b55fa1SMartin Schwidefsky /* Recover two failed data blocks. */
raid6_2data_recov_s390xc(int disks,size_t bytes,int faila,int failb,void ** ptrs)23f5b55fa1SMartin Schwidefsky static void raid6_2data_recov_s390xc(int disks, size_t bytes, int faila,
24f5b55fa1SMartin Schwidefsky 		int failb, void **ptrs)
25f5b55fa1SMartin Schwidefsky {
26f5b55fa1SMartin Schwidefsky 	u8 *p, *q, *dp, *dq;
27f5b55fa1SMartin Schwidefsky 	const u8 *pbmul;	/* P multiplier table for B data */
28f5b55fa1SMartin Schwidefsky 	const u8 *qmul;		/* Q multiplier table (for both) */
29f5b55fa1SMartin Schwidefsky 	int i;
30f5b55fa1SMartin Schwidefsky 
31f5b55fa1SMartin Schwidefsky 	p = (u8 *)ptrs[disks-2];
32f5b55fa1SMartin Schwidefsky 	q = (u8 *)ptrs[disks-1];
33f5b55fa1SMartin Schwidefsky 
34f5b55fa1SMartin Schwidefsky 	/* Compute syndrome with zero for the missing data pages
35f5b55fa1SMartin Schwidefsky 	   Use the dead data pages as temporary storage for
36f5b55fa1SMartin Schwidefsky 	   delta p and delta q */
37f5b55fa1SMartin Schwidefsky 	dp = (u8 *)ptrs[faila];
38f5b55fa1SMartin Schwidefsky 	ptrs[faila] = (void *)raid6_empty_zero_page;
39f5b55fa1SMartin Schwidefsky 	ptrs[disks-2] = dp;
40f5b55fa1SMartin Schwidefsky 	dq = (u8 *)ptrs[failb];
41f5b55fa1SMartin Schwidefsky 	ptrs[failb] = (void *)raid6_empty_zero_page;
42f5b55fa1SMartin Schwidefsky 	ptrs[disks-1] = dq;
43f5b55fa1SMartin Schwidefsky 
44f5b55fa1SMartin Schwidefsky 	raid6_call.gen_syndrome(disks, bytes, ptrs);
45f5b55fa1SMartin Schwidefsky 
46f5b55fa1SMartin Schwidefsky 	/* Restore pointer table */
47f5b55fa1SMartin Schwidefsky 	ptrs[faila]   = dp;
48f5b55fa1SMartin Schwidefsky 	ptrs[failb]   = dq;
49f5b55fa1SMartin Schwidefsky 	ptrs[disks-2] = p;
50f5b55fa1SMartin Schwidefsky 	ptrs[disks-1] = q;
51f5b55fa1SMartin Schwidefsky 
52f5b55fa1SMartin Schwidefsky 	/* Now, pick the proper data tables */
53f5b55fa1SMartin Schwidefsky 	pbmul = raid6_gfmul[raid6_gfexi[failb-faila]];
54f5b55fa1SMartin Schwidefsky 	qmul  = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]^raid6_gfexp[failb]]];
55f5b55fa1SMartin Schwidefsky 
56f5b55fa1SMartin Schwidefsky 	/* Now do it... */
57f5b55fa1SMartin Schwidefsky 	while (bytes) {
58f5b55fa1SMartin Schwidefsky 		xor_block(dp, p);
59f5b55fa1SMartin Schwidefsky 		xor_block(dq, q);
60f5b55fa1SMartin Schwidefsky 		for (i = 0; i < 256; i++)
61f5b55fa1SMartin Schwidefsky 			dq[i] = pbmul[dp[i]] ^ qmul[dq[i]];
62f5b55fa1SMartin Schwidefsky 		xor_block(dp, dq);
63f5b55fa1SMartin Schwidefsky 		p += 256;
64f5b55fa1SMartin Schwidefsky 		q += 256;
65f5b55fa1SMartin Schwidefsky 		dp += 256;
66f5b55fa1SMartin Schwidefsky 		dq += 256;
67f5b55fa1SMartin Schwidefsky 		bytes -= 256;
68f5b55fa1SMartin Schwidefsky 	}
69f5b55fa1SMartin Schwidefsky }
70f5b55fa1SMartin Schwidefsky 
71f5b55fa1SMartin Schwidefsky /* Recover failure of one data block plus the P block */
raid6_datap_recov_s390xc(int disks,size_t bytes,int faila,void ** ptrs)72f5b55fa1SMartin Schwidefsky static void raid6_datap_recov_s390xc(int disks, size_t bytes, int faila,
73f5b55fa1SMartin Schwidefsky 		void **ptrs)
74f5b55fa1SMartin Schwidefsky {
75f5b55fa1SMartin Schwidefsky 	u8 *p, *q, *dq;
76f5b55fa1SMartin Schwidefsky 	const u8 *qmul;		/* Q multiplier table */
77f5b55fa1SMartin Schwidefsky 	int i;
78f5b55fa1SMartin Schwidefsky 
79f5b55fa1SMartin Schwidefsky 	p = (u8 *)ptrs[disks-2];
80f5b55fa1SMartin Schwidefsky 	q = (u8 *)ptrs[disks-1];
81f5b55fa1SMartin Schwidefsky 
82f5b55fa1SMartin Schwidefsky 	/* Compute syndrome with zero for the missing data page
83f5b55fa1SMartin Schwidefsky 	   Use the dead data page as temporary storage for delta q */
84f5b55fa1SMartin Schwidefsky 	dq = (u8 *)ptrs[faila];
85f5b55fa1SMartin Schwidefsky 	ptrs[faila] = (void *)raid6_empty_zero_page;
86f5b55fa1SMartin Schwidefsky 	ptrs[disks-1] = dq;
87f5b55fa1SMartin Schwidefsky 
88f5b55fa1SMartin Schwidefsky 	raid6_call.gen_syndrome(disks, bytes, ptrs);
89f5b55fa1SMartin Schwidefsky 
90f5b55fa1SMartin Schwidefsky 	/* Restore pointer table */
91f5b55fa1SMartin Schwidefsky 	ptrs[faila]   = dq;
92f5b55fa1SMartin Schwidefsky 	ptrs[disks-1] = q;
93f5b55fa1SMartin Schwidefsky 
94f5b55fa1SMartin Schwidefsky 	/* Now, pick the proper data tables */
95f5b55fa1SMartin Schwidefsky 	qmul  = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]]];
96f5b55fa1SMartin Schwidefsky 
97f5b55fa1SMartin Schwidefsky 	/* Now do it... */
98f5b55fa1SMartin Schwidefsky 	while (bytes) {
99f5b55fa1SMartin Schwidefsky 		xor_block(dq, q);
100f5b55fa1SMartin Schwidefsky 		for (i = 0; i < 256; i++)
101f5b55fa1SMartin Schwidefsky 			dq[i] = qmul[dq[i]];
102f5b55fa1SMartin Schwidefsky 		xor_block(p, dq);
103f5b55fa1SMartin Schwidefsky 		p += 256;
104f5b55fa1SMartin Schwidefsky 		q += 256;
105f5b55fa1SMartin Schwidefsky 		dq += 256;
106f5b55fa1SMartin Schwidefsky 		bytes -= 256;
107f5b55fa1SMartin Schwidefsky 	}
108f5b55fa1SMartin Schwidefsky }
109f5b55fa1SMartin Schwidefsky 
110f5b55fa1SMartin Schwidefsky 
111f5b55fa1SMartin Schwidefsky const struct raid6_recov_calls raid6_recov_s390xc = {
112f5b55fa1SMartin Schwidefsky 	.data2 = raid6_2data_recov_s390xc,
113f5b55fa1SMartin Schwidefsky 	.datap = raid6_datap_recov_s390xc,
114f5b55fa1SMartin Schwidefsky 	.valid = NULL,
115f5b55fa1SMartin Schwidefsky 	.name = "s390xc",
116f5b55fa1SMartin Schwidefsky 	.priority = 1,
117f5b55fa1SMartin Schwidefsky };
118