4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or https://opensource.org/licenses/CDDL-1.0.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (C) 2016 Gvozden Nešković. All rights reserved.
28 #include <sys/types.h>
29 #include <sys/debug.h>
30 #include <sys/kstat.h>
32 #include <sys/vdev_impl.h>
43 #define PARITY_PQ (2U)
44 #define PARITY_PQR (3U)
51 * Parity generation methods indexes
53 enum raidz_math_gen_op
{
60 * Data reconstruction methods indexes
73 extern const char *const raidz_gen_name
[RAIDZ_GEN_NUM
];
74 extern const char *const raidz_rec_name
[RAIDZ_REC_NUM
];
77 * Methods used to define raidz implementation
79 * @raidz_gen_f Parity generation function
80 * @par1 pointer to raidz_map
81 * @raidz_rec_f Data reconstruction function
82 * @par1 pointer to raidz_map
83 * @par2 array of reconstruction targets
84 * @will_work_f Function returns TRUE if impl. is supported on the system
85 * @init_impl_f Function is called once on init
86 * @fini_impl_f Function is called once on fini
88 typedef void (*raidz_gen_f
)(void *);
89 typedef int (*raidz_rec_f
)(void *, const int *);
90 typedef boolean_t (*will_work_f
)(void);
91 typedef void (*init_impl_f
)(void);
92 typedef void (*fini_impl_f
)(void);
94 #define RAIDZ_IMPL_NAME_MAX (20)
96 typedef struct raidz_impl_ops
{
99 raidz_gen_f gen
[RAIDZ_GEN_NUM
]; /* Parity generate functions */
100 raidz_rec_f rec
[RAIDZ_REC_NUM
]; /* Data reconstruction functions */
101 will_work_f is_supported
; /* Support check function */
102 char name
[RAIDZ_IMPL_NAME_MAX
]; /* Name of the implementation */
105 typedef struct raidz_col
{
106 uint64_t rc_devidx
; /* child device index for I/O */
107 uint64_t rc_offset
; /* device offset */
108 uint64_t rc_size
; /* I/O size */
109 abd_t rc_abdstruct
; /* rc_abd probably points here */
110 abd_t
*rc_abd
; /* I/O data */
111 abd_t
*rc_orig_data
; /* pre-reconstruction */
112 int rc_error
; /* I/O error for this device */
113 uint8_t rc_tried
; /* Did we attempt this I/O column? */
114 uint8_t rc_skipped
; /* Did we skip this I/O column? */
115 uint8_t rc_need_orig_restore
; /* need to restore from orig_data? */
116 uint8_t rc_force_repair
; /* Write good data to this column */
117 uint8_t rc_allow_repair
; /* Allow repair I/O to this column */
120 typedef struct raidz_row
{
121 uint64_t rr_cols
; /* Regular column count */
122 uint64_t rr_scols
; /* Count including skipped columns */
123 uint64_t rr_bigcols
; /* Remainder data column count */
124 uint64_t rr_missingdata
; /* Count of missing data devices */
125 uint64_t rr_missingparity
; /* Count of missing parity devices */
126 uint64_t rr_firstdatacol
; /* First data column/parity count */
127 abd_t
*rr_abd_empty
; /* dRAID empty sector buffer */
128 int rr_nempty
; /* empty sectors included in parity */
130 uint64_t rr_offset
; /* Logical offset for *_io_verify() */
131 uint64_t rr_size
; /* Physical size for *_io_verify() */
133 raidz_col_t rr_col
[0]; /* Flexible array of I/O columns */
136 typedef struct raidz_map
{
137 boolean_t rm_ecksuminjected
; /* checksum error was injected */
138 int rm_nrows
; /* Regular row count */
139 int rm_nskip
; /* RAIDZ sectors skipped for padding */
140 int rm_skipstart
; /* Column index of padding start */
141 const raidz_impl_ops_t
*rm_ops
; /* RAIDZ math operations */
142 raidz_row_t
*rm_row
[0]; /* flexible array of rows */
146 #define RAIDZ_ORIGINAL_IMPL (INT_MAX)
148 extern const raidz_impl_ops_t vdev_raidz_scalar_impl
;
149 extern boolean_t
raidz_will_scalar_work(void);
151 #if defined(__x86_64) && defined(HAVE_SSE2) /* only x86_64 for now */
152 extern const raidz_impl_ops_t vdev_raidz_sse2_impl
;
154 #if defined(__x86_64) && defined(HAVE_SSSE3) /* only x86_64 for now */
155 extern const raidz_impl_ops_t vdev_raidz_ssse3_impl
;
157 #if defined(__x86_64) && defined(HAVE_AVX2) /* only x86_64 for now */
158 extern const raidz_impl_ops_t vdev_raidz_avx2_impl
;
160 #if defined(__x86_64) && defined(HAVE_AVX512F) /* only x86_64 for now */
161 extern const raidz_impl_ops_t vdev_raidz_avx512f_impl
;
163 #if defined(__x86_64) && defined(HAVE_AVX512BW) /* only x86_64 for now */
164 extern const raidz_impl_ops_t vdev_raidz_avx512bw_impl
;
166 #if defined(__aarch64__)
167 extern const raidz_impl_ops_t vdev_raidz_aarch64_neon_impl
;
168 extern const raidz_impl_ops_t vdev_raidz_aarch64_neonx2_impl
;
170 #if defined(__powerpc__)
171 extern const raidz_impl_ops_t vdev_raidz_powerpc_altivec_impl
;
175 * Commonly used raidz_map helpers
177 * raidz_parity Returns parity of the RAIDZ block
178 * raidz_ncols Returns number of columns the block spans
179 * Note, all rows have the same number of columns.
180 * raidz_nbigcols Returns number of big columns
181 * raidz_col_p Returns pointer to a column
182 * raidz_col_size Returns size of a column
183 * raidz_big_size Returns size of big columns
184 * raidz_short_size Returns size of short columns
186 #define raidz_parity(rm) ((rm)->rm_row[0]->rr_firstdatacol)
187 #define raidz_ncols(rm) ((rm)->rm_row[0]->rr_cols)
188 #define raidz_nbigcols(rm) ((rm)->rm_bigcols)
189 #define raidz_col_p(rm, c) ((rm)->rm_col + (c))
190 #define raidz_col_size(rm, c) ((rm)->rm_col[c].rc_size)
191 #define raidz_big_size(rm) (raidz_col_size(rm, CODE_P))
192 #define raidz_short_size(rm) (raidz_col_size(rm, raidz_ncols(rm)-1))
195 * Macro defines an RAIDZ parity generation method
197 * @code parity the function produce
198 * @impl name of the implementation
200 #define _RAIDZ_GEN_WRAP(code, impl) \
202 impl ## _gen_ ## code(void *rrp) \
204 raidz_row_t *rr = (raidz_row_t *)rrp; \
205 raidz_generate_## code ## _impl(rr); \
209 * Macro defines an RAIDZ data reconstruction method
211 * @code parity the function produce
212 * @impl name of the implementation
214 #define _RAIDZ_REC_WRAP(code, impl) \
216 impl ## _rec_ ## code(void *rrp, const int *tgtidx) \
218 raidz_row_t *rr = (raidz_row_t *)rrp; \
219 return (raidz_reconstruct_## code ## _impl(rr, tgtidx)); \
223 * Define all gen methods for an implementation
225 * @impl name of the implementation
227 #define DEFINE_GEN_METHODS(impl) \
228 _RAIDZ_GEN_WRAP(p, impl); \
229 _RAIDZ_GEN_WRAP(pq, impl); \
230 _RAIDZ_GEN_WRAP(pqr, impl)
233 * Define all rec functions for an implementation
235 * @impl name of the implementation
237 #define DEFINE_REC_METHODS(impl) \
238 _RAIDZ_REC_WRAP(p, impl); \
239 _RAIDZ_REC_WRAP(q, impl); \
240 _RAIDZ_REC_WRAP(r, impl); \
241 _RAIDZ_REC_WRAP(pq, impl); \
242 _RAIDZ_REC_WRAP(pr, impl); \
243 _RAIDZ_REC_WRAP(qr, impl); \
244 _RAIDZ_REC_WRAP(pqr, impl)
246 #define RAIDZ_GEN_METHODS(impl) \
248 [RAIDZ_GEN_P] = & impl ## _gen_p, \
249 [RAIDZ_GEN_PQ] = & impl ## _gen_pq, \
250 [RAIDZ_GEN_PQR] = & impl ## _gen_pqr \
253 #define RAIDZ_REC_METHODS(impl) \
255 [RAIDZ_REC_P] = & impl ## _rec_p, \
256 [RAIDZ_REC_Q] = & impl ## _rec_q, \
257 [RAIDZ_REC_R] = & impl ## _rec_r, \
258 [RAIDZ_REC_PQ] = & impl ## _rec_pq, \
259 [RAIDZ_REC_PR] = & impl ## _rec_pr, \
260 [RAIDZ_REC_QR] = & impl ## _rec_qr, \
261 [RAIDZ_REC_PQR] = & impl ## _rec_pqr \
265 typedef struct raidz_impl_kstat
{
266 uint64_t gen
[RAIDZ_GEN_NUM
]; /* gen method speed B/s */
267 uint64_t rec
[RAIDZ_REC_NUM
]; /* rec method speed B/s */
268 } raidz_impl_kstat_t
;
271 * Enumerate various multiplication constants
272 * used in reconstruction methods
274 typedef enum raidz_mul_info
{
290 /* Reconstruct PQR */
302 * Powers of 2 in the Galois field.
304 extern const uint8_t vdev_raidz_pow2
[256] __attribute__((aligned(256)));
305 /* Logs of 2 in the Galois field defined above. */
306 extern const uint8_t vdev_raidz_log2
[256] __attribute__((aligned(256)));
309 * Multiply a given number by 2 raised to the given power.
311 static inline uint8_t
312 vdev_raidz_exp2(const uint8_t a
, const unsigned exp
)
317 return (vdev_raidz_pow2
[(exp
+ (unsigned)vdev_raidz_log2
[a
]) % 255]);
321 * Galois Field operations.
323 * gf_exp2 - computes 2 raised to the given power
324 * gf_exp4 - computes 4 raised to the given power
325 * gf_mul - multiplication
327 * gf_inv - multiplicative inverse
329 typedef unsigned gf_t
;
330 typedef unsigned gf_log_t
;
333 gf_mul(const gf_t a
, const gf_t b
)
337 if (a
== 0 || b
== 0)
340 logsum
= (gf_log_t
)vdev_raidz_log2
[a
] + (gf_log_t
)vdev_raidz_log2
[b
];
342 return ((gf_t
)vdev_raidz_pow2
[logsum
% 255]);
346 gf_div(const gf_t a
, const gf_t b
)
354 logsum
= (gf_log_t
)255 + (gf_log_t
)vdev_raidz_log2
[a
] -
355 (gf_log_t
)vdev_raidz_log2
[b
];
357 return ((gf_t
)vdev_raidz_pow2
[logsum
% 255]);
367 logsum
= (gf_log_t
)255 - (gf_log_t
)vdev_raidz_log2
[a
];
369 return ((gf_t
)vdev_raidz_pow2
[logsum
]);
373 gf_exp2(gf_log_t exp
)
375 return (vdev_raidz_pow2
[exp
% 255]);
379 gf_exp4(gf_log_t exp
)
381 ASSERT3U(exp
, <=, 255);
382 return ((gf_t
)vdev_raidz_pow2
[(2 * exp
) % 255]);
389 #endif /* _VDEV_RAIDZ_H */