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