/* * Copyright (C) 2011 Andrea Mazzoleni * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /* * The RAID5/RAID6 support was originally derived by the libraid6 library * by H. Peter Anvin released with license "GPL2 or any later version" * used by the Linux Kernel 2.6.38. * * This support was later completely rewritten (many times), but the * H. Peter Anvin's Copyright may still apply. * * The RAIDTP/RAIDQP support is original work implemented from scratch. * For some notes about the method used, see the "recovering" section * in this file. */ #include "portable.h" #include "raid.h" #include "cpu.h" #include "tables.h" /****************************************************************************/ /* specialized parity generation */ /** * Dereference as uint32_t */ #define v_32(p) (*(uint32_t*)&(p)) /** * Dereference as uint64_t */ #define v_64(p) (*(uint64_t*)&(p)) /* * RAID5 32bit C implementation */ void raid5_int32(unsigned char** vbuf, unsigned data, unsigned size) { unsigned char* p; int d, l; unsigned o; uint32_t p0; uint32_t p1; l = data - 1; p = vbuf[data]; for(o=0;o=0;--d) { p0 ^= v_32(vbuf[d][o]); p1 ^= v_32(vbuf[d][o+4]); } v_32(p[o]) = p0; v_32(p[o+4]) = p1; } } /* * RAID5 64bit C implementation */ void raid5_int64(unsigned char** vbuf, unsigned data, unsigned size) { unsigned char* p; int d, l; unsigned o; uint64_t p0; uint64_t p1; l = data - 1; p = vbuf[data]; for(o=0;o=0;--d) { p0 ^= v_64(vbuf[d][o]); p1 ^= v_64(vbuf[d][o+8]); } v_64(p[o]) = p0; v_64(p[o+8]) = p1; } } #if defined(__i386__) || defined(__x86_64__) /* * RAID5 MMX implementation */ void raid5_mmx(unsigned char** vbuf, unsigned data, unsigned size) { unsigned char* p; int d, l; unsigned o; l = data - 1; p = vbuf[data]; for(o=0;o=0;--d) { asm volatile("movq %0,%%mm4" : : "m" (vbuf[d][o])); asm volatile("movq %0,%%mm5" : : "m" (vbuf[d][o+8])); asm volatile("movq %0,%%mm6" : : "m" (vbuf[d][o+16])); asm volatile("movq %0,%%mm7" : : "m" (vbuf[d][o+24])); asm volatile("pxor %mm4,%mm0"); asm volatile("pxor %mm5,%mm1"); asm volatile("pxor %mm6,%mm2"); asm volatile("pxor %mm7,%mm3"); } asm volatile("movq %%mm0,%0" : "=m" (p[o])); asm volatile("movq %%mm1,%0" : "=m" (p[o+8])); asm volatile("movq %%mm2,%0" : "=m" (p[o+16])); asm volatile("movq %%mm3,%0" : "=m" (p[o+24])); } asm volatile("emms" : : : "memory"); } /* * RAID5 SSE2 implementation */ void raid5_sse2(unsigned char** vbuf, unsigned data, unsigned size) { unsigned char* p; int d, l; unsigned o; l = data - 1; p = vbuf[data]; for(o=0;o=0;--d) { asm volatile("movdqa %0,%%xmm4" : : "m" (vbuf[d][o])); asm volatile("movdqa %0,%%xmm5" : : "m" (vbuf[d][o+16])); asm volatile("movdqa %0,%%xmm6" : : "m" (vbuf[d][o+32])); asm volatile("movdqa %0,%%xmm7" : : "m" (vbuf[d][o+48])); asm volatile("pxor %xmm4,%xmm0"); asm volatile("pxor %xmm5,%xmm1"); asm volatile("pxor %xmm6,%xmm2"); asm volatile("pxor %xmm7,%xmm3"); } asm volatile("movntdq %%xmm0,%0" : "=m" (p[o])); asm volatile("movntdq %%xmm1,%0" : "=m" (p[o+16])); asm volatile("movntdq %%xmm2,%0" : "=m" (p[o+32])); asm volatile("movntdq %%xmm3,%0" : "=m" (p[o+48])); } asm volatile("sfence" : : : "memory"); } #endif #if defined(__x86_64__) /* * RAID5 SSE2 implementation * Note that it uses 16 registers, meaning that x64 is required. */ void raid5_sse2ext(unsigned char** vbuf, unsigned data, unsigned size) { unsigned char* p; int d, l; unsigned o; l = data - 1; p = vbuf[data]; for(o=0;o=0;--d) { asm volatile("movdqa %0,%%xmm8" : : "m" (vbuf[d][o])); asm volatile("movdqa %0,%%xmm9" : : "m" (vbuf[d][o+16])); asm volatile("movdqa %0,%%xmm10" : : "m" (vbuf[d][o+32])); asm volatile("movdqa %0,%%xmm11" : : "m" (vbuf[d][o+48])); asm volatile("movdqa %0,%%xmm12" : : "m" (vbuf[d][o+64])); asm volatile("movdqa %0,%%xmm13" : : "m" (vbuf[d][o+80])); asm volatile("movdqa %0,%%xmm14" : : "m" (vbuf[d][o+96])); asm volatile("movdqa %0,%%xmm15" : : "m" (vbuf[d][o+112])); asm volatile("pxor %xmm8,%xmm0"); asm volatile("pxor %xmm9,%xmm1"); asm volatile("pxor %xmm10,%xmm2"); asm volatile("pxor %xmm11,%xmm3"); asm volatile("pxor %xmm12,%xmm4"); asm volatile("pxor %xmm13,%xmm5"); asm volatile("pxor %xmm14,%xmm6"); asm volatile("pxor %xmm15,%xmm7"); } asm volatile("movntdq %%xmm0,%0" : "=m" (p[o])); asm volatile("movntdq %%xmm1,%0" : "=m" (p[o+16])); asm volatile("movntdq %%xmm2,%0" : "=m" (p[o+32])); asm volatile("movntdq %%xmm3,%0" : "=m" (p[o+48])); asm volatile("movntdq %%xmm4,%0" : "=m" (p[o+64])); asm volatile("movntdq %%xmm5,%0" : "=m" (p[o+80])); asm volatile("movntdq %%xmm6,%0" : "=m" (p[o+96])); asm volatile("movntdq %%xmm7,%0" : "=m" (p[o+112])); } asm volatile("sfence" : : : "memory"); } #endif /** * Multiply each byte of a uint32 by 2 in the GF(2^8). */ __attribute__((always_inline)) static inline uint32_t x2_32(uint32_t v) { uint32_t mask = v & 0x80808080U; mask = (mask << 1) - (mask >> 7); v = (v << 1) & 0xfefefefeU; v ^= mask & 0x1d1d1d1dU; return v; } /** * Multiply each byte of a uint64 by 2 in the GF(2^8). */ __attribute__((always_inline)) static inline uint64_t x2_64(uint64_t v) { uint64_t mask = v & 0x8080808080808080ULL; mask = (mask << 1) - (mask >> 7); v = (v << 1) & 0xfefefefefefefefeULL; v ^= mask & 0x1d1d1d1d1d1d1d1dULL; return v; } /* * RAID6 32bit C implementation */ void raid6_int32(unsigned char** vbuf, unsigned data, unsigned size) { unsigned char* p; unsigned char* q; int d, l; unsigned o; uint32_t d0, q0, p0; uint32_t d1, q1, p1; l = data - 1; p = vbuf[data]; q = vbuf[data+1]; for(o=0;o=0;--d) { d0 = v_32(vbuf[d][o]); d1 = v_32(vbuf[d][o+4]); p0 ^= d0; p1 ^= d1; q0 = x2_32(q0); q1 = x2_32(q1); q0 ^= d0; q1 ^= d1; } v_32(p[o]) = p0; v_32(p[o+4]) = p1; v_32(q[o]) = q0; v_32(q[o+4]) = q1; } } /* * RAID6 64bit C implementation */ void raid6_int64(unsigned char** vbuf, unsigned data, unsigned size) { unsigned char* p; unsigned char* q; int d, l; unsigned o; uint64_t d0, q0, p0; uint64_t d1, q1, p1; l = data - 1; p = vbuf[data]; q = vbuf[data+1]; for(o=0;o=0;--d) { d0 = v_64(vbuf[d][o]); d1 = v_64(vbuf[d][o+8]); p0 ^= d0; p1 ^= d1; q0 = x2_64(q0); q1 = x2_64(q1); q0 ^= d0; q1 ^= d1; } v_64(p[o]) = p0; v_64(p[o+8]) = p1; v_64(q[o]) = q0; v_64(q[o+8]) = q1; } } #if defined(__i386__) || defined(__x86_64__) static const struct raid_8_const { unsigned char poly[8]; } raid_8_const __attribute__((aligned(8))) = { GFPOLY8 }; /* * RAID6 MMX implementation */ void raid6_mmx(unsigned char** vbuf, unsigned data, unsigned size) { unsigned char* p; unsigned char* q; int d, l; unsigned o; l = data - 1; p = vbuf[data]; q = vbuf[data+1]; asm volatile("movq %0,%%mm7" : : "m" (raid_8_const.poly[0])); for(o=0;o=0;--d) { asm volatile("pxor %mm4,%mm4"); asm volatile("pxor %mm5,%mm5"); asm volatile("pcmpgtb %mm2,%mm4"); asm volatile("pcmpgtb %mm3,%mm5"); asm volatile("paddb %mm2,%mm2"); asm volatile("paddb %mm3,%mm3"); asm volatile("pand %mm7,%mm4"); asm volatile("pand %mm7,%mm5"); asm volatile("pxor %mm4,%mm2"); asm volatile("pxor %mm5,%mm3"); asm volatile("movq %0,%%mm4" : : "m" (vbuf[d][o])); asm volatile("movq %0,%%mm5" : : "m" (vbuf[d][o+8])); asm volatile("pxor %mm4,%mm0"); asm volatile("pxor %mm5,%mm1"); asm volatile("pxor %mm4,%mm2"); asm volatile("pxor %mm5,%mm3"); } asm volatile("movq %%mm0,%0" : "=m" (p[o])); asm volatile("movq %%mm1,%0" : "=m" (p[o+8])); asm volatile("movq %%mm2,%0" : "=m" (q[o])); asm volatile("movq %%mm3,%0" : "=m" (q[o+8])); } asm volatile("emms" : : : "memory"); } static const struct raid_16_const { unsigned char poly[16]; unsigned char low_nibble[16]; unsigned char x8l[16]; unsigned char x8h[16]; unsigned char x4l[16]; unsigned char x4h[16]; } raid_16_const __attribute__((aligned(16))) = { GFPOLY16, GFMASK16, GFX8L, GFX8H, GFX4L, GFX4H, }; /* * RAID6 SSE2 implementation */ void raid6_sse2(unsigned char** vbuf, unsigned data, unsigned size) { unsigned char* p; unsigned char* q; int d, l; unsigned o; l = data - 1; p = vbuf[data]; q = vbuf[data+1]; asm volatile("movdqa %0,%%xmm7" : : "m" (raid_16_const.poly[0])); for(o=0;o=0;--d) { asm volatile("pxor %xmm4,%xmm4"); asm volatile("pxor %xmm5,%xmm5"); asm volatile("pcmpgtb %xmm2,%xmm4"); asm volatile("pcmpgtb %xmm3,%xmm5"); asm volatile("paddb %xmm2,%xmm2"); asm volatile("paddb %xmm3,%xmm3"); asm volatile("pand %xmm7,%xmm4"); asm volatile("pand %xmm7,%xmm5"); asm volatile("pxor %xmm4,%xmm2"); asm volatile("pxor %xmm5,%xmm3"); asm volatile("movdqa %0,%%xmm4" : : "m" (vbuf[d][o])); asm volatile("movdqa %0,%%xmm5" : : "m" (vbuf[d][o+16])); asm volatile("pxor %xmm4,%xmm0"); asm volatile("pxor %xmm5,%xmm1"); asm volatile("pxor %xmm4,%xmm2"); asm volatile("pxor %xmm5,%xmm3"); } asm volatile("movntdq %%xmm0,%0" : "=m" (p[o])); asm volatile("movntdq %%xmm1,%0" : "=m" (p[o+16])); asm volatile("movntdq %%xmm2,%0" : "=m" (q[o])); asm volatile("movntdq %%xmm3,%0" : "=m" (q[o+16])); } asm volatile("sfence" : : : "memory"); } #endif #if defined(__x86_64__) /* * RAID6 SSE2 implementation * Note that it uses 16 registers, meaning that x64 is required. */ void raid6_sse2ext(unsigned char** vbuf, unsigned data, unsigned size) { unsigned char* p; unsigned char* q; int d, l; unsigned o; l = data - 1; p = vbuf[data]; q = vbuf[data+1]; asm volatile("movdqa %0,%%xmm15" : : "m" (raid_16_const.poly[0])); for(o=0;o=0;--d) { asm volatile("pxor %xmm8,%xmm8"); asm volatile("pxor %xmm9,%xmm9"); asm volatile("pxor %xmm10,%xmm10"); asm volatile("pxor %xmm11,%xmm11"); asm volatile("pcmpgtb %xmm4,%xmm8"); asm volatile("pcmpgtb %xmm5,%xmm9"); asm volatile("pcmpgtb %xmm6,%xmm10"); asm volatile("pcmpgtb %xmm7,%xmm11"); asm volatile("paddb %xmm4,%xmm4"); asm volatile("paddb %xmm5,%xmm5"); asm volatile("paddb %xmm6,%xmm6"); asm volatile("paddb %xmm7,%xmm7"); asm volatile("pand %xmm15,%xmm8"); asm volatile("pand %xmm15,%xmm9"); asm volatile("pand %xmm15,%xmm10"); asm volatile("pand %xmm15,%xmm11"); asm volatile("pxor %xmm8,%xmm4"); asm volatile("pxor %xmm9,%xmm5"); asm volatile("pxor %xmm10,%xmm6"); asm volatile("pxor %xmm11,%xmm7"); asm volatile("movdqa %0,%%xmm8" : : "m" (vbuf[d][o])); asm volatile("movdqa %0,%%xmm9" : : "m" (vbuf[d][o+16])); asm volatile("movdqa %0,%%xmm10" : : "m" (vbuf[d][o+32])); asm volatile("movdqa %0,%%xmm11" : : "m" (vbuf[d][o+48])); asm volatile("pxor %xmm8,%xmm0"); asm volatile("pxor %xmm9,%xmm1"); asm volatile("pxor %xmm10,%xmm2"); asm volatile("pxor %xmm11,%xmm3"); asm volatile("pxor %xmm8,%xmm4"); asm volatile("pxor %xmm9,%xmm5"); asm volatile("pxor %xmm10,%xmm6"); asm volatile("pxor %xmm11,%xmm7"); } asm volatile("movntdq %%xmm0,%0" : "=m" (p[o])); asm volatile("movntdq %%xmm1,%0" : "=m" (p[o+16])); asm volatile("movntdq %%xmm2,%0" : "=m" (p[o+32])); asm volatile("movntdq %%xmm3,%0" : "=m" (p[o+48])); asm volatile("movntdq %%xmm4,%0" : "=m" (q[o])); asm volatile("movntdq %%xmm5,%0" : "=m" (q[o+16])); asm volatile("movntdq %%xmm6,%0" : "=m" (q[o+32])); asm volatile("movntdq %%xmm7,%0" : "=m" (q[o+48])); } asm volatile("sfence" : : : "memory"); } #endif /* * RAIDTP 32bit C implementation */ void raidTP_int32(unsigned char** vbuf, unsigned data, unsigned size) { unsigned char* p; unsigned char* q; unsigned char* r; int d, l; unsigned o; uint32_t d0, r0, q0, p0; uint32_t d1, r1, q1, p1; l = data - 1; p = vbuf[data]; q = vbuf[data+1]; r = vbuf[data+2]; for(o=0;o=0;--d) { d0 = v_32(vbuf[d][o]); d1 = v_32(vbuf[d][o+4]); p0 ^= d0; p1 ^= d1; q0 = x2_32(q0); q1 = x2_32(q1); q0 ^= d0; q1 ^= d1; r0 = x2_32(r0); r1 = x2_32(r1); r0 = x2_32(r0); r1 = x2_32(r1); r0 ^= d0; r1 ^= d1; } v_32(p[o]) = p0; v_32(p[o+4]) = p1; v_32(q[o]) = q0; v_32(q[o+4]) = q1; v_32(r[o]) = r0; v_32(r[o+4]) = r1; } } /* * RAIDTP 64bit C implementation */ void raidTP_int64(unsigned char** vbuf, unsigned data, unsigned size) { unsigned char* p; unsigned char* q; unsigned char* r; int d, l; unsigned o; uint64_t d0, r0, q0, p0; uint64_t d1, r1, q1, p1; l = data - 1; p = vbuf[data]; q = vbuf[data+1]; r = vbuf[data+2]; for(o=0;o=0;--d) { d0 = v_64(vbuf[d][o]); d1 = v_64(vbuf[d][o+8]); p0 ^= d0; p1 ^= d1; q0 = x2_64(q0); q1 = x2_64(q1); q0 ^= d0; q1 ^= d1; r0 = x2_64(r0); r1 = x2_64(r1); r0 = x2_64(r0); r1 = x2_64(r1); r0 ^= d0; r1 ^= d1; } v_64(p[o]) = p0; v_64(p[o+8]) = p1; v_64(q[o]) = q0; v_64(q[o+8]) = q1; v_64(r[o]) = r0; v_64(r[o+8]) = r1; } } #if defined(__i386__) || defined(__x86_64__) /* * RAIDTP MMX implementation */ void raidTP_mmx(unsigned char** vbuf, unsigned data, unsigned size) { unsigned char* p; unsigned char* q; unsigned char* r; int d, l; unsigned o; l = data - 1; p = vbuf[data]; q = vbuf[data+1]; r = vbuf[data+2]; asm volatile("movq %0,%%mm7" : : "m" (raid_8_const.poly[0])); for(o=0;o=0;--d) { asm volatile("pxor %mm4,%mm4"); asm volatile("pxor %mm5,%mm5"); asm volatile("pxor %mm6,%mm6"); asm volatile("pcmpgtb %mm1,%mm4"); asm volatile("pcmpgtb %mm2,%mm5"); asm volatile("paddb %mm1,%mm1"); asm volatile("paddb %mm2,%mm2"); asm volatile("pand %mm7,%mm4"); asm volatile("pand %mm7,%mm5"); asm volatile("pxor %mm4,%mm1"); asm volatile("pxor %mm5,%mm2"); asm volatile("pcmpgtb %mm2,%mm6"); asm volatile("paddb %mm2,%mm2"); asm volatile("pand %mm7,%mm6"); asm volatile("pxor %mm6,%mm2"); asm volatile("movq %0,%%mm3" : : "m" (vbuf[d][o])); asm volatile("pxor %mm3,%mm0"); asm volatile("pxor %mm3,%mm1"); asm volatile("pxor %mm3,%mm2"); } asm volatile("movq %%mm0,%0" : "=m" (p[o])); asm volatile("movq %%mm1,%0" : "=m" (q[o])); asm volatile("movq %%mm2,%0" : "=m" (r[o])); } asm volatile("emms" : : : "memory"); } #endif #if defined(__i386__) || defined(__x86_64__) /* * RAIDTP SSE2 implementation */ void raidTP_sse2(unsigned char** vbuf, unsigned data, unsigned size) { unsigned char* p; unsigned char* q; unsigned char* r; int d, l; unsigned o; l = data - 1; p = vbuf[data]; q = vbuf[data+1]; r = vbuf[data+2]; asm volatile("movdqa %0,%%xmm7" : : "m" (raid_16_const.poly[0])); for(o=0;o=0;--d) { asm volatile("pxor %xmm4,%xmm4"); asm volatile("pxor %xmm5,%xmm5"); asm volatile("pxor %xmm6,%xmm6"); asm volatile("pcmpgtb %xmm1,%xmm4"); asm volatile("pcmpgtb %xmm2,%xmm5"); asm volatile("paddb %xmm1,%xmm1"); asm volatile("paddb %xmm2,%xmm2"); asm volatile("pand %xmm7,%xmm4"); asm volatile("pand %xmm7,%xmm5"); asm volatile("pxor %xmm4,%xmm1"); asm volatile("pxor %xmm5,%xmm2"); asm volatile("pcmpgtb %xmm2,%xmm6"); asm volatile("paddb %xmm2,%xmm2"); asm volatile("pand %xmm7,%xmm6"); asm volatile("pxor %xmm6,%xmm2"); asm volatile("movdqa %0,%%xmm3" : : "m" (vbuf[d][o])); asm volatile("pxor %xmm3,%xmm0"); asm volatile("pxor %xmm3,%xmm1"); asm volatile("pxor %xmm3,%xmm2"); } asm volatile("movntdq %%xmm0,%0" : "=m" (p[o])); asm volatile("movntdq %%xmm1,%0" : "=m" (q[o])); asm volatile("movntdq %%xmm2,%0" : "=m" (r[o])); } asm volatile("sfence" : : : "memory"); } #endif #if defined(__i386__) || defined(__x86_64__) /* * RAIDTP SSSE3 implementation */ void raidTP_ssse3(unsigned char** vbuf, unsigned data, unsigned size) { unsigned char* p; unsigned char* q; unsigned char* r; int d, l; unsigned o; l = data - 1; p = vbuf[data]; q = vbuf[data+1]; r = vbuf[data+2]; asm volatile("movdqa %0,%%xmm3" : : "m" (raid_16_const.low_nibble[0])); asm volatile("movdqa %0,%%xmm5" : : "m" (raid_16_const.x4l[0])); asm volatile("movdqa %0,%%xmm7" : : "m" (raid_16_const.poly[0])); for(o=0;o=0;--d) { asm volatile("pxor %xmm4,%xmm4"); asm volatile("pcmpgtb %xmm1,%xmm4"); asm volatile("paddb %xmm1,%xmm1"); asm volatile("pand %xmm7,%xmm4"); asm volatile("pxor %xmm4,%xmm1"); asm volatile("movdqa %0,%%xmm6" : : "m" (raid_16_const.x4h[0])); asm volatile("movdqa %xmm2,%xmm4"); asm volatile("psraw $4,%xmm2"); asm volatile("pand %xmm3,%xmm4"); asm volatile("pand %xmm3,%xmm2"); asm volatile("pshufb %xmm2,%xmm6"); asm volatile("movdqa %xmm5,%xmm2"); asm volatile("pshufb %xmm4,%xmm2"); asm volatile("pxor %xmm6,%xmm2"); asm volatile("movdqa %0,%%xmm4" : : "m" (vbuf[d][o])); asm volatile("pxor %xmm4,%xmm0"); asm volatile("pxor %xmm4,%xmm1"); asm volatile("pxor %xmm4,%xmm2"); } asm volatile("movntdq %%xmm0,%0" : "=m" (p[o])); asm volatile("movntdq %%xmm1,%0" : "=m" (q[o])); asm volatile("movntdq %%xmm2,%0" : "=m" (r[o])); } asm volatile("sfence" : : : "memory"); } #endif #if defined(__x86_64__) /* * RAIDTP SSE2 implementation * Note that it uses 16 registers, meaning that x64 is required. */ void raidTP_sse2ext(unsigned char** vbuf, unsigned data, unsigned size) { unsigned char* p; unsigned char* q; unsigned char* r; int d, l; unsigned o; l = data - 1; p = vbuf[data]; q = vbuf[data+1]; r = vbuf[data+2]; asm volatile("movdqa %0,%%xmm7" : : "m" (raid_16_const.poly[0])); for(o=0;o=0;--d) { asm volatile("pxor %xmm4,%xmm4"); asm volatile("pxor %xmm5,%xmm5"); asm volatile("pxor %xmm6,%xmm6"); asm volatile("pxor %xmm12,%xmm12"); asm volatile("pxor %xmm13,%xmm13"); asm volatile("pxor %xmm14,%xmm14"); asm volatile("pcmpgtb %xmm1,%xmm4"); asm volatile("pcmpgtb %xmm2,%xmm5"); asm volatile("pcmpgtb %xmm9,%xmm12"); asm volatile("pcmpgtb %xmm10,%xmm13"); asm volatile("paddb %xmm1,%xmm1"); asm volatile("paddb %xmm2,%xmm2"); asm volatile("paddb %xmm9,%xmm9"); asm volatile("paddb %xmm10,%xmm10"); asm volatile("pand %xmm7,%xmm4"); asm volatile("pand %xmm7,%xmm5"); asm volatile("pand %xmm7,%xmm12"); asm volatile("pand %xmm7,%xmm13"); asm volatile("pxor %xmm4,%xmm1"); asm volatile("pxor %xmm5,%xmm2"); asm volatile("pxor %xmm12,%xmm9"); asm volatile("pxor %xmm13,%xmm10"); asm volatile("pcmpgtb %xmm2,%xmm6"); asm volatile("pcmpgtb %xmm10,%xmm14"); asm volatile("paddb %xmm2,%xmm2"); asm volatile("paddb %xmm10,%xmm10"); asm volatile("pand %xmm7,%xmm6"); asm volatile("pand %xmm7,%xmm14"); asm volatile("pxor %xmm6,%xmm2"); asm volatile("pxor %xmm14,%xmm10"); asm volatile("movdqa %0,%%xmm3" : : "m" (vbuf[d][o])); asm volatile("movdqa %0,%%xmm11" : : "m" (vbuf[d][o+16])); asm volatile("pxor %xmm3,%xmm0"); asm volatile("pxor %xmm3,%xmm1"); asm volatile("pxor %xmm3,%xmm2"); asm volatile("pxor %xmm11,%xmm8"); asm volatile("pxor %xmm11,%xmm9"); asm volatile("pxor %xmm11,%xmm10"); } asm volatile("movntdq %%xmm0,%0" : "=m" (p[o])); asm volatile("movntdq %%xmm8,%0" : "=m" (p[o+16])); asm volatile("movntdq %%xmm1,%0" : "=m" (q[o])); asm volatile("movntdq %%xmm9,%0" : "=m" (q[o+16])); asm volatile("movntdq %%xmm2,%0" : "=m" (r[o])); asm volatile("movntdq %%xmm10,%0" : "=m" (r[o+16])); } asm volatile("sfence" : : : "memory"); } #endif #if defined(__x86_64__) /* * RAIDTP SSSE3 implementation * Note that it uses 16 registers, meaning that x64 is required. */ void raidTP_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size) { unsigned char* p; unsigned char* q; unsigned char* r; int d, l; unsigned o; l = data - 1; p = vbuf[data]; q = vbuf[data+1]; r = vbuf[data+2]; asm volatile("movdqa %0,%%xmm3" : : "m" (raid_16_const.low_nibble[0])); asm volatile("movdqa %0,%%xmm5" : : "m" (raid_16_const.x4l[0])); asm volatile("movdqa %0,%%xmm6" : : "m" (raid_16_const.x4h[0])); asm volatile("movdqa %0,%%xmm7" : : "m" (raid_16_const.poly[0])); for(o=0;o=0;--d) { asm volatile("pxor %xmm4,%xmm4"); asm volatile("pxor %xmm12,%xmm12"); asm volatile("pcmpgtb %xmm1,%xmm4"); asm volatile("pcmpgtb %xmm9,%xmm12"); asm volatile("paddb %xmm1,%xmm1"); asm volatile("paddb %xmm9,%xmm9"); asm volatile("pand %xmm7,%xmm4"); asm volatile("pand %xmm7,%xmm12"); asm volatile("pxor %xmm4,%xmm1"); asm volatile("pxor %xmm12,%xmm9"); asm volatile("movdqa %xmm6,%xmm13"); asm volatile("movdqa %xmm6,%xmm14"); asm volatile("movdqa %xmm2,%xmm4"); asm volatile("movdqa %xmm10,%xmm12"); asm volatile("psraw $4,%xmm2"); asm volatile("psraw $4,%xmm10"); asm volatile("pand %xmm3,%xmm4"); asm volatile("pand %xmm3,%xmm12"); asm volatile("pand %xmm3,%xmm2"); asm volatile("pand %xmm3,%xmm10"); asm volatile("pshufb %xmm2,%xmm13"); asm volatile("pshufb %xmm10,%xmm14"); asm volatile("movdqa %xmm5,%xmm2"); asm volatile("movdqa %xmm5,%xmm10"); asm volatile("pshufb %xmm4,%xmm2"); asm volatile("pshufb %xmm12,%xmm10"); asm volatile("pxor %xmm13,%xmm2"); asm volatile("pxor %xmm14,%xmm10"); asm volatile("movdqa %0,%%xmm4" : : "m" (vbuf[d][o])); asm volatile("movdqa %0,%%xmm12" : : "m" (vbuf[d][o+16])); asm volatile("pxor %xmm4,%xmm0"); asm volatile("pxor %xmm4,%xmm1"); asm volatile("pxor %xmm4,%xmm2"); asm volatile("pxor %xmm12,%xmm8"); asm volatile("pxor %xmm12,%xmm9"); asm volatile("pxor %xmm12,%xmm10"); } asm volatile("movntdq %%xmm0,%0" : "=m" (p[o])); asm volatile("movntdq %%xmm8,%0" : "=m" (p[o+16])); asm volatile("movntdq %%xmm1,%0" : "=m" (q[o])); asm volatile("movntdq %%xmm9,%0" : "=m" (q[o+16])); asm volatile("movntdq %%xmm2,%0" : "=m" (r[o])); asm volatile("movntdq %%xmm10,%0" : "=m" (r[o+16])); } asm volatile("sfence" : : : "memory"); } #endif /* * RAIDQP 32bit C implementation */ void raidQP_int32(unsigned char** vbuf, unsigned data, unsigned size) { unsigned char* p; unsigned char* q; unsigned char* r; unsigned char* s; int d, l; unsigned o; uint32_t d0, s0, r0, q0, p0; uint32_t d1, s1, r1, q1, p1; l = data - 1; p = vbuf[data]; q = vbuf[data+1]; r = vbuf[data+2]; s = vbuf[data+3]; for(o=0;o=0;--d) { d0 = v_32(vbuf[d][o]); d1 = v_32(vbuf[d][o+4]); p0 ^= d0; p1 ^= d1; q0 = x2_32(q0); q1 = x2_32(q1); q0 ^= d0; q1 ^= d1; r0 = x2_32(r0); r1 = x2_32(r1); r0 = x2_32(r0); r1 = x2_32(r1); r0 ^= d0; r1 ^= d1; s0 = x2_32(s0); s1 = x2_32(s1); s0 = x2_32(s0); s1 = x2_32(s1); s0 = x2_32(s0); s1 = x2_32(s1); s0 ^= d0; s1 ^= d1; } v_32(p[o]) = p0; v_32(p[o+4]) = p1; v_32(q[o]) = q0; v_32(q[o+4]) = q1; v_32(r[o]) = r0; v_32(r[o+4]) = r1; v_32(s[o]) = s0; v_32(s[o+4]) = s1; } } /* * RAIDQP 64bit C implementation */ void raidQP_int64(unsigned char** vbuf, unsigned data, unsigned size) { unsigned char* p; unsigned char* q; unsigned char* r; unsigned char* s; int d, l; unsigned o; uint64_t d0, s0, r0, q0, p0; uint64_t d1, s1, r1, q1, p1; l = data - 1; p = vbuf[data]; q = vbuf[data+1]; r = vbuf[data+2]; s = vbuf[data+3]; for(o=0;o=0;--d) { d0 = v_64(vbuf[d][o]); d1 = v_64(vbuf[d][o+8]); p0 ^= d0; p1 ^= d1; q0 = x2_64(q0); q1 = x2_64(q1); q0 ^= d0; q1 ^= d1; r0 = x2_64(r0); r1 = x2_64(r1); r0 = x2_64(r0); r1 = x2_64(r1); r0 ^= d0; r1 ^= d1; s0 = x2_64(s0); s1 = x2_64(s1); s0 = x2_64(s0); s1 = x2_64(s1); s0 = x2_64(s0); s1 = x2_64(s1); s0 ^= d0; s1 ^= d1; } v_64(p[o]) = p0; v_64(p[o+8]) = p1; v_64(q[o]) = q0; v_64(q[o+8]) = q1; v_64(r[o]) = r0; v_64(r[o+8]) = r1; v_64(s[o]) = s0; v_64(s[o+8]) = s1; } } #if defined(__i386__) || defined(__x86_64__) /* * RAIDQP MMX implementation */ void raidQP_mmx(unsigned char** vbuf, unsigned data, unsigned size) { unsigned char* p; unsigned char* q; unsigned char* r; unsigned char* s; int d, l; unsigned o; l = data - 1; p = vbuf[data]; q = vbuf[data+1]; r = vbuf[data+2]; s = vbuf[data+3]; asm volatile("movq %0,%%mm7" : : "m" (raid_8_const.poly[0])); for(o=0;o=0;--d) { asm volatile("pxor %mm4,%mm4"); asm volatile("pxor %mm5,%mm5"); asm volatile("pcmpgtb %mm1,%mm4"); asm volatile("pcmpgtb %mm3,%mm5"); asm volatile("paddb %mm1,%mm1"); asm volatile("paddb %mm3,%mm3"); asm volatile("pand %mm7,%mm4"); asm volatile("pand %mm7,%mm5"); asm volatile("pxor %mm4,%mm1"); asm volatile("pxor %mm5,%mm3"); asm volatile("pxor %mm4,%mm4"); asm volatile("pxor %mm5,%mm5"); asm volatile("pcmpgtb %mm2,%mm4"); asm volatile("pcmpgtb %mm3,%mm5"); asm volatile("paddb %mm2,%mm2"); asm volatile("paddb %mm3,%mm3"); asm volatile("pand %mm7,%mm4"); asm volatile("pand %mm7,%mm5"); asm volatile("pxor %mm4,%mm2"); asm volatile("pxor %mm5,%mm3"); asm volatile("pxor %mm4,%mm4"); asm volatile("pxor %mm5,%mm5"); asm volatile("pcmpgtb %mm2,%mm4"); asm volatile("pcmpgtb %mm3,%mm5"); asm volatile("paddb %mm2,%mm2"); asm volatile("paddb %mm3,%mm3"); asm volatile("pand %mm7,%mm4"); asm volatile("pand %mm7,%mm5"); asm volatile("pxor %mm4,%mm2"); asm volatile("pxor %mm5,%mm3"); asm volatile("movq %0,%%mm6" : : "m" (vbuf[d][o])); asm volatile("pxor %mm6,%mm0"); asm volatile("pxor %mm6,%mm1"); asm volatile("pxor %mm6,%mm2"); asm volatile("pxor %mm6,%mm3"); } asm volatile("movq %%mm0,%0" : "=m" (p[o])); asm volatile("movq %%mm1,%0" : "=m" (q[o])); asm volatile("movq %%mm2,%0" : "=m" (r[o])); asm volatile("movq %%mm3,%0" : "=m" (s[o])); } asm volatile("emms" : : : "memory"); } #endif #if defined(__i386__) || defined(__x86_64__) /* * RAIDQP SSE2 implementation */ void raidQP_sse2(unsigned char** vbuf, unsigned data, unsigned size) { unsigned char* p; unsigned char* q; unsigned char* r; unsigned char* s; int d, l; unsigned o; l = data - 1; p = vbuf[data]; q = vbuf[data+1]; r = vbuf[data+2]; s = vbuf[data+3]; asm volatile("movdqa %0,%%xmm7" : : "m" (raid_16_const.poly[0])); for(o=0;o=0;--d) { asm volatile("pxor %xmm4,%xmm4"); asm volatile("pxor %xmm5,%xmm5"); asm volatile("pcmpgtb %xmm1,%xmm4"); asm volatile("pcmpgtb %xmm3,%xmm5"); asm volatile("paddb %xmm1,%xmm1"); asm volatile("paddb %xmm3,%xmm3"); asm volatile("pand %xmm7,%xmm4"); asm volatile("pand %xmm7,%xmm5"); asm volatile("pxor %xmm4,%xmm1"); asm volatile("pxor %xmm5,%xmm3"); asm volatile("pxor %xmm4,%xmm4"); asm volatile("pxor %xmm5,%xmm5"); asm volatile("pcmpgtb %xmm2,%xmm4"); asm volatile("pcmpgtb %xmm3,%xmm5"); asm volatile("paddb %xmm2,%xmm2"); asm volatile("paddb %xmm3,%xmm3"); asm volatile("pand %xmm7,%xmm4"); asm volatile("pand %xmm7,%xmm5"); asm volatile("pxor %xmm4,%xmm2"); asm volatile("pxor %xmm5,%xmm3"); asm volatile("pxor %xmm4,%xmm4"); asm volatile("pxor %xmm5,%xmm5"); asm volatile("pcmpgtb %xmm2,%xmm4"); asm volatile("pcmpgtb %xmm3,%xmm5"); asm volatile("paddb %xmm2,%xmm2"); asm volatile("paddb %xmm3,%xmm3"); asm volatile("pand %xmm7,%xmm4"); asm volatile("pand %xmm7,%xmm5"); asm volatile("pxor %xmm4,%xmm2"); asm volatile("pxor %xmm5,%xmm3"); asm volatile("movdqa %0,%%xmm4" : : "m" (vbuf[d][o])); asm volatile("pxor %xmm4,%xmm0"); asm volatile("pxor %xmm4,%xmm1"); asm volatile("pxor %xmm4,%xmm2"); asm volatile("pxor %xmm4,%xmm3"); } asm volatile("movntdq %%xmm0,%0" : "=m" (p[o])); asm volatile("movntdq %%xmm1,%0" : "=m" (q[o])); asm volatile("movntdq %%xmm2,%0" : "=m" (r[o])); asm volatile("movntdq %%xmm3,%0" : "=m" (s[o])); } asm volatile("sfence" : : : "memory"); } #endif #if defined(__i386__) || defined(__x86_64__) /* * RAIDQP SSSE3 implementation */ void raidQP_ssse3(unsigned char** vbuf, unsigned data, unsigned size) { unsigned char* p; unsigned char* q; unsigned char* r; unsigned char* s; int d, l; unsigned o; l = data - 1; p = vbuf[data]; q = vbuf[data+1]; r = vbuf[data+2]; s = vbuf[data+3]; asm volatile("movdqa %0,%%xmm7" : : "m" (raid_16_const.poly[0])); for(o=0;o=0;--d) { asm volatile("pxor %xmm4,%xmm4"); asm volatile("pxor %xmm5,%xmm5"); asm volatile("pcmpgtb %xmm1,%xmm4"); asm volatile("pcmpgtb %xmm2,%xmm5"); asm volatile("paddb %xmm1,%xmm1"); asm volatile("paddb %xmm2,%xmm2"); asm volatile("pand %xmm7,%xmm4"); asm volatile("pand %xmm7,%xmm5"); asm volatile("pxor %xmm4,%xmm1"); asm volatile("pxor %xmm5,%xmm2"); asm volatile("pxor %xmm4,%xmm4"); asm volatile("pcmpgtb %xmm2,%xmm4"); asm volatile("paddb %xmm2,%xmm2"); asm volatile("pand %xmm7,%xmm4"); asm volatile("pxor %xmm4,%xmm2"); asm volatile("movdqa %0,%%xmm5" : : "m" (raid_16_const.x8l[0])); asm volatile("movdqa %0,%%xmm6" : : "m" (raid_16_const.x8h[0])); asm volatile("movdqa %xmm3,%xmm4"); asm volatile("psraw $4,%xmm3"); asm volatile("pand %0,%%xmm4" : : "m" (raid_16_const.low_nibble[0])); asm volatile("pand %0,%%xmm3" : : "m" (raid_16_const.low_nibble[0])); asm volatile("pshufb %xmm3,%xmm6"); asm volatile("movdqa %xmm5,%xmm3"); asm volatile("pshufb %xmm4,%xmm3"); asm volatile("pxor %xmm6,%xmm3"); asm volatile("movdqa %0,%%xmm4" : : "m" (vbuf[d][o])); asm volatile("pxor %xmm4,%xmm0"); asm volatile("pxor %xmm4,%xmm1"); asm volatile("pxor %xmm4,%xmm2"); asm volatile("pxor %xmm4,%xmm3"); } asm volatile("movntdq %%xmm0,%0" : "=m" (p[o])); asm volatile("movntdq %%xmm1,%0" : "=m" (q[o])); asm volatile("movntdq %%xmm2,%0" : "=m" (r[o])); asm volatile("movntdq %%xmm3,%0" : "=m" (s[o])); } asm volatile("sfence" : : : "memory"); } #endif #if defined(__x86_64__) /* * RAIDQP SSE2 implementation * Note that it uses 16 registers, meaning that x64 is required. */ void raidQP_sse2ext(unsigned char** vbuf, unsigned data, unsigned size) { unsigned char* p; unsigned char* q; unsigned char* r; unsigned char* s; int d, l; unsigned o; l = data - 1; p = vbuf[data]; q = vbuf[data+1]; r = vbuf[data+2]; s = vbuf[data+3]; asm volatile("movdqa %0,%%xmm7" : : "m" (raid_16_const.poly[0])); for(o=0;o=0;--d) { asm volatile("pxor %xmm4,%xmm4"); asm volatile("pxor %xmm5,%xmm5"); asm volatile("pxor %xmm12,%xmm12"); asm volatile("pxor %xmm13,%xmm13"); asm volatile("pcmpgtb %xmm1,%xmm4"); asm volatile("pcmpgtb %xmm3,%xmm5"); asm volatile("pcmpgtb %xmm9,%xmm12"); asm volatile("pcmpgtb %xmm11,%xmm13"); asm volatile("paddb %xmm1,%xmm1"); asm volatile("paddb %xmm3,%xmm3"); asm volatile("paddb %xmm9,%xmm9"); asm volatile("paddb %xmm11,%xmm11"); asm volatile("pand %xmm7,%xmm4"); asm volatile("pand %xmm7,%xmm5"); asm volatile("pand %xmm7,%xmm12"); asm volatile("pand %xmm7,%xmm13"); asm volatile("pxor %xmm4,%xmm1"); asm volatile("pxor %xmm5,%xmm3"); asm volatile("pxor %xmm12,%xmm9"); asm volatile("pxor %xmm13,%xmm11"); asm volatile("pxor %xmm4,%xmm4"); asm volatile("pxor %xmm5,%xmm5"); asm volatile("pxor %xmm12,%xmm12"); asm volatile("pxor %xmm13,%xmm13"); asm volatile("pcmpgtb %xmm2,%xmm4"); asm volatile("pcmpgtb %xmm3,%xmm5"); asm volatile("pcmpgtb %xmm10,%xmm12"); asm volatile("pcmpgtb %xmm11,%xmm13"); asm volatile("paddb %xmm2,%xmm2"); asm volatile("paddb %xmm3,%xmm3"); asm volatile("paddb %xmm10,%xmm10"); asm volatile("paddb %xmm11,%xmm11"); asm volatile("pand %xmm7,%xmm4"); asm volatile("pand %xmm7,%xmm5"); asm volatile("pand %xmm7,%xmm12"); asm volatile("pand %xmm7,%xmm13"); asm volatile("pxor %xmm4,%xmm2"); asm volatile("pxor %xmm5,%xmm3"); asm volatile("pxor %xmm12,%xmm10"); asm volatile("pxor %xmm13,%xmm11"); asm volatile("pxor %xmm4,%xmm4"); asm volatile("pxor %xmm5,%xmm5"); asm volatile("pxor %xmm12,%xmm12"); asm volatile("pxor %xmm13,%xmm13"); asm volatile("pcmpgtb %xmm2,%xmm4"); asm volatile("pcmpgtb %xmm3,%xmm5"); asm volatile("pcmpgtb %xmm10,%xmm12"); asm volatile("pcmpgtb %xmm11,%xmm13"); asm volatile("paddb %xmm2,%xmm2"); asm volatile("paddb %xmm3,%xmm3"); asm volatile("paddb %xmm10,%xmm10"); asm volatile("paddb %xmm11,%xmm11"); asm volatile("pand %xmm7,%xmm4"); asm volatile("pand %xmm7,%xmm5"); asm volatile("pand %xmm7,%xmm12"); asm volatile("pand %xmm7,%xmm13"); asm volatile("pxor %xmm4,%xmm2"); asm volatile("pxor %xmm5,%xmm3"); asm volatile("pxor %xmm12,%xmm10"); asm volatile("pxor %xmm13,%xmm11"); asm volatile("movdqa %0,%%xmm4" : : "m" (vbuf[d][o])); asm volatile("movdqa %0,%%xmm12" : : "m" (vbuf[d][o+16])); asm volatile("pxor %xmm4,%xmm0"); asm volatile("pxor %xmm4,%xmm1"); asm volatile("pxor %xmm4,%xmm2"); asm volatile("pxor %xmm4,%xmm3"); asm volatile("pxor %xmm12,%xmm8"); asm volatile("pxor %xmm12,%xmm9"); asm volatile("pxor %xmm12,%xmm10"); asm volatile("pxor %xmm12,%xmm11"); } asm volatile("movntdq %%xmm0,%0" : "=m" (p[o])); asm volatile("movntdq %%xmm8,%0" : "=m" (p[o+16])); asm volatile("movntdq %%xmm1,%0" : "=m" (q[o])); asm volatile("movntdq %%xmm9,%0" : "=m" (q[o+16])); asm volatile("movntdq %%xmm2,%0" : "=m" (r[o])); asm volatile("movntdq %%xmm10,%0" : "=m" (r[o+16])); asm volatile("movntdq %%xmm3,%0" : "=m" (s[o])); asm volatile("movntdq %%xmm11,%0" : "=m" (s[o+16])); } asm volatile("sfence" : : : "memory"); } #endif #if defined(__x86_64__) /* * RAIDQP SSSE3 implementation * Note that it uses 16 registers, meaning that x64 is required. */ void raidQP_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size) { unsigned char* p; unsigned char* q; unsigned char* r; unsigned char* s; int d, l; unsigned o; l = data - 1; p = vbuf[data]; q = vbuf[data+1]; r = vbuf[data+2]; s = vbuf[data+3]; asm volatile("movdqa %0,%%xmm7" : : "m" (raid_16_const.poly[0])); asm volatile("movdqa %0,%%xmm15" : : "m" (raid_16_const.low_nibble[0])); for(o=0;o=0;--d) { asm volatile("pxor %xmm4,%xmm4"); asm volatile("pxor %xmm12,%xmm12"); asm volatile("pcmpgtb %xmm1,%xmm4"); asm volatile("pcmpgtb %xmm9,%xmm12"); asm volatile("paddb %xmm1,%xmm1"); asm volatile("paddb %xmm9,%xmm9"); asm volatile("pand %xmm7,%xmm4"); asm volatile("pand %xmm7,%xmm12"); asm volatile("pxor %xmm4,%xmm1"); asm volatile("pxor %xmm12,%xmm9"); asm volatile("movdqa %0,%%xmm5" : : "m" (raid_16_const.x4l[0])); asm volatile("movdqa %0,%%xmm6" : : "m" (raid_16_const.x4h[0])); asm volatile("movdqa %xmm5,%xmm13"); asm volatile("movdqa %xmm6,%xmm14"); asm volatile("movdqa %xmm2,%xmm4"); asm volatile("movdqa %xmm10,%xmm12"); asm volatile("psraw $4,%xmm2"); asm volatile("psraw $4,%xmm10"); asm volatile("pand %xmm15,%xmm4"); asm volatile("pand %xmm15,%xmm12"); asm volatile("pand %xmm15,%xmm2"); asm volatile("pand %xmm15,%xmm10"); asm volatile("pshufb %xmm2,%xmm6"); asm volatile("pshufb %xmm10,%xmm14"); asm volatile("movdqa %xmm5,%xmm2"); asm volatile("movdqa %xmm13,%xmm10"); asm volatile("pshufb %xmm4,%xmm2"); asm volatile("pshufb %xmm12,%xmm10"); asm volatile("pxor %xmm6,%xmm2"); asm volatile("pxor %xmm14,%xmm10"); asm volatile("movdqa %0,%%xmm5" : : "m" (raid_16_const.x8l[0])); asm volatile("movdqa %0,%%xmm6" : : "m" (raid_16_const.x8h[0])); asm volatile("movdqa %xmm5,%xmm13"); asm volatile("movdqa %xmm6,%xmm14"); asm volatile("movdqa %xmm3,%xmm4"); asm volatile("movdqa %xmm11,%xmm12"); asm volatile("psraw $4,%xmm3"); asm volatile("psraw $4,%xmm11"); asm volatile("pand %xmm15,%xmm4"); asm volatile("pand %xmm15,%xmm12"); asm volatile("pand %xmm15,%xmm3"); asm volatile("pand %xmm15,%xmm11"); asm volatile("pshufb %xmm3,%xmm6"); asm volatile("pshufb %xmm11,%xmm14"); asm volatile("movdqa %xmm5,%xmm3"); asm volatile("movdqa %xmm13,%xmm11"); asm volatile("pshufb %xmm4,%xmm3"); asm volatile("pshufb %xmm12,%xmm11"); asm volatile("pxor %xmm6,%xmm3"); asm volatile("pxor %xmm14,%xmm11"); asm volatile("movdqa %0,%%xmm4" : : "m" (vbuf[d][o])); asm volatile("movdqa %0,%%xmm12" : : "m" (vbuf[d][o+16])); asm volatile("pxor %xmm4,%xmm0"); asm volatile("pxor %xmm4,%xmm1"); asm volatile("pxor %xmm4,%xmm2"); asm volatile("pxor %xmm4,%xmm3"); asm volatile("pxor %xmm12,%xmm8"); asm volatile("pxor %xmm12,%xmm9"); asm volatile("pxor %xmm12,%xmm10"); asm volatile("pxor %xmm12,%xmm11"); } asm volatile("movntdq %%xmm0,%0" : "=m" (p[o])); asm volatile("movntdq %%xmm8,%0" : "=m" (p[o+16])); asm volatile("movntdq %%xmm1,%0" : "=m" (q[o])); asm volatile("movntdq %%xmm9,%0" : "=m" (q[o+16])); asm volatile("movntdq %%xmm2,%0" : "=m" (r[o])); asm volatile("movntdq %%xmm10,%0" : "=m" (r[o+16])); asm volatile("movntdq %%xmm3,%0" : "=m" (s[o])); asm volatile("movntdq %%xmm11,%0" : "=m" (s[o+16])); } asm volatile("sfence" : : : "memory"); } /* * RAIDQP AVX implementation * Note that it uses 16 registers, meaning that x64 is required. */ void raidQP_avxext(unsigned char** vbuf, unsigned data, unsigned size) { unsigned char* p; unsigned char* q; unsigned char* r; unsigned char* s; int d, l; unsigned o; l = data - 1; p = vbuf[data]; q = vbuf[data+1]; r = vbuf[data+2]; s = vbuf[data+3]; asm volatile("movdqa %0,%%xmm5" : : "m" (raid_16_const.x8l[0])); asm volatile("movdqa %0,%%xmm6" : : "m" (raid_16_const.x8h[0])); asm volatile("movdqa %0,%%xmm7" : : "m" (raid_16_const.poly[0])); asm volatile("movdqa %0,%%xmm13" : : "m" (raid_16_const.x4l[0])); asm volatile("movdqa %0,%%xmm14" : : "m" (raid_16_const.x4h[0])); asm volatile("movdqa %0,%%xmm15" : : "m" (raid_16_const.low_nibble[0])); for(o=0;o=0;--d) { asm volatile("pxor %xmm4,%xmm4"); asm volatile("pxor %xmm12,%xmm12"); asm volatile("pcmpgtb %xmm1,%xmm4"); asm volatile("pcmpgtb %xmm9,%xmm12"); asm volatile("paddb %xmm1,%xmm1"); asm volatile("paddb %xmm9,%xmm9"); asm volatile("pand %xmm7,%xmm4"); asm volatile("pand %xmm7,%xmm12"); asm volatile("pxor %xmm4,%xmm1"); asm volatile("pxor %xmm12,%xmm9"); asm volatile("movdqa %xmm2,%xmm4"); asm volatile("movdqa %xmm10,%xmm12"); asm volatile("psraw $4,%xmm2"); asm volatile("psraw $4,%xmm10"); asm volatile("pand %xmm15,%xmm4"); asm volatile("pand %xmm15,%xmm12"); asm volatile("pand %xmm15,%xmm2"); asm volatile("pand %xmm15,%xmm10"); asm volatile("vpshufb %xmm2,%xmm14,%xmm2"); asm volatile("vpshufb %xmm10,%xmm14,%xmm10"); asm volatile("vpshufb %xmm4,%xmm13,%xmm4"); asm volatile("vpshufb %xmm12,%xmm13,%xmm12"); asm volatile("pxor %xmm4,%xmm2"); asm volatile("pxor %xmm12,%xmm10"); asm volatile("movdqa %xmm3,%xmm4"); asm volatile("movdqa %xmm11,%xmm12"); asm volatile("psraw $4,%xmm3"); asm volatile("psraw $4,%xmm11"); asm volatile("pand %xmm15,%xmm4"); asm volatile("pand %xmm15,%xmm12"); asm volatile("pand %xmm15,%xmm3"); asm volatile("pand %xmm15,%xmm11"); asm volatile("vpshufb %xmm3,%xmm6,%xmm3"); asm volatile("vpshufb %xmm11,%xmm6,%xmm11"); asm volatile("vpshufb %xmm4,%xmm5,%xmm4"); asm volatile("vpshufb %xmm12,%xmm5,%xmm12"); asm volatile("pxor %xmm4,%xmm3"); asm volatile("pxor %xmm12,%xmm11"); asm volatile("movdqa %0,%%xmm4" : : "m" (vbuf[d][o])); asm volatile("movdqa %0,%%xmm12" : : "m" (vbuf[d][o+16])); asm volatile("pxor %xmm4,%xmm0"); asm volatile("pxor %xmm4,%xmm1"); asm volatile("pxor %xmm4,%xmm2"); asm volatile("pxor %xmm4,%xmm3"); asm volatile("pxor %xmm12,%xmm8"); asm volatile("pxor %xmm12,%xmm9"); asm volatile("pxor %xmm12,%xmm10"); asm volatile("pxor %xmm12,%xmm11"); } asm volatile("movntdq %%xmm0,%0" : "=m" (p[o])); asm volatile("movntdq %%xmm8,%0" : "=m" (p[o+16])); asm volatile("movntdq %%xmm1,%0" : "=m" (q[o])); asm volatile("movntdq %%xmm9,%0" : "=m" (q[o+16])); asm volatile("movntdq %%xmm2,%0" : "=m" (r[o])); asm volatile("movntdq %%xmm10,%0" : "=m" (r[o+16])); asm volatile("movntdq %%xmm3,%0" : "=m" (s[o])); asm volatile("movntdq %%xmm11,%0" : "=m" (s[o+16])); } asm volatile("sfence" : : : "memory"); } #endif /****************************************************************************/ /* parity generation */ /* internal forwarder */ static void (*raid5_gen)(unsigned char** vbuf, unsigned data, unsigned size); static void (*raid6_gen)(unsigned char** vbuf, unsigned data, unsigned size); static void (*raidTP_gen)(unsigned char** vbuf, unsigned data, unsigned size); static void (*raidQP_gen)(unsigned char** vbuf, unsigned data, unsigned size); void raid_gen(unsigned level, unsigned char** vbuf, unsigned data, unsigned size) { switch (level) { case 1 : raid5_gen(vbuf, data, size); break; case 2 : raid6_gen(vbuf, data, size); break; case 3 : raidTP_gen(vbuf, data, size); break; case 4 : raidQP_gen(vbuf, data, size); break; } } /****************************************************************************/ /* recovering */ /** * The data recovering is based on the paper "The mathematics of RAID-6" [1], * that covers the RAID5 and RAID6 cases. * * In such cases we compute the parities in the Galois Field GF(2^8) with * the primitive polynomial x^8 + x^4 + x^3 + x^2 + 1 (285 decimal), * using the following equations and starting from a set of n disk Di * with 0<=i 254) { fprintf(stderr, "GF invalid exponent\n"); exit(EXIT_FAILURE); } return gfexp2[v]; } /** * GF 4^a. */ static inline unsigned char pow4(int v) { if (v < 0 || v > 254) { fprintf(stderr, "GF invalid exponent\n"); exit(EXIT_FAILURE); } return gfexp4[v]; } /** * GF 8^a. */ static inline unsigned char pow8(int v) { if (v < 0 || v > 254) { fprintf(stderr, "GF invalid exponent\n"); exit(EXIT_FAILURE); } return gfexp8[v]; } /** * GF 2^b^a. */ static inline unsigned char pown(int b, int e) { switch (b) { case 0 : return 1; case 1 : return pow2(e); case 2 : return pow4(e); case 3 : return pow8(e); } fprintf(stderr, "GF invalid base\n"); exit(EXIT_FAILURE); } /** * Gets the multiplication table for a specified value. */ static inline const unsigned char* table(unsigned char v) { return gfmul[v]; } /** * Computes the parity without the missing data blocks * and store it in the buffers of such data blocks. */ static void raid_delta_1data(int x, int i, unsigned char** vbuf, unsigned data, unsigned char* zero, unsigned size) { unsigned char* p; unsigned char* pa; /* parity buffer */ p = vbuf[data+i]; /* missing data blcks */ pa = vbuf[x]; /* set at zero the missing data blocks */ vbuf[x] = zero; /* compute only for the level we really need */ vbuf[data+i] = pa; /* compute the parity */ raid_gen(i + 1, vbuf, data, size); /* restore as before */ vbuf[x] = pa; vbuf[data+i] = p; } /** * Computes the parity without the missing data blocks * and store it in the buffers of such data blocks. */ static void raid_delta_2data(int x, int y, int i, int j, unsigned char** vbuf, unsigned data, unsigned char* zero, unsigned size) { unsigned char* p; unsigned char* q; unsigned char* pa; unsigned char* qa; /* parity buffer */ p = vbuf[data+i]; q = vbuf[data+j]; /* missing data blcks */ pa = vbuf[x]; qa = vbuf[y]; /* set at zero the missing data blocks */ vbuf[x] = zero; vbuf[y] = zero; /* compute the parity over the missing data blocks */ vbuf[data+i] = pa; vbuf[data+j] = qa; /* compute only for the level we really need */ raid_gen(j + 1, vbuf, data, size); /* restore as before */ vbuf[x] = pa; vbuf[y] = qa; vbuf[data+i] = p; vbuf[data+j] = q; } /** * Computes the parity without the missing data blocks * and store it in the buffers of such data blocks. */ static void raid_delta_3data(int x, int y, int z, int i, int j, int k, unsigned char** vbuf, unsigned data, unsigned char* zero, unsigned size) { unsigned char* p; unsigned char* q; unsigned char* r; unsigned char* pa; unsigned char* qa; unsigned char* ra; /* parity buffer */ p = vbuf[data+i]; q = vbuf[data+j]; r = vbuf[data+k]; /* missing data blcks */ pa = vbuf[x]; qa = vbuf[y]; ra = vbuf[z]; /* set at zero the missing data blocks */ vbuf[x] = zero; vbuf[y] = zero; vbuf[z] = zero; /* compute the parity over the missing data blocks */ vbuf[data+i] = pa; vbuf[data+j] = qa; vbuf[data+k] = ra; /* compute only for the level we really need */ raid_gen(k + 1, vbuf, data, size); /* restore as before */ vbuf[x] = pa; vbuf[y] = qa; vbuf[z] = ra; vbuf[data+i] = p; vbuf[data+j] = q; vbuf[data+k] = r; } /** * Computes the parity without the missing data blocks * and store it in the buffers of such data blocks. */ static void raid_delta_4data(int x, int y, int z, int v, int i, int j, int k, int l, unsigned char** vbuf, unsigned data, unsigned char* zero, unsigned size) { unsigned char* p; unsigned char* q; unsigned char* r; unsigned char* s; unsigned char* pa; unsigned char* qa; unsigned char* ra; unsigned char* sa; /* parity buffer */ p = vbuf[data+i]; q = vbuf[data+j]; r = vbuf[data+k]; s = vbuf[data+l]; /* missing data blcks */ pa = vbuf[x]; qa = vbuf[y]; ra = vbuf[z]; sa = vbuf[v]; /* set at zero the missing data blocks */ vbuf[x] = zero; vbuf[y] = zero; vbuf[z] = zero; vbuf[v] = zero; /* compute the parity over the missing data blocks */ vbuf[data+i] = pa; vbuf[data+j] = qa; vbuf[data+k] = ra; vbuf[data+l] = sa; /* compute only for the level we really need */ raid_gen(l + 1, vbuf, data, size); /* restore as before */ vbuf[x] = pa; vbuf[y] = qa; vbuf[z] = ra; vbuf[v] = sa; vbuf[data+i] = p; vbuf[data+j] = q; vbuf[data+k] = r; vbuf[data+l] = s; } /** * Recover failure of one data block for RAID5. * * Starting from the equation: * * Pd = Dx * * and solving we get: * * Dx = Pd (this one is easy :D) */ static void raid5_recov_data(int x, unsigned char** vbuf, unsigned data, unsigned size) { unsigned char* p; unsigned char* pa; /* for RAID5 we can directly compute the mssing block */ /* and we don't need to use the zero buffer */ p = vbuf[data]; pa = vbuf[x]; /* use the parity as missing data block */ vbuf[x] = p; /* compute the parity over the missing data block */ vbuf[data] = pa; /* compute */ raid5_gen(vbuf, data, size); /* restore as before */ vbuf[x] = pa; vbuf[data] = p; } /** * Recover failure of two data blocks for RAID6. * * Starting from the equations: * * Pd = Dx + Dy * Qd = 2^x * Dx + 2^y * Dy * * and solving we get: * * 1 2^(-x) * Dy = ----------- * Pd + ----------- * Qd * 2^(y-x) + 1 2^(y-x) + 1 * * Dx = Dy + Pd * * with conditions: * * 2^x != 0 * 2^(y-x) + 1 != 0 * * That are always satisfied for any 0<=xname != 0) { if (i->p == func) return i->name; ++i; } return "unknown"; } const char* raid5_tag(void) { return raid_tag(raid5_gen); } const char* raid6_tag(void) { return raid_tag(raid6_gen); } const char* raidTP_tag(void) { return raid_tag(raidTP_gen); } const char* raidQP_tag(void) { return raid_tag(raidQP_gen); }