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