13626738bSChristoph Hellwig // SPDX-License-Identifier: GPL-2.0 23626738bSChristoph Hellwig /* 33626738bSChristoph Hellwig * RAID-6 data recovery in dual failure mode based on the XC instruction. 43626738bSChristoph Hellwig * 53626738bSChristoph Hellwig * Copyright IBM Corp. 2016 63626738bSChristoph Hellwig * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> 73626738bSChristoph Hellwig */ 83626738bSChristoph Hellwig 9*769d603fSChristoph Hellwig #include <linux/mm.h> 103626738bSChristoph Hellwig #include <linux/raid/pq.h> 11*769d603fSChristoph Hellwig #include "algos.h" 123626738bSChristoph Hellwig 133626738bSChristoph Hellwig static inline void xor_block(u8 *p1, u8 *p2) 143626738bSChristoph Hellwig { 153626738bSChristoph Hellwig typedef struct { u8 _[256]; } addrtype; 163626738bSChristoph Hellwig 173626738bSChristoph Hellwig asm volatile( 183626738bSChristoph Hellwig " xc 0(256,%[p1]),0(%[p2])\n" 193626738bSChristoph Hellwig : "+m" (*(addrtype *) p1) : "m" (*(addrtype *) p2), 203626738bSChristoph Hellwig [p1] "a" (p1), [p2] "a" (p2) : "cc"); 213626738bSChristoph Hellwig } 223626738bSChristoph Hellwig 233626738bSChristoph Hellwig /* Recover two failed data blocks. */ 243626738bSChristoph Hellwig static void raid6_2data_recov_s390xc(int disks, size_t bytes, int faila, 253626738bSChristoph Hellwig int failb, void **ptrs) 263626738bSChristoph Hellwig { 273626738bSChristoph Hellwig u8 *p, *q, *dp, *dq; 283626738bSChristoph Hellwig const u8 *pbmul; /* P multiplier table for B data */ 293626738bSChristoph Hellwig const u8 *qmul; /* Q multiplier table (for both) */ 303626738bSChristoph Hellwig int i; 313626738bSChristoph Hellwig 323626738bSChristoph Hellwig p = (u8 *)ptrs[disks-2]; 333626738bSChristoph Hellwig q = (u8 *)ptrs[disks-1]; 343626738bSChristoph Hellwig 353626738bSChristoph Hellwig /* Compute syndrome with zero for the missing data pages 363626738bSChristoph Hellwig Use the dead data pages as temporary storage for 373626738bSChristoph Hellwig delta p and delta q */ 383626738bSChristoph Hellwig dp = (u8 *)ptrs[faila]; 39885d3142SChristoph Hellwig ptrs[faila] = page_address(ZERO_PAGE(0)); 403626738bSChristoph Hellwig ptrs[disks-2] = dp; 413626738bSChristoph Hellwig dq = (u8 *)ptrs[failb]; 42885d3142SChristoph Hellwig ptrs[failb] = page_address(ZERO_PAGE(0)); 433626738bSChristoph Hellwig ptrs[disks-1] = dq; 443626738bSChristoph Hellwig 4535472bc6SChristoph Hellwig raid6_gen_syndrome(disks, bytes, ptrs); 463626738bSChristoph Hellwig 473626738bSChristoph Hellwig /* Restore pointer table */ 483626738bSChristoph Hellwig ptrs[faila] = dp; 493626738bSChristoph Hellwig ptrs[failb] = dq; 503626738bSChristoph Hellwig ptrs[disks-2] = p; 513626738bSChristoph Hellwig ptrs[disks-1] = q; 523626738bSChristoph Hellwig 533626738bSChristoph Hellwig /* Now, pick the proper data tables */ 543626738bSChristoph Hellwig pbmul = raid6_gfmul[raid6_gfexi[failb-faila]]; 553626738bSChristoph Hellwig qmul = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]^raid6_gfexp[failb]]]; 563626738bSChristoph Hellwig 573626738bSChristoph Hellwig /* Now do it... */ 583626738bSChristoph Hellwig while (bytes) { 593626738bSChristoph Hellwig xor_block(dp, p); 603626738bSChristoph Hellwig xor_block(dq, q); 613626738bSChristoph Hellwig for (i = 0; i < 256; i++) 623626738bSChristoph Hellwig dq[i] = pbmul[dp[i]] ^ qmul[dq[i]]; 633626738bSChristoph Hellwig xor_block(dp, dq); 643626738bSChristoph Hellwig p += 256; 653626738bSChristoph Hellwig q += 256; 663626738bSChristoph Hellwig dp += 256; 673626738bSChristoph Hellwig dq += 256; 683626738bSChristoph Hellwig bytes -= 256; 693626738bSChristoph Hellwig } 703626738bSChristoph Hellwig } 713626738bSChristoph Hellwig 723626738bSChristoph Hellwig /* Recover failure of one data block plus the P block */ 733626738bSChristoph Hellwig static void raid6_datap_recov_s390xc(int disks, size_t bytes, int faila, 743626738bSChristoph Hellwig void **ptrs) 753626738bSChristoph Hellwig { 763626738bSChristoph Hellwig u8 *p, *q, *dq; 773626738bSChristoph Hellwig const u8 *qmul; /* Q multiplier table */ 783626738bSChristoph Hellwig int i; 793626738bSChristoph Hellwig 803626738bSChristoph Hellwig p = (u8 *)ptrs[disks-2]; 813626738bSChristoph Hellwig q = (u8 *)ptrs[disks-1]; 823626738bSChristoph Hellwig 833626738bSChristoph Hellwig /* Compute syndrome with zero for the missing data page 843626738bSChristoph Hellwig Use the dead data page as temporary storage for delta q */ 853626738bSChristoph Hellwig dq = (u8 *)ptrs[faila]; 86885d3142SChristoph Hellwig ptrs[faila] = page_address(ZERO_PAGE(0)); 873626738bSChristoph Hellwig ptrs[disks-1] = dq; 883626738bSChristoph Hellwig 8935472bc6SChristoph Hellwig raid6_gen_syndrome(disks, bytes, ptrs); 903626738bSChristoph Hellwig 913626738bSChristoph Hellwig /* Restore pointer table */ 923626738bSChristoph Hellwig ptrs[faila] = dq; 933626738bSChristoph Hellwig ptrs[disks-1] = q; 943626738bSChristoph Hellwig 953626738bSChristoph Hellwig /* Now, pick the proper data tables */ 963626738bSChristoph Hellwig qmul = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]]]; 973626738bSChristoph Hellwig 983626738bSChristoph Hellwig /* Now do it... */ 993626738bSChristoph Hellwig while (bytes) { 1003626738bSChristoph Hellwig xor_block(dq, q); 1013626738bSChristoph Hellwig for (i = 0; i < 256; i++) 1023626738bSChristoph Hellwig dq[i] = qmul[dq[i]]; 1033626738bSChristoph Hellwig xor_block(p, dq); 1043626738bSChristoph Hellwig p += 256; 1053626738bSChristoph Hellwig q += 256; 1063626738bSChristoph Hellwig dq += 256; 1073626738bSChristoph Hellwig bytes -= 256; 1083626738bSChristoph Hellwig } 1093626738bSChristoph Hellwig } 1103626738bSChristoph Hellwig 1113626738bSChristoph Hellwig 1123626738bSChristoph Hellwig const struct raid6_recov_calls raid6_recov_s390xc = { 1133626738bSChristoph Hellwig .data2 = raid6_2data_recov_s390xc, 1143626738bSChristoph Hellwig .datap = raid6_datap_recov_s390xc, 1153626738bSChristoph Hellwig .name = "s390xc", 1163626738bSChristoph Hellwig }; 117