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