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 }; 117