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