18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* -*- linux-c -*- ------------------------------------------------------- * 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright 2002 H. Peter Anvin - All Rights Reserved 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * ----------------------------------------------------------------------- */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci/* 98c2ecf20Sopenharmony_ci * raid6/recov.c 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * RAID-6 data recovery in dual failure mode. In single failure mode, 128c2ecf20Sopenharmony_ci * use the RAID-5 algorithm (or, in the case of Q failure, just reconstruct 138c2ecf20Sopenharmony_ci * the syndrome.) 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/export.h> 178c2ecf20Sopenharmony_ci#include <linux/raid/pq.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* Recover two failed data blocks. */ 208c2ecf20Sopenharmony_cistatic void raid6_2data_recov_intx1(int disks, size_t bytes, int faila, 218c2ecf20Sopenharmony_ci int failb, void **ptrs) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci u8 *p, *q, *dp, *dq; 248c2ecf20Sopenharmony_ci u8 px, qx, db; 258c2ecf20Sopenharmony_ci const u8 *pbmul; /* P multiplier table for B data */ 268c2ecf20Sopenharmony_ci const u8 *qmul; /* Q multiplier table (for both) */ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci p = (u8 *)ptrs[disks-2]; 298c2ecf20Sopenharmony_ci q = (u8 *)ptrs[disks-1]; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci /* Compute syndrome with zero for the missing data pages 328c2ecf20Sopenharmony_ci Use the dead data pages as temporary storage for 338c2ecf20Sopenharmony_ci delta p and delta q */ 348c2ecf20Sopenharmony_ci dp = (u8 *)ptrs[faila]; 358c2ecf20Sopenharmony_ci ptrs[faila] = (void *)raid6_empty_zero_page; 368c2ecf20Sopenharmony_ci ptrs[disks-2] = dp; 378c2ecf20Sopenharmony_ci dq = (u8 *)ptrs[failb]; 388c2ecf20Sopenharmony_ci ptrs[failb] = (void *)raid6_empty_zero_page; 398c2ecf20Sopenharmony_ci ptrs[disks-1] = dq; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci raid6_call.gen_syndrome(disks, bytes, ptrs); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci /* Restore pointer table */ 448c2ecf20Sopenharmony_ci ptrs[faila] = dp; 458c2ecf20Sopenharmony_ci ptrs[failb] = dq; 468c2ecf20Sopenharmony_ci ptrs[disks-2] = p; 478c2ecf20Sopenharmony_ci ptrs[disks-1] = q; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci /* Now, pick the proper data tables */ 508c2ecf20Sopenharmony_ci pbmul = raid6_gfmul[raid6_gfexi[failb-faila]]; 518c2ecf20Sopenharmony_ci qmul = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]^raid6_gfexp[failb]]]; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci /* Now do it... */ 548c2ecf20Sopenharmony_ci while ( bytes-- ) { 558c2ecf20Sopenharmony_ci px = *p ^ *dp; 568c2ecf20Sopenharmony_ci qx = qmul[*q ^ *dq]; 578c2ecf20Sopenharmony_ci *dq++ = db = pbmul[px] ^ qx; /* Reconstructed B */ 588c2ecf20Sopenharmony_ci *dp++ = db ^ px; /* Reconstructed A */ 598c2ecf20Sopenharmony_ci p++; q++; 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/* Recover failure of one data block plus the P block */ 648c2ecf20Sopenharmony_cistatic void raid6_datap_recov_intx1(int disks, size_t bytes, int faila, 658c2ecf20Sopenharmony_ci void **ptrs) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci u8 *p, *q, *dq; 688c2ecf20Sopenharmony_ci const u8 *qmul; /* Q multiplier table */ 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci p = (u8 *)ptrs[disks-2]; 718c2ecf20Sopenharmony_ci q = (u8 *)ptrs[disks-1]; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci /* Compute syndrome with zero for the missing data page 748c2ecf20Sopenharmony_ci Use the dead data page as temporary storage for delta q */ 758c2ecf20Sopenharmony_ci dq = (u8 *)ptrs[faila]; 768c2ecf20Sopenharmony_ci ptrs[faila] = (void *)raid6_empty_zero_page; 778c2ecf20Sopenharmony_ci ptrs[disks-1] = dq; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci raid6_call.gen_syndrome(disks, bytes, ptrs); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci /* Restore pointer table */ 828c2ecf20Sopenharmony_ci ptrs[faila] = dq; 838c2ecf20Sopenharmony_ci ptrs[disks-1] = q; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci /* Now, pick the proper data tables */ 868c2ecf20Sopenharmony_ci qmul = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]]]; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* Now do it... */ 898c2ecf20Sopenharmony_ci while ( bytes-- ) { 908c2ecf20Sopenharmony_ci *p++ ^= *dq = qmul[*q ^ *dq]; 918c2ecf20Sopenharmony_ci q++; dq++; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ciconst struct raid6_recov_calls raid6_recov_intx1 = { 978c2ecf20Sopenharmony_ci .data2 = raid6_2data_recov_intx1, 988c2ecf20Sopenharmony_ci .datap = raid6_datap_recov_intx1, 998c2ecf20Sopenharmony_ci .valid = NULL, 1008c2ecf20Sopenharmony_ci .name = "intx1", 1018c2ecf20Sopenharmony_ci .priority = 0, 1028c2ecf20Sopenharmony_ci}; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci#ifndef __KERNEL__ 1058c2ecf20Sopenharmony_ci/* Testing only */ 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/* Recover two failed blocks. */ 1088c2ecf20Sopenharmony_civoid raid6_dual_recov(int disks, size_t bytes, int faila, int failb, void **ptrs) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci if ( faila > failb ) { 1118c2ecf20Sopenharmony_ci int tmp = faila; 1128c2ecf20Sopenharmony_ci faila = failb; 1138c2ecf20Sopenharmony_ci failb = tmp; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci if ( failb == disks-1 ) { 1178c2ecf20Sopenharmony_ci if ( faila == disks-2 ) { 1188c2ecf20Sopenharmony_ci /* P+Q failure. Just rebuild the syndrome. */ 1198c2ecf20Sopenharmony_ci raid6_call.gen_syndrome(disks, bytes, ptrs); 1208c2ecf20Sopenharmony_ci } else { 1218c2ecf20Sopenharmony_ci /* data+Q failure. Reconstruct data from P, 1228c2ecf20Sopenharmony_ci then rebuild syndrome. */ 1238c2ecf20Sopenharmony_ci /* NOT IMPLEMENTED - equivalent to RAID-5 */ 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci } else { 1268c2ecf20Sopenharmony_ci if ( failb == disks-2 ) { 1278c2ecf20Sopenharmony_ci /* data+P failure. */ 1288c2ecf20Sopenharmony_ci raid6_datap_recov(disks, bytes, faila, ptrs); 1298c2ecf20Sopenharmony_ci } else { 1308c2ecf20Sopenharmony_ci /* data+data failure. */ 1318c2ecf20Sopenharmony_ci raid6_2data_recov(disks, bytes, faila, failb, ptrs); 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci#endif 137