^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /* -*- linux-c -*- ------------------------------------------------------- *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright 2002 H. Peter Anvin - All Rights Reserved
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * ----------------------------------------------------------------------- */
^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) * raid6/recov.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * RAID-6 data recovery in dual failure mode. In single failure mode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * use the RAID-5 algorithm (or, in the case of Q failure, just reconstruct
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * the syndrome.)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/raid/pq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) /* Recover two failed data blocks. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) static void raid6_2data_recov_intx1(int disks, size_t bytes, int faila,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) int failb, void **ptrs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) u8 *p, *q, *dp, *dq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) u8 px, qx, db;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) const u8 *pbmul; /* P multiplier table for B data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) const u8 *qmul; /* Q multiplier table (for both) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) p = (u8 *)ptrs[disks-2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) q = (u8 *)ptrs[disks-1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) /* Compute syndrome with zero for the missing data pages
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) Use the dead data pages as temporary storage for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) delta p and delta q */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) dp = (u8 *)ptrs[faila];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) ptrs[faila] = (void *)raid6_empty_zero_page;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) ptrs[disks-2] = dp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) dq = (u8 *)ptrs[failb];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) ptrs[failb] = (void *)raid6_empty_zero_page;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) ptrs[disks-1] = dq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) raid6_call.gen_syndrome(disks, bytes, ptrs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) /* Restore pointer table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) ptrs[faila] = dp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) ptrs[failb] = dq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) ptrs[disks-2] = p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) ptrs[disks-1] = q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) /* Now, pick the proper data tables */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) pbmul = raid6_gfmul[raid6_gfexi[failb-faila]];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) qmul = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]^raid6_gfexp[failb]]];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) /* Now do it... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) while ( bytes-- ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) px = *p ^ *dp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) qx = qmul[*q ^ *dq];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) *dq++ = db = pbmul[px] ^ qx; /* Reconstructed B */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) *dp++ = db ^ px; /* Reconstructed A */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) p++; q++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) /* Recover failure of one data block plus the P block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static void raid6_datap_recov_intx1(int disks, size_t bytes, int faila,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) void **ptrs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) u8 *p, *q, *dq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) const u8 *qmul; /* Q multiplier table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) p = (u8 *)ptrs[disks-2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) q = (u8 *)ptrs[disks-1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) /* Compute syndrome with zero for the missing data page
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) Use the dead data page as temporary storage for delta q */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) dq = (u8 *)ptrs[faila];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) ptrs[faila] = (void *)raid6_empty_zero_page;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) ptrs[disks-1] = dq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) raid6_call.gen_syndrome(disks, bytes, ptrs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) /* Restore pointer table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) ptrs[faila] = dq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) ptrs[disks-1] = q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) /* Now, pick the proper data tables */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) qmul = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]]];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) /* Now do it... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) while ( bytes-- ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) *p++ ^= *dq = qmul[*q ^ *dq];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) q++; dq++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) const struct raid6_recov_calls raid6_recov_intx1 = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) .data2 = raid6_2data_recov_intx1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) .datap = raid6_datap_recov_intx1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) .valid = NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) .name = "intx1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) .priority = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) #ifndef __KERNEL__
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) /* Testing only */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) /* Recover two failed blocks. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) void raid6_dual_recov(int disks, size_t bytes, int faila, int failb, void **ptrs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if ( faila > failb ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) int tmp = faila;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) faila = failb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) failb = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) if ( failb == disks-1 ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) if ( faila == disks-2 ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) /* P+Q failure. Just rebuild the syndrome. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) raid6_call.gen_syndrome(disks, bytes, ptrs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) /* data+Q failure. Reconstruct data from P,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) then rebuild syndrome. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) /* NOT IMPLEMENTED - equivalent to RAID-5 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if ( failb == disks-2 ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) /* data+P failure. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) raid6_datap_recov(disks, bytes, faila, ptrs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) /* data+data failure. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) raid6_2data_recov(disks, bytes, faila, failb, ptrs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) #endif